DCERPC: factor out proto_tree_add_dcerpc_drep()
[wireshark-wip.git] / wiretap / peekclassic.c
blobf516775d479d46898c5a1f7cec8d66463abb6112
1 /* peekclassic.c
2 * Routines for opening files in what WildPackets calls the classic file
3 * format in the description of their "PeekRdr Sample Application" (C++
4 * source code to read their capture files, downloading of which requires
5 * a maintenance contract, so it's not free as in beer and probably not
6 * as in speech, either).
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.
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).
16 * Copyright (c) 2001, Daniel Thompson <d.thompson@gmx.net>
18 * $Id$
20 * Wiretap Library
21 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 #include "config.h"
39 #include <errno.h>
40 #include <string.h>
41 #include "wtap-int.h"
42 #include "file_wrappers.h"
43 #include "buffer.h"
44 #include "peekclassic.h"
45 /* CREDITS
47 * This file decoder could not have been writen without examining how
48 * tcptrace (http://www.tcptrace.org/) handles EtherPeek files.
51 /* master header */
52 typedef struct peekclassic_master_header {
53 guint8 version;
54 guint8 status;
55 } peekclassic_master_header_t;
56 #define PEEKCLASSIC_MASTER_HDR_SIZE 2
58 /* secondary header (V5,V6,V7) */
59 typedef struct peekclassic_v567_header {
60 guint32 filelength;
61 guint32 numPackets;
62 guint32 timeDate;
63 guint32 timeStart;
64 guint32 timeStop;
65 guint32 mediaType; /* Media Type Ethernet=0 Token Ring = 1 */
66 guint32 physMedium; /* Physical Medium native=0 802.1=1 */
67 guint32 appVers; /* App Version Number Maj.Min.Bug.Build */
68 guint32 linkSpeed; /* Link Speed Bits/sec */
69 guint32 reserved[3];
70 } peekclassic_v567_header_t;
71 #define PEEKCLASSIC_V567_HDR_SIZE 48
73 /* full header */
74 typedef struct peekclassic_header {
75 peekclassic_master_header_t master;
76 union {
77 peekclassic_v567_header_t v567;
78 } secondary;
79 } peekclassic_header_t;
82 * Packet header (V5, V6).
84 * NOTE: the time stamp, although it's a 32-bit number, is only aligned
85 * on a 16-bit boundary. (Does this date back to 68K Macs? The 68000
86 * only required 16-bit alignment of 32-bit quantities, as did the 68010,
87 * and the 68020/68030/68040 required no alignment.)
89 * As such, we cannot declare this as a C structure, as compilers on
90 * most platforms will put 2 bytes of padding before the time stamp to
91 * align it on a 32-bit boundary.
93 * So, instead, we #define numbers as the offsets of the fields.
95 #define PEEKCLASSIC_V56_LENGTH_OFFSET 0
96 #define PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET 2
97 #define PEEKCLASSIC_V56_FLAGS_OFFSET 4
98 #define PEEKCLASSIC_V56_STATUS_OFFSET 5
99 #define PEEKCLASSIC_V56_TIMESTAMP_OFFSET 6
100 #define PEEKCLASSIC_V56_DESTNUM_OFFSET 10
101 #define PEEKCLASSIC_V56_SRCNUM_OFFSET 12
102 #define PEEKCLASSIC_V56_PROTONUM_OFFSET 14
103 #define PEEKCLASSIC_V56_PROTOSTR_OFFSET 16
104 #define PEEKCLASSIC_V56_FILTERNUM_OFFSET 24
105 #define PEEKCLASSIC_V56_PKT_SIZE 26
107 /* 64-bit time in micro seconds from the (Mac) epoch */
108 typedef struct peekclassic_utime {
109 guint32 upper;
110 guint32 lower;
111 } peekclassic_utime;
114 * Packet header (V7).
116 * This doesn't have the same alignment problem, but we do it with
117 * #defines anyway.
119 #define PEEKCLASSIC_V7_PROTONUM_OFFSET 0
120 #define PEEKCLASSIC_V7_LENGTH_OFFSET 2
121 #define PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET 4
122 #define PEEKCLASSIC_V7_FLAGS_OFFSET 6
123 #define PEEKCLASSIC_V7_STATUS_OFFSET 7
124 #define PEEKCLASSIC_V7_TIMESTAMP_OFFSET 8
125 #define PEEKCLASSIC_V7_PKT_SIZE 16
127 typedef struct peekclassic_encap_lookup {
128 guint16 protoNum;
129 int encap;
130 } peekclassic_encap_lookup_t;
132 static const unsigned int mac2unix = 2082844800u;
133 static const peekclassic_encap_lookup_t peekclassic_encap[] = {
134 { 1400, WTAP_ENCAP_ETHERNET }
136 #define NUM_PEEKCLASSIC_ENCAPS \
137 (sizeof (peekclassic_encap) / sizeof (peekclassic_encap[0]))
139 typedef struct {
140 struct timeval reference_time;
141 } peekclassic_t;
143 static gboolean peekclassic_read_v7(wtap *wth, int *err, gchar **err_info,
144 gint64 *data_offset);
145 static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off,
146 struct wtap_pkthdr *phdr, Buffer *buf, int length,
147 int *err, gchar **err_info);
148 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
149 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
150 static gboolean peekclassic_read_v56(wtap *wth, int *err, gchar **err_info,
151 gint64 *data_offset);
152 static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off,
153 struct wtap_pkthdr *phdr, Buffer *buf, int length,
154 int *err, gchar **err_info);
155 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
156 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
158 int peekclassic_open(wtap *wth, int *err, gchar **err_info)
160 peekclassic_header_t ep_hdr;
161 int bytes_read;
162 struct timeval reference_time;
163 int file_encap;
164 peekclassic_t *peekclassic;
166 /* Peek classic files do not start with a magic value large enough
167 * to be unique; hence we use the following algorithm to determine
168 * the type of an unknown file:
169 * - populate the master header and reject file if there is no match
170 * - populate the secondary header and check that the reserved space
171 * is zero, and check some other fields; this isn't perfect,
172 * and we may have to add more checks at some point.
174 g_assert(sizeof(ep_hdr.master) == PEEKCLASSIC_MASTER_HDR_SIZE);
175 bytes_read = file_read(&ep_hdr.master, (int)sizeof(ep_hdr.master),
176 wth->fh);
177 if (bytes_read != sizeof(ep_hdr.master)) {
178 *err = file_error(wth->fh, err_info);
179 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
180 return -1;
181 return 0;
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.
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.
196 ep_hdr.master.version &= ~0x80;
198 /* switch on the file version */
199 switch (ep_hdr.master.version) {
201 case 5:
202 case 6:
203 case 7:
204 /* get the secondary header */
205 g_assert(sizeof(ep_hdr.secondary.v567) ==
206 PEEKCLASSIC_V567_HDR_SIZE);
207 bytes_read = file_read(&ep_hdr.secondary.v567,
208 (int)sizeof(ep_hdr.secondary.v567), wth->fh);
209 if (bytes_read != sizeof(ep_hdr.secondary.v567)) {
210 *err = file_error(wth->fh, err_info);
211 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
212 return -1;
213 return 0;
216 if ((0 != ep_hdr.secondary.v567.reserved[0]) ||
217 (0 != ep_hdr.secondary.v567.reserved[1]) ||
218 (0 != ep_hdr.secondary.v567.reserved[2])) {
219 /* still unknown */
220 return 0;
224 * Check the mediaType and physMedium fields.
225 * We assume it's not a Peek classic file if
226 * these aren't values we know, rather than
227 * reporting them as invalid Peek classic files,
228 * as, given the lack of a magic number, we need
229 * all the checks we can get.
231 ep_hdr.secondary.v567.mediaType =
232 g_ntohl(ep_hdr.secondary.v567.mediaType);
233 ep_hdr.secondary.v567.physMedium =
234 g_ntohl(ep_hdr.secondary.v567.physMedium);
236 switch (ep_hdr.secondary.v567.physMedium) {
238 case 0:
240 * "Native" format, presumably meaning
241 * Ethernet or Token Ring.
243 switch (ep_hdr.secondary.v567.mediaType) {
245 case 0:
246 file_encap = WTAP_ENCAP_ETHERNET;
247 break;
249 case 1:
250 file_encap = WTAP_ENCAP_TOKEN_RING;
251 break;
253 default:
255 * Assume this isn't a Peek classic file.
257 return 0;
259 break;
261 case 1:
262 switch (ep_hdr.secondary.v567.mediaType) {
264 case 0:
266 * 802.11, with a private header giving
267 * some radio information. Presumably
268 * this is from AiroPeek.
270 file_encap = WTAP_ENCAP_IEEE_802_11_AIROPEEK;
271 break;
273 default:
275 * Assume this isn't a Peek classic file.
277 return 0;
279 break;
281 default:
283 * Assume this isn't a Peek classic file.
285 return 0;
290 * Assume this is a V5, V6 or V7 Peek classic file, and
291 * byte swap the rest of the fields in the secondary header.
293 * XXX - we could check the file length if the file were
294 * uncompressed, but it might be compressed.
296 ep_hdr.secondary.v567.filelength =
297 g_ntohl(ep_hdr.secondary.v567.filelength);
298 ep_hdr.secondary.v567.numPackets =
299 g_ntohl(ep_hdr.secondary.v567.numPackets);
300 ep_hdr.secondary.v567.timeDate =
301 g_ntohl(ep_hdr.secondary.v567.timeDate);
302 ep_hdr.secondary.v567.timeStart =
303 g_ntohl(ep_hdr.secondary.v567.timeStart);
304 ep_hdr.secondary.v567.timeStop =
305 g_ntohl(ep_hdr.secondary.v567.timeStop);
306 ep_hdr.secondary.v567.appVers =
307 g_ntohl(ep_hdr.secondary.v567.appVers);
308 ep_hdr.secondary.v567.linkSpeed =
309 g_ntohl(ep_hdr.secondary.v567.linkSpeed);
311 /* Get the reference time as a "struct timeval" */
312 reference_time.tv_sec =
313 ep_hdr.secondary.v567.timeDate - mac2unix;
314 reference_time.tv_usec = 0;
315 break;
317 default:
319 * Assume this isn't a Peek classic file.
321 return 0;
325 * This is a Peek classic file.
327 * At this point we have recognised the file type and have populated
328 * the whole ep_hdr structure in host byte order.
330 peekclassic = (peekclassic_t *)g_malloc(sizeof(peekclassic_t));
331 wth->priv = (void *)peekclassic;
332 peekclassic->reference_time = reference_time;
333 switch (ep_hdr.master.version) {
335 case 5:
336 case 6:
337 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEEKCLASSIC_V56;
339 * XXX - can we get the file encapsulation from the
340 * header in the same way we do for V7 files?
342 wth->file_encap = WTAP_ENCAP_PER_PACKET;
343 wth->subtype_read = peekclassic_read_v56;
344 wth->subtype_seek_read = peekclassic_seek_read_v56;
345 break;
347 case 7:
348 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEEKCLASSIC_V7;
349 wth->file_encap = file_encap;
350 wth->subtype_read = peekclassic_read_v7;
351 wth->subtype_seek_read = peekclassic_seek_read_v7;
352 break;
354 default:
355 /* this is impossible */
356 g_assert_not_reached();
359 wth->snapshot_length = 0; /* not available in header */
360 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
362 return 1;
365 static gboolean peekclassic_read_v7(wtap *wth, int *err, gchar **err_info,
366 gint64 *data_offset)
368 int sliceLength;
370 *data_offset = file_tell(wth->fh);
372 /* Read the packet. */
373 sliceLength = peekclassic_read_packet_v7(wth, wth->fh, &wth->phdr,
374 wth->frame_buffer, err, err_info);
375 if (sliceLength < 0)
376 return FALSE;
378 /* Skip extra ignored data at the end of the packet. */
379 if ((guint32)sliceLength > wth->phdr.caplen) {
380 if (!file_skip(wth->fh, sliceLength - wth->phdr.caplen, err))
381 return FALSE;
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 (!file_skip(wth->fh, 1, err))
388 return FALSE;
391 return TRUE;
394 static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off,
395 struct wtap_pkthdr *phdr, Buffer *buf, int length _U_,
396 int *err, gchar **err_info)
398 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
399 return FALSE;
401 /* Read the packet. */
402 if (peekclassic_read_packet_v7(wth, wth->random_fh, phdr, buf,
403 err, err_info) == -1) {
404 if (*err == 0)
405 *err = WTAP_ERR_SHORT_READ;
406 return FALSE;
408 return TRUE;
411 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
412 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
414 guint8 ep_pkt[PEEKCLASSIC_V7_PKT_SIZE];
415 int bytes_read;
416 #if 0
417 guint16 protoNum;
418 #endif
419 guint16 length;
420 guint16 sliceLength;
421 #if 0
422 guint8 flags;
423 #endif
424 guint8 status;
425 guint64 timestamp;
426 time_t tsecs;
427 guint32 tusecs;
429 bytes_read = file_read(ep_pkt, sizeof(ep_pkt), fh);
430 if (bytes_read != (int) sizeof(ep_pkt)) {
431 *err = file_error(fh, err_info);
432 if (*err == 0 && bytes_read > 0)
433 *err = WTAP_ERR_SHORT_READ;
434 return -1;
437 /* Extract the fields from the packet */
438 #if 0
439 protoNum = pntohs(&ep_pkt[PEEKCLASSIC_V7_PROTONUM_OFFSET]);
440 #endif
441 length = pntohs(&ep_pkt[PEEKCLASSIC_V7_LENGTH_OFFSET]);
442 sliceLength = pntohs(&ep_pkt[PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET]);
443 #if 0
444 flags = ep_pkt[PEEKCLASSIC_V7_FLAGS_OFFSET];
445 #endif
446 status = ep_pkt[PEEKCLASSIC_V7_STATUS_OFFSET];
447 timestamp = pntohll(&ep_pkt[PEEKCLASSIC_V7_TIMESTAMP_OFFSET]);
449 /* force sliceLength to be the actual length of the packet */
450 if (0 == sliceLength) {
451 sliceLength = length;
454 /* fill in packet header values */
455 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
456 tsecs = (time_t) (timestamp/1000000);
457 tusecs = (guint32) (timestamp - tsecs*1000000);
458 phdr->ts.secs = tsecs - mac2unix;
459 phdr->ts.nsecs = tusecs * 1000;
460 phdr->len = length;
461 phdr->caplen = sliceLength;
463 switch (wth->file_encap) {
465 case WTAP_ENCAP_IEEE_802_11_AIROPEEK:
466 phdr->pseudo_header.ieee_802_11.fcs_len = 0; /* no FCS */
467 phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
470 * The last 4 bytes appear to be random data - the length
471 * might include the FCS - so we reduce the length by 4.
473 * Or maybe this is just the same kind of random 4 bytes
474 * of junk at the end you get in Wireless Sniffer
475 * captures.
477 if (phdr->len < 4 || phdr->caplen < 4) {
478 *err = WTAP_ERR_BAD_FILE;
479 *err_info = g_strdup_printf("peekclassic: 802.11 packet has length < 4");
480 return -1;
482 phdr->len -= 4;
483 phdr->caplen -= 4;
484 break;
486 case WTAP_ENCAP_ETHERNET:
487 /* XXX - it appears that if the low-order bit of
488 "status" is 0, there's an FCS in this frame,
489 and if it's 1, there's 4 bytes of 0. */
490 phdr->pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4;
491 break;
494 /* read the packet data */
495 if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
496 return -1;
498 return sliceLength;
501 static gboolean peekclassic_read_v56(wtap *wth, int *err, gchar **err_info,
502 gint64 *data_offset)
504 *data_offset = file_tell(wth->fh);
506 /* read the packet */
507 if (!peekclassic_read_packet_v56(wth, wth->fh, &wth->phdr,
508 wth->frame_buffer, err, err_info))
509 return FALSE;
512 * XXX - is the captured packet data padded to a multiple
513 * of 2 bytes?
515 return TRUE;
518 static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off,
519 struct wtap_pkthdr *phdr, Buffer *buf, int length _U_,
520 int *err, gchar **err_info)
522 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
523 return FALSE;
525 /* read the packet */
526 if (!peekclassic_read_packet_v56(wth, wth->random_fh, phdr, buf,
527 err, err_info)) {
528 if (*err == 0)
529 *err = WTAP_ERR_SHORT_READ;
530 return FALSE;
532 return TRUE;
535 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
536 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
538 peekclassic_t *peekclassic = (peekclassic_t *)wth->priv;
539 guint8 ep_pkt[PEEKCLASSIC_V56_PKT_SIZE];
540 guint16 length;
541 guint16 sliceLength;
542 #if 0
543 guint8 flags;
544 guint8 status;
545 #endif
546 guint32 timestamp;
547 #if 0
548 guint16 destNum;
549 guint16 srcNum;
550 #endif
551 guint16 protoNum;
552 #if 0
553 char protoStr[8];
554 #endif
555 unsigned int i;
557 wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), fh, err,
558 err_info);
560 /* Extract the fields from the packet */
561 length = pntohs(&ep_pkt[PEEKCLASSIC_V56_LENGTH_OFFSET]);
562 sliceLength = pntohs(&ep_pkt[PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET]);
563 #if 0
564 flags = ep_pkt[PEEKCLASSIC_V56_FLAGS_OFFSET];
565 status = ep_pkt[PEEKCLASSIC_V56_STATUS_OFFSET];
566 #endif
567 timestamp = pntohl(&ep_pkt[PEEKCLASSIC_V56_TIMESTAMP_OFFSET]);
568 #if 0
569 destNum = pntohs(&ep_pkt[PEEKCLASSIC_V56_DESTNUM_OFFSET]);
570 srcNum = pntohs(&ep_pkt[PEEKCLASSIC_V56_SRCNUM_OFFSET]);
571 #endif
572 protoNum = pntohs(&ep_pkt[PEEKCLASSIC_V56_PROTONUM_OFFSET]);
573 #if 0
574 memcpy(protoStr, &ep_pkt[PEEKCLASSIC_V56_PROTOSTR_OFFSET],
575 sizeof protoStr);
576 #endif
579 * XXX - is the captured packet data padded to a multiple
580 * of 2 bytes?
583 /* force sliceLength to be the actual length of the packet */
584 if (0 == sliceLength) {
585 sliceLength = length;
588 /* fill in packet header values */
589 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
590 /* timestamp is in milliseconds since reference_time */
591 phdr->ts.secs = peekclassic->reference_time.tv_sec
592 + (timestamp / 1000);
593 phdr->ts.nsecs = 1000 * (timestamp % 1000) * 1000;
594 phdr->len = length;
595 phdr->caplen = sliceLength;
597 phdr->pkt_encap = WTAP_ENCAP_UNKNOWN;
598 for (i=0; i<NUM_PEEKCLASSIC_ENCAPS; i++) {
599 if (peekclassic_encap[i].protoNum == protoNum) {
600 phdr->pkt_encap = peekclassic_encap[i].encap;
604 switch (phdr->pkt_encap) {
606 case WTAP_ENCAP_ETHERNET:
607 /* We assume there's no FCS in this frame. */
608 phdr->pseudo_header.eth.fcs_len = 0;
609 break;
612 /* read the packet data */
613 return wtap_read_packet_bytes(fh, buf, sliceLength, err, err_info);