When writing an option in an IDB, also write an endofoption option.
[obnox/wireshark/wip.git] / wiretap / etherpeek.c
1 /* etherpeek.c
2  * Routines for opening EtherPeek and AiroPeek (and TokenPeek?) V5, V6,
3  * and V7 files
4  * Copyright (c) 2001, Daniel Thompson <d.thompson@gmx.net>
5  *
6  * $Id$
7  *
8  * Wiretap Library
9  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 #include <errno.h>
30 #include <string.h>
31 #include "wtap-int.h"
32 #include "file_wrappers.h"
33 #include "buffer.h"
34 #include "etherpeek.h"
35 /* CREDITS
36  *
37  * This file decoder could not have been writen without examining how
38  * tcptrace (http://www.tcptrace.org/) handles EtherPeek files.
39  */
40
41 /*
42  * NOTE: it says "etherpeek" because the first files seen that use this
43  * format were EtherPeek files; however, AiroPeek files using it have
44  * also been seen, and I suspect TokenPeek uses it as well.
45  */
46
47 /* master header */
48 typedef struct etherpeek_master_header {
49         guint8  version;
50         guint8  status;
51 } etherpeek_master_header_t;
52 #define ETHERPEEK_MASTER_HDR_SIZE 2
53
54 /* secondary header (V5,V6,V7) */
55 typedef struct etherpeek_v567_header {
56         guint32 filelength;
57         guint32 numPackets;
58         guint32 timeDate;
59         guint32 timeStart;
60         guint32 timeStop;
61         guint32 mediaType;  /* Media Type Ethernet=0 Token Ring = 1 */
62         guint32 physMedium; /* Physical Medium native=0 802.1=1 */
63         guint32 appVers;    /* App Version Number Maj.Min.Bug.Build */
64         guint32 linkSpeed;  /* Link Speed Bits/sec */
65         guint32 reserved[3];
66 } etherpeek_v567_header_t;
67 #define ETHERPEEK_V567_HDR_SIZE 48
68
69 /* full header */
70 typedef struct etherpeek_header {
71         etherpeek_master_header_t master;
72         union {
73                 etherpeek_v567_header_t v567;
74         } secondary;
75 } etherpeek_header_t;
76
77 /*
78  * Packet header (V5, V6).
79  *
80  * NOTE: the time stamp, although it's a 32-bit number, is only aligned
81  * on a 16-bit boundary.  (Does this date back to 68K Macs?  The 68000
82  * only required 16-bit alignment of 32-bit quantities, as did the 68010,
83  * and the 68020/68030/68040 required no alignment.)
84  *
85  * As such, we cannot declare this as a C structure, as compilers on
86  * most platforms will put 2 bytes of padding before the time stamp to
87  * align it on a 32-bit boundary.
88  *
89  * So, instead, we #define numbers as the offsets of the fields.
90  */
91 #define ETHERPEEK_V56_LENGTH_OFFSET             0
92 #define ETHERPEEK_V56_SLICE_LENGTH_OFFSET       2
93 #define ETHERPEEK_V56_FLAGS_OFFSET              4
94 #define ETHERPEEK_V56_STATUS_OFFSET             5
95 #define ETHERPEEK_V56_TIMESTAMP_OFFSET          6
96 #define ETHERPEEK_V56_DESTNUM_OFFSET            10
97 #define ETHERPEEK_V56_SRCNUM_OFFSET             12
98 #define ETHERPEEK_V56_PROTONUM_OFFSET           14
99 #define ETHERPEEK_V56_PROTOSTR_OFFSET           16
100 #define ETHERPEEK_V56_FILTERNUM_OFFSET          24
101 #define ETHERPEEK_V56_PKT_SIZE                  26
102
103 /* 64-bit time in micro seconds from the (Mac) epoch */
104 typedef struct etherpeek_utime {
105         guint32 upper;
106         guint32 lower;
107 } etherpeek_utime;
108
109 /*
110  * Packet header (V7).
111  *
112  * This doesn't have the same alignment problem, but we do it with
113  * #defines anyway.
114  */
115 #define ETHERPEEK_V7_PROTONUM_OFFSET            0
116 #define ETHERPEEK_V7_LENGTH_OFFSET              2
117 #define ETHERPEEK_V7_SLICE_LENGTH_OFFSET        4
118 #define ETHERPEEK_V7_FLAGS_OFFSET               6
119 #define ETHERPEEK_V7_STATUS_OFFSET              7
120 #define ETHERPEEK_V7_TIMESTAMP_OFFSET           8
121 #define ETHERPEEK_V7_PKT_SIZE                   16
122
123 /*
124  * AiroPeek radio information, at the beginning of every packet.
125  */
126 typedef struct {
127         guint8  data_rate;
128         guint8  channel;
129         guint8  signal_level;
130         guint8  unused;
131 } airopeek_radio_hdr_t;
132
133 typedef struct etherpeek_encap_lookup {
134         guint16 protoNum;
135         int     encap;
136 } etherpeek_encap_lookup_t;
137
138 static const unsigned int mac2unix = 2082844800u;
139 static const etherpeek_encap_lookup_t etherpeek_encap[] = {
140         { 1400, WTAP_ENCAP_ETHERNET }
141 };
142 #define NUM_ETHERPEEK_ENCAPS \
143         (sizeof (etherpeek_encap) / sizeof (etherpeek_encap[0]))
144
145 typedef struct {
146         struct timeval reference_time;
147 } etherpeek_t;
148
149 static gboolean etherpeek_read_v7(wtap *wth, int *err, gchar **err_info,
150     gint64 *data_offset);
151 static gboolean etherpeek_seek_read_v7(wtap *wth, gint64 seek_off,
152     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
153     int *err, gchar **err_info);
154 static void etherpeek_fill_pseudo_header_v7(
155     union wtap_pseudo_header *pseudo_header, airopeek_radio_hdr_t *radio_hdr);
156 static gboolean etherpeek_read_v56(wtap *wth, int *err, gchar **err_info,
157     gint64 *data_offset);
158 static gboolean etherpeek_seek_read_v56(wtap *wth, gint64 seek_off,
159     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
160     int *err, gchar **err_info);
161
162 int etherpeek_open(wtap *wth, int *err, gchar **err_info)
163 {
164         etherpeek_header_t ep_hdr;
165         struct timeval reference_time;
166         int file_encap;
167         etherpeek_t *etherpeek;
168
169         /* EtherPeek files do not start with a magic value large enough
170          * to be unique; hence we use the following algorithm to determine
171          * the type of an unknown file:
172          *  - populate the master header and reject file if there is no match
173          *  - populate the secondary header and check that the reserved space
174          *      is zero, and check some other fields; this isn't perfect,
175          *      and we may have to add more checks at some point.
176          */
177         g_assert(sizeof(ep_hdr.master) == ETHERPEEK_MASTER_HDR_SIZE);
178         wtap_file_read_unknown_bytes(
179                 &ep_hdr.master, sizeof(ep_hdr.master), wth->fh, err, err_info);
180         wth->data_offset += sizeof(ep_hdr.master);
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                         ETHERPEEK_V567_HDR_SIZE);
205                 wtap_file_read_unknown_bytes(
206                         &ep_hdr.secondary.v567,
207                         sizeof(ep_hdr.secondary.v567), wth->fh, err, err_info);
208                 wth->data_offset += sizeof(ep_hdr.secondary.v567);
209
210                 if ((0 != ep_hdr.secondary.v567.reserved[0]) ||
211                     (0 != ep_hdr.secondary.v567.reserved[1]) ||
212                     (0 != ep_hdr.secondary.v567.reserved[2])) {
213                         /* still unknown */
214                         return 0;
215                 }
216
217                 /*
218                  * Check the mediaType and physMedium fields.
219                  * We assume it's not an EtherPeek/TokenPeek/AiroPeek
220                  * file if these aren't values we know, rather than
221                  * reporting them as invalid *Peek files, as, given
222                  * the lack of a magic number, we need all the checks
223                  * we can get.
224                  */
225                 ep_hdr.secondary.v567.mediaType =
226                     g_ntohl(ep_hdr.secondary.v567.mediaType);
227                 ep_hdr.secondary.v567.physMedium =
228                     g_ntohl(ep_hdr.secondary.v567.physMedium);
229
230                 switch (ep_hdr.secondary.v567.physMedium) {
231
232                 case 0:
233                         /*
234                          * "Native" format, presumably meaning
235                          * Ethernet or Token Ring.
236                          */
237                         switch (ep_hdr.secondary.v567.mediaType) {
238
239                         case 0:
240                                 file_encap = WTAP_ENCAP_ETHERNET;
241                                 break;
242
243                         case 1:
244                                 file_encap = WTAP_ENCAP_TOKEN_RING;
245                                 break;
246
247                         default:
248                                 /*
249                                  * Assume this isn't a *Peek file.
250                                  */
251                                 return 0;
252                         }
253                         break;
254
255                 case 1:
256                         switch (ep_hdr.secondary.v567.mediaType) {
257
258                         case 0:
259                                 /*
260                                  * 802.11, with a private header giving
261                                  * some radio information.  Presumably
262                                  * this is from AiroPeek.
263                                  *
264                                  * We supply the private header as
265                                  * the WTAP_ENCAP_IEEE_802_11_WITH_RADIO
266                                  * pseudo-header, rather than as frame
267                                  * data.
268                                  */
269                                 file_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
270                                 break;
271
272                         default:
273                                 /*
274                                  * Assume this isn't a *Peek file.
275                                  */
276                                 return 0;
277                         }
278                         break;
279
280                 default:
281                         /*
282                          * Assume this isn't a *Peek file.
283                          */
284                         return 0;
285                 }
286
287
288                 /*
289                  * Assume this is a V5, V6 or V7 *Peek file, and byte
290                  * swap the rest of the fields in the secondary header.
291                  *
292                  * XXX - we could check the file length if the file were
293                  * uncompressed, but it might be compressed.
294                  */
295                 ep_hdr.secondary.v567.filelength =
296                     g_ntohl(ep_hdr.secondary.v567.filelength);
297                 ep_hdr.secondary.v567.numPackets =
298                     g_ntohl(ep_hdr.secondary.v567.numPackets);
299                 ep_hdr.secondary.v567.timeDate =
300                     g_ntohl(ep_hdr.secondary.v567.timeDate);
301                 ep_hdr.secondary.v567.timeStart =
302                     g_ntohl(ep_hdr.secondary.v567.timeStart);
303                 ep_hdr.secondary.v567.timeStop =
304                     g_ntohl(ep_hdr.secondary.v567.timeStop);
305                 ep_hdr.secondary.v567.appVers =
306                     g_ntohl(ep_hdr.secondary.v567.appVers);
307                 ep_hdr.secondary.v567.linkSpeed =
308                     g_ntohl(ep_hdr.secondary.v567.linkSpeed);
309
310                 /* Get the reference time as a "struct timeval" */
311                 reference_time.tv_sec  =
312                     ep_hdr.secondary.v567.timeDate - mac2unix;
313                 reference_time.tv_usec = 0;
314                 break;
315
316         default:
317                 /*
318                  * Assume this isn't a *Peek file.
319                  */
320                 return 0;
321         }
322
323         /*
324          * This is an EtherPeek (or TokenPeek or AiroPeek?) file.
325          *
326          * At this point we have recognised the file type and have populated
327          * the whole ep_hdr structure in host byte order.
328          */
329         etherpeek = (etherpeek_t *)g_malloc(sizeof(etherpeek_t));
330         wth->priv = (void *)etherpeek;
331         etherpeek->reference_time = reference_time;
332         switch (ep_hdr.master.version) {
333
334         case 5:
335         case 6:
336                 wth->file_type = WTAP_FILE_ETHERPEEK_V56;
337                 /*
338                  * XXX - can we get the file encapsulation from the
339                  * header in the same way we do for V7 files?
340                  */
341                 wth->file_encap = WTAP_ENCAP_PER_PACKET;
342                 wth->subtype_read = etherpeek_read_v56;
343                 wth->subtype_seek_read = etherpeek_seek_read_v56;
344                 break;
345
346         case 7:
347                 wth->file_type = WTAP_FILE_ETHERPEEK_V7;
348                 wth->file_encap = file_encap;
349                 wth->subtype_read = etherpeek_read_v7;
350                 wth->subtype_seek_read = etherpeek_seek_read_v7;
351                 break;
352
353         default:
354                 /* this is impossible */
355                 g_assert_not_reached();
356         }
357
358         wth->snapshot_length   = 0; /* not available in header */
359         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
360
361         return 1;
362 }
363
364 static gboolean etherpeek_read_v7(wtap *wth, int *err, gchar **err_info,
365     gint64 *data_offset)
366 {
367         guint8 ep_pkt[ETHERPEEK_V7_PKT_SIZE];
368 #if 0
369         guint16 protoNum;
370 #endif
371         guint16 length;
372         guint16 sliceLength;
373 #if 0
374         guint8  flags;
375 #endif
376         guint8  status;
377         guint64 timestamp;
378         time_t tsecs;
379         guint32 tusecs;
380         airopeek_radio_hdr_t radio_hdr;
381
382         *data_offset = wth->data_offset;
383
384         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->fh, err,
385             err_info);
386         wth->data_offset += sizeof(ep_pkt);
387
388         /* Extract the fields from the packet */
389 #if 0
390         protoNum = pntohs(&ep_pkt[ETHERPEEK_V7_PROTONUM_OFFSET]);
391 #endif
392         length = pntohs(&ep_pkt[ETHERPEEK_V7_LENGTH_OFFSET]);
393         sliceLength = pntohs(&ep_pkt[ETHERPEEK_V7_SLICE_LENGTH_OFFSET]);
394 #if 0
395         flags = ep_pkt[ETHERPEEK_V7_FLAGS_OFFSET];
396 #endif
397         status = ep_pkt[ETHERPEEK_V7_STATUS_OFFSET];
398         timestamp = pntohll(&ep_pkt[ETHERPEEK_V7_TIMESTAMP_OFFSET]);
399
400         /* force sliceLength to be the actual length of the packet */
401         if (0 == sliceLength) {
402                 sliceLength = length;
403         }
404
405         /* fill in packet header length values before slicelength may be
406            adjusted */
407         wth->phdr.len    = length;
408         wth->phdr.caplen = sliceLength;
409
410         if (sliceLength % 2) /* packets are padded to an even length */
411                 sliceLength++;
412
413         switch (wth->file_encap) {
414
415         case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
416                 /*
417                  * The first 4 bytes of the packet data are radio
418                  * information (including a reserved byte).
419                  */
420                 if (sliceLength < 4) {
421                         /*
422                          * We don't *have* 4 bytes of packet data.
423                          */
424                         *err = WTAP_ERR_BAD_FILE;
425                         *err_info = g_strdup("etherpeek: packet not long enough for 802.11 radio header");
426                         return FALSE;
427                 }
428                 wtap_file_read_expected_bytes(&radio_hdr, 4, wth->fh, err,
429                     err_info);
430
431                 /*
432                  * We don't treat the radio information as packet data.
433                  */
434                 sliceLength -= 4;
435                 wth->phdr.len -= 4;
436                 wth->phdr.caplen -= 4;
437                 wth->data_offset += 4;
438
439                 etherpeek_fill_pseudo_header_v7(&wth->pseudo_header,
440                     &radio_hdr);
441                 break;
442
443         case WTAP_ENCAP_ETHERNET:
444                 /* XXX - it appears that if the low-order bit of
445                    "status" is 0, there's an FCS in this frame,
446                    and if it's 1, there's 4 bytes of 0. */
447                 wth->pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4;
448                 break;
449         }
450
451         /* read the frame data */
452         buffer_assure_space(wth->frame_buffer, sliceLength);
453         wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
454                                       sliceLength, wth->fh, err, err_info);
455         wth->data_offset += sliceLength;
456
457         /* fill in packet header values */
458         tsecs = (time_t) (timestamp/1000000);
459         tusecs = (guint32) (timestamp - tsecs*1000000);
460         wth->phdr.ts.secs  = tsecs - mac2unix;
461         wth->phdr.ts.nsecs = tusecs * 1000;
462
463         if (wth->file_encap == WTAP_ENCAP_IEEE_802_11_WITH_RADIO) {
464                 /*
465                  * The last 4 bytes appear to be random data - the length
466                  * might include the FCS - so we reduce the length by 4.
467                  *
468                  * Or maybe this is just the same kind of random 4 bytes
469                  * of junk at the end you get in Wireless Sniffer
470                  * captures.
471                  */
472                  wth->phdr.len -= 4;
473                  wth->phdr.caplen -= 4;
474         }
475
476         return TRUE;
477 }
478
479 static gboolean
480 etherpeek_seek_read_v7(wtap *wth, gint64 seek_off,
481     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
482     int *err, gchar **err_info)
483 {
484         guint8 ep_pkt[ETHERPEEK_V7_PKT_SIZE];
485         guint8  status;
486         airopeek_radio_hdr_t radio_hdr;
487
488         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
489                 return FALSE;
490
491         /* Read the packet header. */
492         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->random_fh,
493             err, err_info);
494         status = ep_pkt[ETHERPEEK_V7_STATUS_OFFSET];
495
496         switch (wth->file_encap) {
497
498         case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
499                 /*
500                  * The first 4 bytes of the packet data are radio
501                  * information (including a reserved byte).
502                  */
503                 if (length < 4) {
504                         /*
505                          * We don't *have* 4 bytes of packet data.
506                          */
507                         *err = WTAP_ERR_BAD_FILE;
508                         *err_info = g_strdup("etherpeek: packet not long enough for 802.11 radio header");
509                         return FALSE;
510                 }
511                 wtap_file_read_expected_bytes(&radio_hdr, 4, wth->random_fh,
512                     err, err_info);
513
514                 etherpeek_fill_pseudo_header_v7(pseudo_header,
515                     &radio_hdr);
516                 break;
517
518         case WTAP_ENCAP_ETHERNET:
519                 /* XXX - it appears that if the low-order bit of
520                    "status" is 0, there's an FCS in this frame,
521                    and if it's 1, there's 4 bytes of 0. */
522                 pseudo_header->eth.fcs_len = (status & 0x01) ? 0 : 4;
523                 break;
524         }
525
526         /*
527          * XXX - should "errno" be set in "wtap_file_read_expected_bytes()"?
528          */
529         errno = WTAP_ERR_CANT_READ;
530         wtap_file_read_expected_bytes(pd, length, wth->random_fh, err,
531             err_info);
532         return TRUE;
533 }
534
535 static void
536 etherpeek_fill_pseudo_header_v7(union wtap_pseudo_header *pseudo_header,
537     airopeek_radio_hdr_t *radio_hdr)
538 {
539         pseudo_header->ieee_802_11.fcs_len = 0;         /* no FCS */
540         pseudo_header->ieee_802_11.channel = radio_hdr->channel;
541         pseudo_header->ieee_802_11.data_rate = radio_hdr->data_rate;
542         pseudo_header->ieee_802_11.signal_level = radio_hdr->signal_level;
543 }
544
545 static gboolean etherpeek_read_v56(wtap *wth, int *err, gchar **err_info,
546     gint64 *data_offset)
547 {
548         etherpeek_t *etherpeek = (etherpeek_t *)wth->priv;
549         guint8 ep_pkt[ETHERPEEK_V56_PKT_SIZE];
550         guint16 length;
551         guint16 sliceLength;
552 #if 0
553         guint8  flags;
554         guint8  status;
555 #endif
556         guint32 timestamp;
557 #if 0
558         guint16 destNum;
559         guint16 srcNum;
560 #endif
561         guint16 protoNum;
562         char    protoStr[8];
563         unsigned int i;
564
565         /*
566          * XXX - in order to figure out whether this packet is an
567          * Ethernet packet or not, we have to look at the packet
568          * header, so we have to remember the address of the header,
569          * not the address of the data, for random access.
570          *
571          * If we can determine that from the file header, rather than
572          * the packet header, we can remember the offset of the data,
573          * and not have the seek_read routine read the header.
574          */
575         *data_offset = wth->data_offset;
576
577         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->fh, err,
578             err_info);
579         wth->data_offset += sizeof(ep_pkt);
580
581         /* Extract the fields from the packet */
582         length = pntohs(&ep_pkt[ETHERPEEK_V56_LENGTH_OFFSET]);
583         sliceLength = pntohs(&ep_pkt[ETHERPEEK_V56_SLICE_LENGTH_OFFSET]);
584 #if 0
585         flags = ep_pkt[ETHERPEEK_V56_FLAGS_OFFSET];
586         status = ep_pkt[ETHERPEEK_V56_STATUS_OFFSET];
587 #endif
588         timestamp = pntohl(&ep_pkt[ETHERPEEK_V56_TIMESTAMP_OFFSET]);
589 #if 0
590         destNum = pntohs(&ep_pkt[ETHERPEEK_V56_DESTNUM_OFFSET]);
591         srcNum = pntohs(&ep_pkt[ETHERPEEK_V56_SRCNUM_OFFSET]);
592 #endif
593         protoNum = pntohs(&ep_pkt[ETHERPEEK_V56_PROTONUM_OFFSET]);
594         memcpy(protoStr, &ep_pkt[ETHERPEEK_V56_PROTOSTR_OFFSET],
595             sizeof protoStr);
596
597         /*
598          * XXX - is the captured packet data padded to a multiple
599          * of 2 bytes?
600          */
601
602         /* force sliceLength to be the actual length of the packet */
603         if (0 == sliceLength) {
604                 sliceLength = length;
605         }
606
607         /* read the frame data */
608         buffer_assure_space(wth->frame_buffer, sliceLength);
609         wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
610                                       sliceLength, wth->fh, err, err_info);
611         wth->data_offset += sliceLength;
612
613         /* fill in packet header values */
614         wth->phdr.len        = length;
615         wth->phdr.caplen     = sliceLength;
616         /* timestamp is in milliseconds since reference_time */
617         wth->phdr.ts.secs  = etherpeek->reference_time.tv_sec
618             + (timestamp / 1000);
619         wth->phdr.ts.nsecs = 1000 * (timestamp % 1000) * 1000;
620
621         wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
622         for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
623                 if (etherpeek_encap[i].protoNum == protoNum) {
624                         wth->phdr.pkt_encap = etherpeek_encap[i].encap;
625                 }
626         }
627
628         switch (wth->phdr.pkt_encap) {
629
630         case WTAP_ENCAP_ETHERNET:
631                 /* We assume there's no FCS in this frame. */
632                 wth->pseudo_header.eth.fcs_len = 0;
633                 break;
634         }
635         return TRUE;
636 }
637
638 static gboolean
639 etherpeek_seek_read_v56(wtap *wth, gint64 seek_off,
640     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
641     int *err, gchar **err_info)
642 {
643         guint8 ep_pkt[ETHERPEEK_V56_PKT_SIZE];
644         int pkt_encap;
645         guint16 protoNum;
646         unsigned int i;
647
648         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
649                 return FALSE;
650
651         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->random_fh,
652             err, err_info);
653
654         protoNum = pntohs(&ep_pkt[ETHERPEEK_V56_PROTONUM_OFFSET]);
655         pkt_encap = WTAP_ENCAP_UNKNOWN;
656         for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
657                 if (etherpeek_encap[i].protoNum == protoNum) {
658                         pkt_encap = etherpeek_encap[i].encap;
659                 }
660         }
661
662         switch (pkt_encap) {
663
664         case WTAP_ENCAP_ETHERNET:
665                 /* We assume there's no FCS in this frame. */
666                 pseudo_header->eth.fcs_len = 0;
667                 break;
668         }
669
670         /*
671          * XXX - should "errno" be set in "wtap_file_read_expected_bytes()"?
672          */
673         errno = WTAP_ERR_CANT_READ;
674         wtap_file_read_expected_bytes(pd, length, wth->random_fh, err,
675             err_info);
676         return TRUE;
677 }