aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/lanalyzer.c
blob: 44013670d4c349d4eaeb7d4412373274a64f3c07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/* lanalyzer.c
 *
 * $Id: lanalyzer.c,v 1.28 2001/04/16 22:06:34 guy Exp $
 *
 * Wiretap Library
 * Copyright (c) 1998 by Gilbert Ramirez <gram@xiexie.org>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <errno.h>
#include "wtap-int.h"
#include "file_wrappers.h"
#include "buffer.h"
#include "lanalyzer.h"

/* The LANalyzer format is documented (at least in part) in Novell document
   TID022037, which can be found at, among other places:

	http://www.hackzone.ru/nsp/info/nw/lan/trace.txt
 */

/* Record types. */
#define REC_TRACE_HEADER	0x1001
#define REC_CYCLIC_TRACE_HEADER	0x1007
#define REC_TRACE_SUMMARY	0x1002
#define REC_TRACE_PACKET_DATA	0x1005

/* LANalyzer board types (which indicate the type of network on which
   the capture was done). */
#define BOARD_325		226	/* LANalyzer 325 (Ethernet) */
#define BOARD_325TR		227	/* LANalyzer 325TR (Token-ring) */

static gboolean lanalyzer_read(wtap *wth, int *err, int *data_offset);
static void lanalyzer_close(wtap *wth);

int lanalyzer_open(wtap *wth, int *err)
{
	int bytes_read;
	char LE_record_type[2];
	char LE_record_length[2];
	char summary[210];
	guint16 board_type, mxslc;
	guint16 record_type, record_length;
	guint8 cr_day, cr_month, cr_year;
	struct tm tm;

	errno = WTAP_ERR_CANT_READ;
	bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
	bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
	if (bytes_read != 4) {
		*err = file_error(wth->fh);
		if (*err != 0)
			return -1;
		return 0;
	}
	wth->data_offset += 4;
	record_type = pletohs(LE_record_type);
	record_length = pletohs(LE_record_length); /* make sure to do this for while() loop */

	if (record_type != REC_TRACE_HEADER && record_type != REC_CYCLIC_TRACE_HEADER) {  
		return 0;
	}

	/* If we made it this far, then the file is a LANAlyzer file.
	 * Let's get some info from it. Note that we get wth->snapshot_length
	 * from a record later in the file. */
	wth->file_type = WTAP_FILE_LANALYZER;
	wth->capture.lanalyzer = g_malloc(sizeof(lanalyzer_t));
	wth->subtype_read = lanalyzer_read;
	wth->subtype_seek_read = wtap_def_seek_read;
	wth->subtype_close = lanalyzer_close;
	wth->snapshot_length = 0;

	/* Read records until we find the start of packets */
	while (1) {
		file_seek(wth->fh, record_length, SEEK_CUR);
		wth->data_offset += record_length;
		errno = WTAP_ERR_CANT_READ;
		bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
		bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
		if (bytes_read != 4) {
			*err = file_error(wth->fh);
			if (*err != 0) {
				g_free(wth->capture.lanalyzer);
				return -1;
			}
			g_free(wth->capture.lanalyzer);
			return 0;
		}
		wth->data_offset += 4;

		record_type = pletohs(LE_record_type);
		record_length = pletohs(LE_record_length);

		/*g_message("Record 0x%04X Length %d", record_type, record_length);*/
		switch (record_type) {
			/* Trace Summary Record */
			case REC_TRACE_SUMMARY:
				errno = WTAP_ERR_CANT_READ;
				bytes_read = file_read(summary, 1, sizeof summary,
				    wth->fh);
				if (bytes_read != sizeof summary) {
					*err = file_error(wth->fh);
					if (*err != 0) {
						g_free(wth->capture.lanalyzer);
						return -1;
					}
					g_free(wth->capture.lanalyzer);
					return 0;
				}
				wth->data_offset += sizeof summary;

				/* Assume that the date of the creation of the trace file
				 * is the same date of the trace. Lanalyzer doesn't
				 * store the creation date/time of the trace, but only of
				 * the file. Unless you traced at 11:55 PM and saved at 00:05
				 * AM, the assumption that trace.date == file.date is true.
				 */
				cr_day = summary[0];
				cr_month = summary[1];
				cr_year = pletohs(&summary[2]);
				/*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
						cr_year, cr_year);*/

				/* Get capture start time. I learned how to do
				 * this from Guy's code in ngsniffer.c
				 */
				/* this strange year offset is not in the
				 * lanalyzer file format documentation, but it
				 * works. */
				tm.tm_year = cr_year - (1900 - 1792);
				tm.tm_mon = cr_month - 1;
				tm.tm_mday = cr_day;
				tm.tm_hour = 0;
				tm.tm_min = 0;
				tm.tm_sec = 0;
				tm.tm_isdst = -1;
				wth->capture.lanalyzer->start = mktime(&tm);
				/*g_message("Day %d Month %d Year %d", tm.tm_mday,
						tm.tm_mon, tm.tm_year);*/
				mxslc = pletohs(&summary[30]);
				wth->snapshot_length = mxslc;

				record_length = 0; /* to fake the next iteration of while() */
				board_type = pletohs(&summary[188]);
				switch (board_type) {
					case BOARD_325:
						wth->file_encap = WTAP_ENCAP_ETHERNET;
						break;
					case BOARD_325TR:
						wth->file_encap = WTAP_ENCAP_TOKEN_RING;
						break;
					default:
						g_message("lanalyzer: board type %u unknown",
						    board_type);
						g_free(wth->capture.lanalyzer);
						*err = WTAP_ERR_UNSUPPORTED;
						return -1;
				}
				break;

			/* Trace Packet Data Record */
			case REC_TRACE_PACKET_DATA:
				/* Go back header number ob ytes so that lanalyzer_read
				 * can read this header */
				file_seek(wth->fh, -bytes_read, SEEK_CUR);
				wth->data_offset -= bytes_read;
				return 1;

			default:
				; /* no action */
		}
	} 
}

#define DESCRIPTOR_LEN	32

/* Read the next packet */
static gboolean lanalyzer_read(wtap *wth, int *err, int *data_offset)
{
	int		packet_size = 0;
	int		bytes_read;
	char		LE_record_type[2];
	char		LE_record_length[2];
	guint16		record_type, record_length;
	gchar		descriptor[DESCRIPTOR_LEN];
	guint16		time_low, time_med, time_high, true_size;
	double		t;

	/* read the record type and length. */
	errno = WTAP_ERR_CANT_READ;
	bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
	if (bytes_read != 2) {
		*err = file_error(wth->fh);
		if (*err == 0 && bytes_read != 0) {
			*err = WTAP_ERR_SHORT_READ;
		}
		return FALSE;
	}
	wth->data_offset += 2;
	bytes_read = file_read(LE_record_length, 1, 2, wth->fh);
	if (bytes_read != 2) {
		*err = file_error(wth->fh);
		if (*err == 0)
			*err = WTAP_ERR_SHORT_READ;
		return FALSE;
	}
	wth->data_offset += 2;

	record_type = pletohs(LE_record_type);
	record_length = pletohs(LE_record_length);

	/* Only Trace Packet Data Records should occur now that we're in
	 * the middle of reading packets.  If any other record type exists
	 * after a Trace Packet Data Record, mark it as an error. */
	if (record_type != REC_TRACE_PACKET_DATA) {
		g_message("lanalyzer: record type %u seen after trace summary record",
		    record_type);
		*err = WTAP_ERR_BAD_RECORD;
		return FALSE;
	}
	else {
		packet_size = record_length - DESCRIPTOR_LEN;
	}

	/* Read the descriptor data */
	errno = WTAP_ERR_CANT_READ;
	bytes_read = file_read(descriptor, 1, DESCRIPTOR_LEN, wth->fh);
	if (bytes_read != DESCRIPTOR_LEN) {
		*err = file_error(wth->fh);
		if (*err == 0)
			*err = WTAP_ERR_SHORT_READ;
		return FALSE;
	}
	wth->data_offset += DESCRIPTOR_LEN;

	/* Read the packet data */
	buffer_assure_space(wth->frame_buffer, packet_size);
	*data_offset = wth->data_offset;
	errno = WTAP_ERR_CANT_READ;
	bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
		packet_size, wth->fh);

	if (bytes_read != packet_size) {
		*err = file_error(wth->fh);
		if (*err == 0)
			*err = WTAP_ERR_SHORT_READ;
		return FALSE;
	}
	wth->data_offset += packet_size;

	true_size = pletohs(&descriptor[4]);
	time_low = pletohs(&descriptor[8]);
	time_med = pletohs(&descriptor[10]);
	time_high = pletohs(&descriptor[12]);

	t = (double)time_low+(double)(time_med)*65536.0 +
		(double)time_high*4294967296.0;
	t = t/1000000.0 * 0.5; /* t = # of secs */
	t += wth->capture.lanalyzer->start;

	wth->phdr.ts.tv_sec = (long)t;
	wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
			*1.0e6);

	wth->phdr.len = true_size - 4;
	wth->phdr.caplen = packet_size;
	wth->phdr.pkt_encap = wth->file_encap;

	return TRUE;
}

static void
lanalyzer_close(wtap *wth)
{
	g_free(wth->capture.lanalyzer);
}