smb-direct fragmentation
[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 *err, gchar **err_info);
147 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
148     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
149 static gboolean peekclassic_read_v56(wtap *wth, int *err, gchar **err_info,
150     gint64 *data_offset);
151 static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off,
152     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
153 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
154     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
155
156 int peekclassic_open(wtap *wth, int *err, gchar **err_info)
157 {
158         peekclassic_header_t ep_hdr;
159         int bytes_read;
160         struct timeval reference_time;
161         int file_encap;
162         peekclassic_t *peekclassic;
163
164         /* Peek classic files do not start with a magic value large enough
165          * to be unique; hence we use the following algorithm to determine
166          * the type of an unknown file:
167          *  - populate the master header and reject file if there is no match
168          *  - populate the secondary header and check that the reserved space
169          *      is zero, and check some other fields; this isn't perfect,
170          *      and we may have to add more checks at some point.
171          */
172         g_assert(sizeof(ep_hdr.master) == PEEKCLASSIC_MASTER_HDR_SIZE);
173         bytes_read = file_read(&ep_hdr.master, (int)sizeof(ep_hdr.master),
174             wth->fh);
175         if (bytes_read != sizeof(ep_hdr.master)) {
176                 *err = file_error(wth->fh, err_info);
177                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
178                         return -1;
179                 return 0;
180         }
181
182         /*
183          * It appears that EtherHelp (a free application from WildPackets
184          * that did blind capture, saving to a file, so that you could
185          * give the resulting file to somebody with EtherPeek) saved
186          * captures in EtherPeek format except that it ORed the 0x80
187          * bit on in the version number.
188          *
189          * We therefore strip off the 0x80 bit in the version number.
190          * Perhaps there's some reason to care whether the capture
191          * came from EtherHelp; if we discover one, we should check
192          * that bit.
193          */
194         ep_hdr.master.version &= ~0x80;
195
196         /* switch on the file version */
197         switch (ep_hdr.master.version) {
198
199         case 5:
200         case 6:
201         case 7:
202                 /* get the secondary header */
203                 g_assert(sizeof(ep_hdr.secondary.v567) ==
204                         PEEKCLASSIC_V567_HDR_SIZE);
205                 bytes_read = file_read(&ep_hdr.secondary.v567,
206                     (int)sizeof(ep_hdr.secondary.v567), wth->fh);
207                 if (bytes_read != sizeof(ep_hdr.secondary.v567)) {
208                         *err = file_error(wth->fh, err_info);
209                         if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
210                                 return -1;
211                         return 0;
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 0;
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 0;
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_AIROPEEK;
269                                 break;
270
271                         default:
272                                 /*
273                                  * Assume this isn't a Peek classic file.
274                                  */
275                                 return 0;
276                         }
277                         break;
278
279                 default:
280                         /*
281                          * Assume this isn't a Peek classic file.
282                          */
283                         return 0;
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 "struct timeval" */
310                 reference_time.tv_sec  =
311                     ep_hdr.secondary.v567.timeDate - mac2unix;
312                 reference_time.tv_usec = 0;
313                 break;
314
315         default:
316                 /*
317                  * Assume this isn't a Peek classic file.
318                  */
319                 return 0;
320         }
321
322         /*
323          * This is a Peek classic file.
324          *
325          * At this point we have recognised the file type and have populated
326          * the whole ep_hdr structure in host byte order.
327          */
328         peekclassic = (peekclassic_t *)g_malloc(sizeof(peekclassic_t));
329         wth->priv = (void *)peekclassic;
330         peekclassic->reference_time = reference_time;
331         switch (ep_hdr.master.version) {
332
333         case 5:
334         case 6:
335                 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEEKCLASSIC_V56;
336                 /*
337                  * XXX - can we get the file encapsulation from the
338                  * header in the same way we do for V7 files?
339                  */
340                 wth->file_encap = WTAP_ENCAP_PER_PACKET;
341                 wth->subtype_read = peekclassic_read_v56;
342                 wth->subtype_seek_read = peekclassic_seek_read_v56;
343                 break;
344
345         case 7:
346                 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEEKCLASSIC_V7;
347                 wth->file_encap = file_encap;
348                 wth->subtype_read = peekclassic_read_v7;
349                 wth->subtype_seek_read = peekclassic_seek_read_v7;
350                 break;
351
352         default:
353                 /* this is impossible */
354                 g_assert_not_reached();
355         }
356
357         wth->snapshot_length   = 0; /* not available in header */
358         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
359
360         return 1;
361 }
362
363 static gboolean peekclassic_read_v7(wtap *wth, int *err, gchar **err_info,
364     gint64 *data_offset)
365 {
366         int sliceLength;
367
368         *data_offset = file_tell(wth->fh);
369
370         /* Read the packet. */
371         sliceLength = peekclassic_read_packet_v7(wth, wth->fh, &wth->phdr,
372             wth->frame_buffer, err, err_info);
373         if (sliceLength < 0)
374                 return FALSE;
375
376         /* Skip extra ignored data at the end of the packet. */
377         if ((guint32)sliceLength > wth->phdr.caplen) {
378                 if (!file_skip(wth->fh, sliceLength - wth->phdr.caplen, err))
379                         return FALSE;
380         }
381
382         /* Records are padded to an even length, so if the slice length
383            is odd, read the padding byte. */
384         if (sliceLength & 0x01) {
385                 if (!file_skip(wth->fh, 1, err))
386                         return FALSE;
387         }
388
389         return TRUE;
390 }
391
392 static gboolean peekclassic_seek_read_v7(wtap *wth, gint64 seek_off,
393     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
394 {
395         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
396                 return FALSE;
397
398         /* Read the packet. */
399         if (peekclassic_read_packet_v7(wth, wth->random_fh, phdr, buf,
400             err, err_info) == -1) {
401                 if (*err == 0)
402                         *err = WTAP_ERR_SHORT_READ;
403                 return FALSE;
404         }
405         return TRUE;
406 }
407
408 static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
409     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
410 {
411         guint8 ep_pkt[PEEKCLASSIC_V7_PKT_SIZE];
412         int bytes_read;
413 #if 0
414         guint16 protoNum;
415 #endif
416         guint16 length;
417         guint16 sliceLength;
418 #if 0
419         guint8  flags;
420 #endif
421         guint8  status;
422         guint64 timestamp;
423         time_t tsecs;
424         guint32 tusecs;
425
426         bytes_read = file_read(ep_pkt, sizeof(ep_pkt), fh);
427         if (bytes_read != (int) sizeof(ep_pkt)) {
428                 *err = file_error(fh, err_info);
429                 if (*err == 0 && bytes_read > 0)
430                         *err = WTAP_ERR_SHORT_READ;
431                 return -1;
432         }
433
434         /* Extract the fields from the packet */
435 #if 0
436         protoNum = pntoh16(&ep_pkt[PEEKCLASSIC_V7_PROTONUM_OFFSET]);
437 #endif
438         length = pntoh16(&ep_pkt[PEEKCLASSIC_V7_LENGTH_OFFSET]);
439         sliceLength = pntoh16(&ep_pkt[PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET]);
440 #if 0
441         flags = ep_pkt[PEEKCLASSIC_V7_FLAGS_OFFSET];
442 #endif
443         status = ep_pkt[PEEKCLASSIC_V7_STATUS_OFFSET];
444         timestamp = pntoh64(&ep_pkt[PEEKCLASSIC_V7_TIMESTAMP_OFFSET]);
445
446         /* force sliceLength to be the actual length of the packet */
447         if (0 == sliceLength) {
448                 sliceLength = length;
449         }
450
451         /* fill in packet header values */
452         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
453         tsecs = (time_t) (timestamp/1000000);
454         tusecs = (guint32) (timestamp - tsecs*1000000);
455         phdr->ts.secs  = tsecs - mac2unix;
456         phdr->ts.nsecs = tusecs * 1000;
457         phdr->len    = length;
458         phdr->caplen = sliceLength;
459
460         switch (wth->file_encap) {
461
462         case WTAP_ENCAP_IEEE_802_11_AIROPEEK:
463                 phdr->pseudo_header.ieee_802_11.fcs_len = 0;            /* no FCS */
464                 phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
465
466                 /*
467                  * The last 4 bytes appear to be random data - the length
468                  * might include the FCS - so we reduce the length by 4.
469                  *
470                  * Or maybe this is just the same kind of random 4 bytes
471                  * of junk at the end you get in Wireless Sniffer
472                  * captures.
473                  */
474                 if (phdr->len < 4 || phdr->caplen < 4) {
475                         *err = WTAP_ERR_BAD_FILE;
476                         *err_info = g_strdup_printf("peekclassic: 802.11 packet has length < 4");
477                         return -1;
478                 }
479                 phdr->len -= 4;
480                 phdr->caplen -= 4;
481                 break;
482
483         case WTAP_ENCAP_ETHERNET:
484                 /* XXX - it appears that if the low-order bit of
485                    "status" is 0, there's an FCS in this frame,
486                    and if it's 1, there's 4 bytes of 0. */
487                 phdr->pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4;
488                 break;
489         }
490
491         /* read the packet data */
492         if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
493                 return -1;
494
495         return sliceLength;
496 }
497
498 static gboolean peekclassic_read_v56(wtap *wth, int *err, gchar **err_info,
499     gint64 *data_offset)
500 {
501         *data_offset = file_tell(wth->fh);
502
503         /* read the packet */
504         if (!peekclassic_read_packet_v56(wth, wth->fh, &wth->phdr,
505             wth->frame_buffer, err, err_info))
506                 return FALSE;
507
508         /*
509          * XXX - is the captured packet data padded to a multiple
510          * of 2 bytes?
511          */
512         return TRUE;
513 }
514
515 static gboolean peekclassic_seek_read_v56(wtap *wth, gint64 seek_off,
516     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
517 {
518         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
519                 return FALSE;
520
521         /* read the packet */
522         if (!peekclassic_read_packet_v56(wth, wth->random_fh, phdr, buf,
523             err, err_info)) {
524                 if (*err == 0)
525                         *err = WTAP_ERR_SHORT_READ;
526                 return FALSE;
527         }
528         return TRUE;
529 }
530
531 static gboolean peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
532     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
533 {
534         peekclassic_t *peekclassic = (peekclassic_t *)wth->priv;
535         guint8 ep_pkt[PEEKCLASSIC_V56_PKT_SIZE];
536         guint16 length;
537         guint16 sliceLength;
538 #if 0
539         guint8  flags;
540         guint8  status;
541 #endif
542         guint32 timestamp;
543 #if 0
544         guint16 destNum;
545         guint16 srcNum;
546 #endif
547         guint16 protoNum;
548 #if 0
549         char    protoStr[8];
550 #endif
551         unsigned int i;
552
553         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), fh, err,
554             err_info);
555
556         /* Extract the fields from the packet */
557         length = pntoh16(&ep_pkt[PEEKCLASSIC_V56_LENGTH_OFFSET]);
558         sliceLength = pntoh16(&ep_pkt[PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET]);
559 #if 0
560         flags = ep_pkt[PEEKCLASSIC_V56_FLAGS_OFFSET];
561         status = ep_pkt[PEEKCLASSIC_V56_STATUS_OFFSET];
562 #endif
563         timestamp = pntoh32(&ep_pkt[PEEKCLASSIC_V56_TIMESTAMP_OFFSET]);
564 #if 0
565         destNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_DESTNUM_OFFSET]);
566         srcNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_SRCNUM_OFFSET]);
567 #endif
568         protoNum = pntoh16(&ep_pkt[PEEKCLASSIC_V56_PROTONUM_OFFSET]);
569 #if 0
570         memcpy(protoStr, &ep_pkt[PEEKCLASSIC_V56_PROTOSTR_OFFSET],
571             sizeof protoStr);
572 #endif
573
574         /*
575          * XXX - is the captured packet data padded to a multiple
576          * of 2 bytes?
577          */
578
579         /* force sliceLength to be the actual length of the packet */
580         if (0 == sliceLength) {
581                 sliceLength = length;
582         }
583
584         /* fill in packet header values */
585         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
586         /* timestamp is in milliseconds since reference_time */
587         phdr->ts.secs  = peekclassic->reference_time.tv_sec
588             + (timestamp / 1000);
589         phdr->ts.nsecs = 1000 * (timestamp % 1000) * 1000;
590         phdr->len      = length;
591         phdr->caplen   = sliceLength;
592
593         phdr->pkt_encap = WTAP_ENCAP_UNKNOWN;
594         for (i=0; i<NUM_PEEKCLASSIC_ENCAPS; i++) {
595                 if (peekclassic_encap[i].protoNum == protoNum) {
596                         phdr->pkt_encap = peekclassic_encap[i].encap;
597                 }
598         }
599
600         switch (phdr->pkt_encap) {
601
602         case WTAP_ENCAP_ETHERNET:
603                 /* We assume there's no FCS in this frame. */
604                 phdr->pseudo_header.eth.fcs_len = 0;
605                 break;
606         }
607
608         /* read the packet data */
609         return wtap_read_packet_bytes(fh, buf, sliceLength, err, err_info);
610 }