1 /* peekclassic.c
2  * Routines for opening files in what Savvius (formerly WildPackets) calls
3  * the classic file format in the description of their "PeekRdr Sample
4  * Application" (C++ source code to read their capture files, downloading
5  * of which requires a maintenance contract, so it's not free as in beer
6  * and probably not as in speech, either).
7  *
8  * As that description says, it's used by AiroPeek and AiroPeek NX prior
9  * to 2.0, EtherPeek prior to 6.0, and EtherPeek NX prior to 3.0.  It
10  * was probably also used by TokenPeek.
11  *
12  * This handles versions 5, 6, and 7 of that format (the format version
13  * number is what appears in the file, and is distinct from the application
14  * version number).
15  *
16  * Copyright (c) 2001, Daniel Thompson <d.thompson@gmx.net>
17  *
18  * Wiretap Library
19  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
20  *
21  * SPDX-License-Identifier: GPL-2.0-or-later
22  */
23 
24 #include "config.h"
25 #include <errno.h>
26 #include <string.h>
27 
28 #include <wsutil/epochs.h>
29 #include <wsutil/802_11-utils.h>
30 #include <wsutil/ws_assert.h>
31 
32 #include "wtap-int.h"
33 #include "file_wrappers.h"
34 #include "peekclassic.h"
35 
36 /* CREDITS
37  *
38  * This file decoder could not have been written without examining how
39  * tcptrace (http://www.tcptrace.org/) handles EtherPeek files.
40  */
41 
42 /* master header */
43 typedef struct peekclassic_master_header {
44 	guint8  version;
45 	guint8  status;
46 } peekclassic_master_header_t;
47 #define PEEKCLASSIC_MASTER_HDR_SIZE 2
48 
49 /* secondary header (V5,V6,V7) */
50 typedef struct peekclassic_v567_header {
51 	guint32 filelength;
52 	guint32 numPackets;
53 	guint32 timeDate;
54 	guint32 timeStart;
55 	guint32 timeStop;
56 	guint32 mediaType;  /* Media Type Ethernet=0 Token Ring = 1 */
57 	guint32 physMedium; /* Physical Medium native=0 802.1=1 */
58 	guint32 appVers;    /* App Version Number Maj.Min.Bug.Build */
59 	guint32 linkSpeed;  /* Link Speed Bits/sec */
60 	guint32 reserved[3];
61 } peekclassic_v567_header_t;
62 #define PEEKCLASSIC_V567_HDR_SIZE 48
63 
64 /* full header */
65 typedef struct peekclassic_header {
66 	peekclassic_master_header_t master;
67 	union {
68 		peekclassic_v567_header_t v567;
69 	} secondary;
70 } peekclassic_header_t;
71 
72 /*
73  * Packet header (V5, V6).
74  *
75  * NOTE: the time stamp, although it's a 32-bit number, is only aligned
76  * on a 16-bit boundary.  (Does this date back to 68K Macs?  The 68000
77  * only required 16-bit alignment of 32-bit quantities, as did the 68010,
78  * and the 68020/68030/68040 required no alignment.)
79  *
80  * As such, we cannot declare this as a C structure, as compilers on
81  * most platforms will put 2 bytes of padding before the time stamp to
82  * align it on a 32-bit boundary.
83  *
84  * So, instead, we #define numbers as the offsets of the fields.
85  */
86 #define PEEKCLASSIC_V56_LENGTH_OFFSET		0
87 #define PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET	2
88 #define PEEKCLASSIC_V56_FLAGS_OFFSET		4
89 #define PEEKCLASSIC_V56_STATUS_OFFSET		5
90 #define PEEKCLASSIC_V56_TIMESTAMP_OFFSET	6
91 #define PEEKCLASSIC_V56_DESTNUM_OFFSET		10
92 #define PEEKCLASSIC_V56_SRCNUM_OFFSET		12
93 #define PEEKCLASSIC_V56_PROTONUM_OFFSET		14
94 #define PEEKCLASSIC_V56_PROTOSTR_OFFSET		16
95 #define PEEKCLASSIC_V56_FILTERNUM_OFFSET	24
96 #define PEEKCLASSIC_V56_PKT_SIZE		26
97 
98 /* 64-bit time in micro seconds from the (Mac) epoch */
99 typedef struct peekclassic_utime {
100 	guint32 upper;
101 	guint32 lower;
102 } peekclassic_utime;
103 
104 /*
105  * Packet header (V7).
106  *
107  * This doesn't have the same alignment problem, but we do it with
108  * #defines anyway.
109  */
110 #define PEEKCLASSIC_V7_PROTONUM_OFFSET		0
111 #define PEEKCLASSIC_V7_LENGTH_OFFSET		2
112 #define PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET	4
113 #define PEEKCLASSIC_V7_FLAGS_OFFSET		6
114 #define PEEKCLASSIC_V7_STATUS_OFFSET		7
115 #define PEEKCLASSIC_V7_TIMESTAMP_OFFSET		8
116 #define PEEKCLASSIC_V7_PKT_SIZE			16
117 
118 /*
119  * Flag bits.
120  */
121 #define FLAGS_CONTROL_FRAME	0x01	/* Frame is a control frame */
122 #define FLAGS_HAS_CRC_ERROR	0x02	/* Frame has a CRC error */
123 #define FLAGS_HAS_FRAME_ERROR	0x04	/* Frame has a frame error */
124 #define FLAGS_ROUTE_INFO	0x08	/* Frame has token ring routing information */
125 #define FLAGS_FRAME_TOO_LONG	0x10	/* Frame too long */
126 #define FLAGS_FRAME_TOO_SHORT	0x20	/* Frame too short (runt) */
127 #define FLAGS_TRIGGER		0x40	/* Trigger packet (?) */
128 #define FLAGS_SNAP		0x80	/* SNAP packet (SNAP header?) */
129 
130 /*
131  * Status bits.
132  */
133 #define STATUS_SELECTED		0x01	/* Selected (in the *Peek GUI?) */
134 #define STATUS_TRUNCATED	0x02	/* Truncated (?) */
135 #define STATUS_APPLEPEEK	0x10	/* ApplePeek packet (?) */
136 #define STATUS_SLICED		0x20	/* Sliced (cut short by snaplen?) */
137 #define STATUS_HIDDEN		0x80	/* Hidden (in the *Peek GUI?) */
138 
139 typedef struct {
140 	time_t reference_time;
141 } peekclassic_t;
142 
143 static gboolean peekclassic_read_v7(wtap *wth, wtap_rec *rec, Buffer *buf,
144     int *err, gchar **err_info, gint64 *data_offset);
145 static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off,
146     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
147 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
148     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
149 static gboolean peekclassic_read_v56(wtap *wth, wtap_rec *rec, Buffer *buf,
150     int *err, gchar **err_info, gint64 *data_offset);
151 static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off,
152     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
153 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
154     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
155 
156 static int peekclassic_v56_file_type_subtype = -1;
157 static int peekclassic_v7_file_type_subtype = -1;
158 
159 void register_peekclassic(void);
160 
peekclassic_open(wtap * wth,int * err,gchar ** err_info)161 wtap_open_return_val peekclassic_open(wtap *wth, int *err, gchar **err_info)
162 {
163 	peekclassic_header_t ep_hdr;
164 	time_t reference_time;
165 	int file_encap;
166 	peekclassic_t *peekclassic;
167 
168 	/* Peek classic files do not start with a magic value large enough
169 	 * to be unique; hence we use the following algorithm to determine
170 	 * the type of an unknown file:
171 	 *  - populate the master header and reject file if there is no match
172 	 *  - populate the secondary header and check that the reserved space
173 	 *      is zero, and check some other fields; this isn't perfect,
174 	 *	and we may have to add more checks at some point.
175 	 */
176 	ws_assert(sizeof(ep_hdr.master) == PEEKCLASSIC_MASTER_HDR_SIZE);
177 	if (!wtap_read_bytes(wth->fh, &ep_hdr.master,
178 	    (int)sizeof(ep_hdr.master), err, err_info)) {
179 		if (*err != WTAP_ERR_SHORT_READ)
180 			return WTAP_OPEN_ERROR;
181 		return WTAP_OPEN_NOT_MINE;
182 	}
183 
184 	/*
185 	 * It appears that EtherHelp (a free application from WildPackets
186 	 * that did blind capture, saving to a file, so that you could
187 	 * give the resulting file to somebody with EtherPeek) saved
188 	 * captures in EtherPeek format except that it ORed the 0x80
189 	 * bit on in the version number.
190 	 *
191 	 * We therefore strip off the 0x80 bit in the version number.
192 	 * Perhaps there's some reason to care whether the capture
193 	 * came from EtherHelp; if we discover one, we should check
194 	 * that bit.
195 	 */
196 	ep_hdr.master.version &= ~0x80;
197 
198 	/* switch on the file version */
199 	switch (ep_hdr.master.version) {
200 
201 	case 5:
202 	case 6:
203 	case 7:
204 		/* get the secondary header */
205 		ws_assert(sizeof(ep_hdr.secondary.v567) ==
206 		        PEEKCLASSIC_V567_HDR_SIZE);
207 		if (!wtap_read_bytes(wth->fh, &ep_hdr.secondary.v567,
208 		    (int)sizeof(ep_hdr.secondary.v567), err, err_info)) {
209 			if (*err != WTAP_ERR_SHORT_READ)
210 				return WTAP_OPEN_ERROR;
211 			return WTAP_OPEN_NOT_MINE;
212 		}
213 
214 		if ((0 != ep_hdr.secondary.v567.reserved[0]) ||
215 		    (0 != ep_hdr.secondary.v567.reserved[1]) ||
216 		    (0 != ep_hdr.secondary.v567.reserved[2])) {
217 			/* still unknown */
218 			return WTAP_OPEN_NOT_MINE;
219 		}
220 
221 		/*
222 		 * Check the mediaType and physMedium fields.
223 		 * We assume it's not a Peek classic file if
224 		 * these aren't values we know, rather than
225 		 * reporting them as invalid Peek classic files,
226 		 * as, given the lack of a magic number, we need
227 		 * all the checks we can get.
228 		 */
229 		ep_hdr.secondary.v567.mediaType =
230 		    g_ntohl(ep_hdr.secondary.v567.mediaType);
231 		ep_hdr.secondary.v567.physMedium =
232 		    g_ntohl(ep_hdr.secondary.v567.physMedium);
233 
234 		switch (ep_hdr.secondary.v567.physMedium) {
235 
236 		case 0:
237 			/*
238 			 * "Native" format, presumably meaning
239 			 * Ethernet or Token Ring.
240 			 */
241 			switch (ep_hdr.secondary.v567.mediaType) {
242 
243 			case 0:
244 				file_encap = WTAP_ENCAP_ETHERNET;
245 				break;
246 
247 			case 1:
248 				file_encap = WTAP_ENCAP_TOKEN_RING;
249 				break;
250 
251 			default:
252 				/*
253 				 * Assume this isn't a Peek classic file.
254 				 */
255 				return WTAP_OPEN_NOT_MINE;
256 			}
257 			break;
258 
259 		case 1:
260 			switch (ep_hdr.secondary.v567.mediaType) {
261 
262 			case 0:
263 				/*
264 				 * 802.11, with a private header giving
265 				 * some radio information.  Presumably
266 				 * this is from AiroPeek.
267 				 */
268 				file_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
269 				break;
270 
271 			default:
272 				/*
273 				 * Assume this isn't a Peek classic file.
274 				 */
275 				return WTAP_OPEN_NOT_MINE;
276 			}
277 			break;
278 
279 		default:
280 			/*
281 			 * Assume this isn't a Peek classic file.
282 			 */
283 			return WTAP_OPEN_NOT_MINE;
284 		}
285 
286 
287 		/*
288 		 * Assume this is a V5, V6 or V7 Peek classic file, and
289 		 * byte swap the rest of the fields in the secondary header.
290 		 *
291 		 * XXX - we could check the file length if the file were
292 		 * uncompressed, but it might be compressed.
293 		 */
294 		ep_hdr.secondary.v567.filelength =
295 		    g_ntohl(ep_hdr.secondary.v567.filelength);
296 		ep_hdr.secondary.v567.numPackets =
297 		    g_ntohl(ep_hdr.secondary.v567.numPackets);
298 		ep_hdr.secondary.v567.timeDate =
299 		    g_ntohl(ep_hdr.secondary.v567.timeDate);
300 		ep_hdr.secondary.v567.timeStart =
301 		    g_ntohl(ep_hdr.secondary.v567.timeStart);
302 		ep_hdr.secondary.v567.timeStop =
303 		    g_ntohl(ep_hdr.secondary.v567.timeStop);
304 		ep_hdr.secondary.v567.appVers =
305 		    g_ntohl(ep_hdr.secondary.v567.appVers);
306 		ep_hdr.secondary.v567.linkSpeed =
307 		    g_ntohl(ep_hdr.secondary.v567.linkSpeed);
308 
309 		/* Get the reference time as a time_t */
310 		reference_time = ep_hdr.secondary.v567.timeDate - EPOCH_DELTA_1904_01_01_00_00_00_UTC;
311 		break;
312 
313 	default:
314 		/*
315 		 * Assume this isn't a Peek classic file.
316 		 */
317 		return WTAP_OPEN_NOT_MINE;
318 	}
319 
320 	/*
321 	 * This is a Peek classic file.
322 	 *
323 	 * At this point we have recognised the file type and have populated
324 	 * the whole ep_hdr structure in host byte order.
325 	 */
326 	peekclassic = g_new(peekclassic_t, 1);
327 	wth->priv = (void *)peekclassic;
328 	peekclassic->reference_time = reference_time;
329 	wth->file_encap = file_encap;
330 	switch (ep_hdr.master.version) {
331 
332 	case 5:
333 	case 6:
334 		wth->file_type_subtype = peekclassic_v56_file_type_subtype;
335 		wth->subtype_read = peekclassic_read_v56;
336 		wth->subtype_seek_read = peekclassic_seek_read_v56;
337 		break;
338 
339 	case 7:
340 		wth->file_type_subtype = peekclassic_v7_file_type_subtype;
341 		wth->subtype_read = peekclassic_read_v7;
342 		wth->subtype_seek_read = peekclassic_seek_read_v7;
343 		break;
344 
345 	default:
346 		/* this is impossible */
347 		ws_assert_not_reached();
348 	}
349 
350 	wth->snapshot_length   = 0; /* not available in header */
351 	wth->file_tsprec = WTAP_TSPREC_USEC;
352 
353 	/*
354 	 * Add an IDB; we don't know how many interfaces were
355 	 * involved, so we just say one interface, about which
356 	 * we only know the link-layer type, snapshot length,
357 	 * and time stamp resolution.
358 	 */
359 	wtap_add_generated_idb(wth);
360 
361 	return WTAP_OPEN_MINE;
362 }
363 
peekclassic_read_v7(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)364 static gboolean peekclassic_read_v7(wtap *wth, wtap_rec *rec, Buffer *buf,
365     int *err, gchar **err_info, gint64 *data_offset)
366 {
367 	int sliceLength;
368 
369 	*data_offset = file_tell(wth->fh);
370 
371 	/* Read the packet. */
372 	sliceLength = peekclassic_read_packet_v7(wth, wth->fh, rec, buf,
373 	    err, err_info);
374 	if (sliceLength < 0)
375 		return FALSE;
376 
377 	/* Skip extra ignored data at the end of the packet. */
378 	if ((guint32)sliceLength > rec->rec_header.packet_header.caplen) {
379 		if (!wtap_read_bytes(wth->fh, NULL, sliceLength - rec->rec_header.packet_header.caplen,
380 		    err, err_info))
381 			return FALSE;
382 	}
383 
384 	/* Records are padded to an even length, so if the slice length
385 	   is odd, read the padding byte. */
386 	if (sliceLength & 0x01) {
387 		if (!wtap_read_bytes(wth->fh, NULL, 1, err, err_info))
388 			return FALSE;
389 	}
390 
391 	return TRUE;
392 }
393 
peekclassic_seek_read_v7(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)394 static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off,
395     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
396 {
397 	if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
398 		return FALSE;
399 
400 	/* Read the packet. */
401 	if (peekclassic_read_packet_v7(wth, wth->random_fh, rec, buf,
402 	    err, err_info) == -1) {
403 		if (*err == 0)
404 			*err = WTAP_ERR_SHORT_READ;
405 		return FALSE;
406 	}
407 	return TRUE;
408 }
409 
410 #define RADIO_INFO_SIZE	4
411 
peekclassic_read_packet_v7(wtap * wth,FILE_T fh,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)412 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
413     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
414 {
415 	guint8 ep_pkt[PEEKCLASSIC_V7_PKT_SIZE];
416 #if 0
417 	guint16 protoNum;
418 #endif
419 	guint16 length;
420 	guint16 sliceLength;
421 	guint8  flags;
422 	guint8  status;
423 	guint64 timestamp;
424 	time_t tsecs;
425 	guint32 tusecs;
426 	guint32 pack_flags;
427 	guint8 radio_info[RADIO_INFO_SIZE];
428 
429 	if (!wtap_read_bytes_or_eof(fh, ep_pkt, sizeof(ep_pkt), err, err_info))
430 		return -1;
431 
432 	/* Extract the fields from the packet */
433 #if 0
434 	protoNum = pntoh16(&ep_pkt[PEEKCLASSIC_V7_PROTONUM_OFFSET]);
435 #endif
436 	length = pntoh16(&ep_pkt[PEEKCLASSIC_V7_LENGTH_OFFSET]);
437 	sliceLength = pntoh16(&ep_pkt[PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET]);
438 	flags = ep_pkt[PEEKCLASSIC_V7_FLAGS_OFFSET];
439 	status = ep_pkt[PEEKCLASSIC_V7_STATUS_OFFSET];
440 	timestamp = pntoh64(&ep_pkt[PEEKCLASSIC_V7_TIMESTAMP_OFFSET]);
441 
442 	/* force sliceLength to be the actual length of the packet */
443 	if (0 == sliceLength) {
444 		sliceLength = length;
445 	}
446 	/*
447 	 * The maximum value of sliceLength and length are 65535, which
448 	 * are less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't
449 	 * need to check them.
450 	 */
451 
452 	/* fill in packet header values */
453 	rec->rec_type = REC_TYPE_PACKET;
454 	rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
455 	rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
456 	tsecs = (time_t) (timestamp/1000000);
457 	tusecs = (guint32) (timestamp - tsecs*1000000);
458 	rec->ts.secs  = tsecs - EPOCH_DELTA_1904_01_01_00_00_00_UTC;
459 	rec->ts.nsecs = tusecs * 1000;
460 	rec->rec_header.packet_header.len    = length;
461 	rec->rec_header.packet_header.caplen = sliceLength;
462 	pack_flags = 0;
463 	if (flags & FLAGS_HAS_CRC_ERROR)
464 		pack_flags |= PACK_FLAGS_CRC_ERROR;
465 	if (flags & FLAGS_FRAME_TOO_LONG)
466 		pack_flags |= PACK_FLAGS_PACKET_TOO_LONG;
467 	if (flags & FLAGS_FRAME_TOO_SHORT)
468 		pack_flags |= PACK_FLAGS_PACKET_TOO_SHORT;
469 	wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, pack_flags);
470 
471 	switch (wth->file_encap) {
472 
473 	case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
474 		memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
475 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = 0;		/* no FCS */
476 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = FALSE;
477 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = FALSE;
478 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
479 
480 		/*
481 		 * Now process the radio information pseudo-header.
482 		 * It's a 4-byte pseudo-header, consisting of:
483 		 *
484 		 *   1 byte of data rate, in units of 500 kb/s;
485 		 *
486 		 *   1 byte of channel number;
487 		 *
488 		 *   1 byte of signal strength as a percentage of
489 		 *   the maximum, i.e. (RXVECTOR RSSI/RXVECTOR RSSI_Max)*100,
490 		 *   or, at least, that's what I infer it is, given what
491 		 *   the WildPackets note "Converting Signal Strength
492 		 *   Percentage to dBm Values" says (it also says that
493 		 *   the conversion the percentage to a dBm value is
494 		 *   an adapter-dependent process, so, as we don't know
495 		 *   what type of adapter was used to do the capture,
496 		 *   we can't do the conversion);
497 		 *
498 		 *   1 byte of unknown content (padding?).
499 		 */
500 		if (rec->rec_header.packet_header.len < RADIO_INFO_SIZE || rec->rec_header.packet_header.caplen < RADIO_INFO_SIZE) {
501 			*err = WTAP_ERR_BAD_FILE;
502 			*err_info = g_strdup_printf("peekclassic: 802.11 packet has length < 4");
503 			return -1;
504 		}
505 		rec->rec_header.packet_header.len -= RADIO_INFO_SIZE;
506 		rec->rec_header.packet_header.caplen -= RADIO_INFO_SIZE;
507 		sliceLength -= RADIO_INFO_SIZE;
508 
509 		/* read the pseudo-header */
510 		if (!wtap_read_bytes(fh, radio_info, RADIO_INFO_SIZE, err, err_info))
511 			return -1;
512 
513 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = TRUE;
514 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate = radio_info[0];
515 
516 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = TRUE;
517 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = radio_info[1];
518 
519 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = TRUE;
520 		rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = radio_info[2];
521 
522 		/*
523 		 * We don't know they PHY, but we do have the data rate;
524 		 * try to guess it based on the data rate and channel.
525 		 */
526 		if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
527 			/* 11b */
528 			rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
529 			rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = FALSE;
530 		} else if (RATE_IS_OFDM(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
531 			/* 11a or 11g, depending on the band. */
532 			if (CHAN_IS_BG(rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel)) {
533 				/* 11g */
534 				rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
535 				rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = FALSE;
536 			} else {
537 				/* 11a */
538 				rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
539 				rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_channel_type = FALSE;
540 				rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = FALSE;
541 			}
542 		}
543 
544 		/*
545 		 * The last 4 bytes appear to be random data - the length
546 		 * might include the FCS - so we reduce the length by 4.
547 		 *
548 		 * Or maybe this is just the same kind of random 4 bytes
549 		 * of junk at the end you get in Wireless Sniffer
550 		 * captures.
551 		 */
552 		if (rec->rec_header.packet_header.len < 4 || rec->rec_header.packet_header.caplen < 4) {
553 			*err = WTAP_ERR_BAD_FILE;
554 			*err_info = g_strdup_printf("peekclassic: 802.11 packet has length < 8");
555 			return -1;
556 		}
557 		rec->rec_header.packet_header.len -= 4;
558 		rec->rec_header.packet_header.caplen -= 4;
559 		break;
560 
561 	case WTAP_ENCAP_ETHERNET:
562 		/* XXX - it appears that if the low-order bit of
563 		   "status" is 0, there's an FCS in this frame,
564 		   and if it's 1, there's 4 bytes of 0. */
565 		rec->rec_header.packet_header.pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4;
566 		break;
567 	}
568 
569 	/* read the packet data */
570 	if (!wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info))
571 		return -1;
572 
573 	return sliceLength;
574 }
575 
peekclassic_read_v56(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)576 static gboolean peekclassic_read_v56(wtap *wth, wtap_rec *rec, Buffer *buf,
577     int *err, gchar **err_info, gint64 *data_offset)
578 {
579 	*data_offset = file_tell(wth->fh);
580 
581 	/* read the packet */
582 	if (!peekclassic_read_packet_v56(wth, wth->fh, rec, buf,
583 	    err, err_info))
584 		return FALSE;
585 
586 	/*
587 	 * XXX - is the captured packet data padded to a multiple
588 	 * of 2 bytes?
589 	 */
590 	return TRUE;
591 }
592 
peekclassic_seek_read_v56(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)593 static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off,
594     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
595 {
596 	if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
597 		return FALSE;
598 
599 	/* read the packet */
600 	if (!peekclassic_read_packet_v56(wth, wth->random_fh, rec, buf,
601 	    err, err_info)) {
602 		if (*err == 0)
603 			*err = WTAP_ERR_SHORT_READ;
604 		return FALSE;
605 	}
606 	return TRUE;
607 }
608 
peekclassic_read_packet_v56(wtap * wth,FILE_T fh,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)609 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
610     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
611 {
612 	peekclassic_t *peekclassic = (peekclassic_t *)wth->priv;
613 	guint8 ep_pkt[PEEKCLASSIC_V56_PKT_SIZE];
614 	guint16 length;
615 	guint16 sliceLength;
616 	guint8  flags;
617 #if 0
618 	guint8  status;
619 #endif
620 	guint32 timestamp;
621 #if 0
622 	guint16 destNum;
623 	guint16 srcNum;
624 #endif
625 #if 0
626 	guint16 protoNum;
627 	char    protoStr[8];
628 #endif
629 	guint32 pack_flags;
630 
631 	if (!wtap_read_bytes_or_eof(fh, ep_pkt, sizeof(ep_pkt), err, err_info))
632 		return FALSE;
633 
634 	/* Extract the fields from the packet */
635 	length = pntoh16(&ep_pkt[PEEKCLASSIC_V56_LENGTH_OFFSET]);
636 	sliceLength = pntoh16(&ep_pkt[PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET]);
637 	flags = ep_pkt[PEEKCLASSIC_V56_FLAGS_OFFSET];
638 #if 0
639 	status = ep_pkt[PEEKCLASSIC_V56_STATUS_OFFSET];
640 #endif
641 	timestamp = pntoh32(&ep_pkt[PEEKCLASSIC_V56_TIMESTAMP_OFFSET]);
642 #if 0
643 	destNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_DESTNUM_OFFSET]);
644 	srcNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_SRCNUM_OFFSET]);
645 	protoNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_PROTONUM_OFFSET]);
646 	memcpy(protoStr, &ep_pkt[PEEKCLASSIC_V56_PROTOSTR_OFFSET],
647 	    sizeof protoStr);
648 #endif
649 
650 	/*
651 	 * XXX - is the captured packet data padded to a multiple
652 	 * of 2 bytes?
653 	 */
654 
655 	/* force sliceLength to be the actual length of the packet */
656 	if (0 == sliceLength) {
657 		sliceLength = length;
658 	}
659 	/*
660 	 * The maximum value of sliceLength and length are 65535, which
661 	 * are less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't
662 	 * need to check them.
663 	 */
664 
665 	/* fill in packet header values */
666 	rec->rec_type = REC_TYPE_PACKET;
667 	rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
668 	rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
669 	/* timestamp is in milliseconds since reference_time */
670 	rec->ts.secs  = peekclassic->reference_time + (timestamp / 1000);
671 	rec->ts.nsecs = 1000 * (timestamp % 1000) * 1000;
672 	rec->rec_header.packet_header.len      = length;
673 	rec->rec_header.packet_header.caplen   = sliceLength;
674 	pack_flags = 0;
675 	if (flags & FLAGS_HAS_CRC_ERROR)
676 		pack_flags |= PACK_FLAGS_CRC_ERROR;
677 	if (flags & FLAGS_FRAME_TOO_LONG)
678 		pack_flags |= PACK_FLAGS_PACKET_TOO_LONG;
679 	if (flags & FLAGS_FRAME_TOO_SHORT)
680 		pack_flags |= PACK_FLAGS_PACKET_TOO_SHORT;
681 	wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, pack_flags);
682 
683 	switch (wth->file_encap) {
684 
685 	case WTAP_ENCAP_ETHERNET:
686 		/* We assume there's no FCS in this frame. */
687 		rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
688 		break;
689 	}
690 
691 	/* read the packet data */
692 	return wtap_read_packet_bytes(fh, buf, sliceLength, err, err_info);
693 }
694 
695 static const struct supported_block_type peekclassic_v56_blocks_supported[] = {
696 	/*
697 	 * We support packet blocks, with no comments or other options.
698 	 */
699 	{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
700 };
701 
702 static const struct file_type_subtype_info peekclassic_v56_info = {
703 	"Savvius classic (V5 and V6)", "peekclassic56", "pkt", "tpc;apc;wpz",
704 	FALSE, BLOCKS_SUPPORTED(peekclassic_v56_blocks_supported),
705 	NULL, NULL, NULL
706 };
707 
708 static const struct supported_block_type peekclassic_v7_blocks_supported[] = {
709 	/*
710 	 * We support packet blocks, with no comments or other options.
711 	 */
712 	{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
713 };
714 
715 static const struct file_type_subtype_info peekclassic_v7_info = {
716 	"Savvius classic (V7)", "peekclassic7", "pkt", "tpc;apc;wpz",
717 	FALSE, BLOCKS_SUPPORTED(peekclassic_v7_blocks_supported),
718 	NULL, NULL, NULL
719 };
720 
register_peekclassic(void)721 void register_peekclassic(void)
722 {
723 	peekclassic_v56_file_type_subtype = wtap_register_file_type_subtype(&peekclassic_v56_info);
724 	peekclassic_v7_file_type_subtype = wtap_register_file_type_subtype(&peekclassic_v7_info);
725 
726 	/*
727 	 * Register names for backwards compatibility with the
728 	 * wtap_filetypes table in Lua.
729 	 */
730 	wtap_register_backwards_compatibility_lua_name("PEEKCLASSIC_V56",
731 	    peekclassic_v56_file_type_subtype);
732 	wtap_register_backwards_compatibility_lua_name("PEEKCLASSIC_V7",
733 	    peekclassic_v7_file_type_subtype);
734 }
735 
736 /*
737  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
738  *
739  * Local variables:
740  * c-basic-offset: 8
741  * tab-width: 8
742  * indent-tabs-mode: t
743  * End:
744  *
745  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
746  * :indentSize=8:tabSize=8:noTabs=false:
747  */
748