Merge "read record header" and "read packet data" routines into a single
[metze/wireshark/wip.git] / wiretap / peekclassic.c
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).
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  * $Id$
19  *
20  * Wiretap Library
21  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
22  *
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.
27  *
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.
32  *
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.
36  */
37
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
46  *
47  * This file decoder could not have been writen without examining how
48  * tcptrace (http://www.tcptrace.org/) handles EtherPeek files.
49  */
50
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
57
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
72
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;
80
81 /*
82  * Packet header (V5, V6).
83  *
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.)
88  *
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.
92  *
93  * So, instead, we #define numbers as the offsets of the fields.
94  */
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
106
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;
112
113 /*
114  * Packet header (V7).
115  *
116  * This doesn't have the same alignment problem, but we do it with
117  * #defines anyway.
118  */
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
126
127 typedef struct peekclassic_encap_lookup {
128         guint16 protoNum;
129         int     encap;
130 } peekclassic_encap_lookup_t;
131
132 static const unsigned int mac2unix = 2082844800u;
133 static const peekclassic_encap_lookup_t peekclassic_encap[] = {
134         { 1400, WTAP_ENCAP_ETHERNET }
135 };
136 #define NUM_PEEKCLASSIC_ENCAPS \
137         (sizeof (peekclassic_encap) / sizeof (peekclassic_encap[0]))
138
139 typedef struct {
140         struct timeval reference_time;
141 } peekclassic_t;
142
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);
157
158 int peekclassic_open(wtap *wth, int *err, gchar **err_info)
159 {
160         peekclassic_header_t ep_hdr;
161         int bytes_read;
162         struct timeval reference_time;
163         int file_encap;
164         peekclassic_t *peekclassic;
165
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.
173          */
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;
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                 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;
214                 }
215
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;
221                 }
222
223                 /*
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.
230                  */
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);
235
236                 switch (ep_hdr.secondary.v567.physMedium) {
237
238                 case 0:
239                         /*
240                          * "Native" format, presumably meaning
241                          * Ethernet or Token Ring.
242                          */
243                         switch (ep_hdr.secondary.v567.mediaType) {
244
245                         case 0:
246                                 file_encap = WTAP_ENCAP_ETHERNET;
247                                 break;
248
249                         case 1:
250                                 file_encap = WTAP_ENCAP_TOKEN_RING;
251                                 break;
252
253                         default:
254                                 /*
255                                  * Assume this isn't a Peek classic file.
256                                  */
257                                 return 0;
258                         }
259                         break;
260
261                 case 1:
262                         switch (ep_hdr.secondary.v567.mediaType) {
263
264                         case 0:
265                                 /*
266                                  * 802.11, with a private header giving
267                                  * some radio information.  Presumably
268                                  * this is from AiroPeek.
269                                  */
270                                 file_encap = WTAP_ENCAP_IEEE_802_11_AIROPEEK;
271                                 break;
272
273                         default:
274                                 /*
275                                  * Assume this isn't a Peek classic file.
276                                  */
277                                 return 0;
278                         }
279                         break;
280
281                 default:
282                         /*
283                          * Assume this isn't a Peek classic file.
284                          */
285                         return 0;
286                 }
287
288
289                 /*
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.
292                  *
293                  * XXX - we could check the file length if the file were
294                  * uncompressed, but it might be compressed.
295                  */
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);
310
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;
316
317         default:
318                 /*
319                  * Assume this isn't a Peek classic file.
320                  */
321                 return 0;
322         }
323
324         /*
325          * This is a Peek classic file.
326          *
327          * At this point we have recognised the file type and have populated
328          * the whole ep_hdr structure in host byte order.
329          */
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) {
334
335         case 5:
336         case 6:
337                 wth->file_type = WTAP_FILE_PEEKCLASSIC_V56;
338                 /*
339                  * XXX - can we get the file encapsulation from the
340                  * header in the same way we do for V7 files?
341                  */
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;
346
347         case 7:
348                 wth->file_type = WTAP_FILE_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;
353
354         default:
355                 /* this is impossible */
356                 g_assert_not_reached();
357         }
358
359         wth->snapshot_length   = 0; /* not available in header */
360         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
361
362         return 1;
363 }
364
365 static gboolean peekclassic_read_v7(wtap *wth, int *err, gchar **err_info,
366     gint64 *data_offset)
367 {
368         int sliceLength;
369
370         *data_offset = file_tell(wth->fh);
371
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;
377
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;
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 (!file_skip(wth->fh, 1, err))
388                         return FALSE;
389         }
390
391         return TRUE;
392 }
393
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)
397 {
398         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
399                 return FALSE;
400
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;
407         }
408         return TRUE;
409 }
410
411 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
412     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
413 {
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;
428
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;
435         }
436
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]);
448
449         /* force sliceLength to be the actual length of the packet */
450         if (0 == sliceLength) {
451                 sliceLength = length;
452         }
453
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;
462
463         switch (wth->file_encap) {
464
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;
468
469                 /*
470                  * The last 4 bytes appear to be random data - the length
471                  * might include the FCS - so we reduce the length by 4.
472                  *
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.
476                  */
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;
481                 }
482                 phdr->len -= 4;
483                 phdr->caplen -= 4;
484                 break;
485
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;
492         }
493
494         /* read the packet data */
495         if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
496                 return -1;
497
498         return sliceLength;
499 }
500
501 static gboolean peekclassic_read_v56(wtap *wth, int *err, gchar **err_info,
502     gint64 *data_offset)
503 {
504         *data_offset = file_tell(wth->fh);
505
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;
510
511         /*
512          * XXX - is the captured packet data padded to a multiple
513          * of 2 bytes?
514          */
515         return TRUE;
516 }
517
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)
521 {
522         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
523                 return FALSE;
524
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;
531         }
532         return TRUE;
533 }
534
535 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
536     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
537 {
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;
556
557         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), fh, err,
558             err_info);
559
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
577
578         /*
579          * XXX - is the captured packet data padded to a multiple
580          * of 2 bytes?
581          */
582
583         /* force sliceLength to be the actual length of the packet */
584         if (0 == sliceLength) {
585                 sliceLength = length;
586         }
587
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;
596
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;
601                 }
602         }
603
604         switch (phdr->pkt_encap) {
605
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;
610         }
611
612         /* read the packet data */
613         return wtap_read_packet_bytes(fh, buf, sliceLength, err, err_info);
614 }