Remove the (long deprecated) proto_tree_add_*_hidden() functions
[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 static gboolean etherpeek_read_v7(wtap *wth, int *err, gchar **err_info,
146     gint64 *data_offset);
147 static gboolean etherpeek_seek_read_v7(wtap *wth, gint64 seek_off,
148     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
149     int *err, gchar **err_info);
150 static void etherpeek_fill_pseudo_header_v7(
151     union wtap_pseudo_header *pseudo_header, airopeek_radio_hdr_t *radio_hdr);
152 static gboolean etherpeek_read_v56(wtap *wth, int *err, gchar **err_info,
153     gint64 *data_offset);
154 static gboolean etherpeek_seek_read_v56(wtap *wth, gint64 seek_off,
155     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
156     int *err, gchar **err_info);
157 static void etherpeek_close(wtap *wth);
158
159 int etherpeek_open(wtap *wth, int *err, gchar **err_info _U_)
160 {
161         etherpeek_header_t ep_hdr;
162         struct timeval reference_time;
163         int file_encap;
164
165         /* EtherPeek files do not start with a magic value large enough
166          * to be unique; hence we use the following algorithm to determine
167          * the type of an unknown file:
168          *  - populate the master header and reject file if there is no match
169          *  - populate the secondary header and check that the reserved space
170          *      is zero, and check some other fields; this isn't perfect,
171          *      and we may have to add more checks at some point.
172          */
173         g_assert(sizeof(ep_hdr.master) == ETHERPEEK_MASTER_HDR_SIZE);
174         wtap_file_read_unknown_bytes(
175                 &ep_hdr.master, sizeof(ep_hdr.master), wth->fh, err);
176         wth->data_offset += sizeof(ep_hdr.master);
177
178         /*
179          * It appears that EtherHelp (a free application from WildPackets
180          * that did blind capture, saving to a file, so that you could
181          * give the resulting file to somebody with EtherPeek) saved
182          * captures in EtherPeek format except that it ORed the 0x80
183          * bit on in the version number.
184          *
185          * We therefore strip off the 0x80 bit in the version number.
186          * Perhaps there's some reason to care whether the capture
187          * came from EtherHelp; if we discover one, we should check
188          * that bit.
189          */
190         ep_hdr.master.version &= ~0x80;
191
192         /* switch on the file version */
193         switch (ep_hdr.master.version) {
194
195         case 5:
196         case 6:
197         case 7:
198                 /* get the secondary header */
199                 g_assert(sizeof(ep_hdr.secondary.v567) ==
200                         ETHERPEEK_V567_HDR_SIZE);
201                 wtap_file_read_unknown_bytes(
202                         &ep_hdr.secondary.v567,
203                         sizeof(ep_hdr.secondary.v567), wth->fh, err);
204                 wth->data_offset += sizeof(ep_hdr.secondary.v567);
205
206                 if ((0 != ep_hdr.secondary.v567.reserved[0]) ||
207                     (0 != ep_hdr.secondary.v567.reserved[1]) ||
208                     (0 != ep_hdr.secondary.v567.reserved[2])) {
209                         /* still unknown */
210                         return 0;
211                 }
212
213                 /*
214                  * Check the mediaType and physMedium fields.
215                  * We assume it's not an EtherPeek/TokenPeek/AiroPeek
216                  * file if these aren't values we know, rather than
217                  * reporting them as invalid *Peek files, as, given
218                  * the lack of a magic number, we need all the checks
219                  * we can get.
220                  */
221                 ep_hdr.secondary.v567.mediaType =
222                     g_ntohl(ep_hdr.secondary.v567.mediaType);
223                 ep_hdr.secondary.v567.physMedium =
224                     g_ntohl(ep_hdr.secondary.v567.physMedium);
225
226                 switch (ep_hdr.secondary.v567.physMedium) {
227
228                 case 0:
229                         /*
230                          * "Native" format, presumably meaning
231                          * Ethernet or Token Ring.
232                          */
233                         switch (ep_hdr.secondary.v567.mediaType) {
234
235                         case 0:
236                                 file_encap = WTAP_ENCAP_ETHERNET;
237                                 break;
238
239                         case 1:
240                                 file_encap = WTAP_ENCAP_TOKEN_RING;
241                                 break;
242
243                         default:
244                                 /*
245                                  * Assume this isn't a *Peek file.
246                                  */
247                                 return 0;
248                         }
249                         break;
250
251                 case 1:
252                         switch (ep_hdr.secondary.v567.mediaType) {
253
254                         case 0:
255                                 /*
256                                  * 802.11, with a private header giving
257                                  * some radio information.  Presumably
258                                  * this is from AiroPeek.
259                                  *
260                                  * We supply the private header as
261                                  * the WTAP_ENCAP_IEEE_802_11_WITH_RADIO
262                                  * pseudo-header, rather than as frame
263                                  * data.
264                                  */
265                                 file_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
266                                 break;
267
268                         default:
269                                 /*
270                                  * Assume this isn't a *Peek file.
271                                  */
272                                 return 0;
273                         }
274                         break;
275
276                 default:
277                         /*
278                          * Assume this isn't a *Peek file.
279                          */
280                         return 0;
281                 }
282
283
284                 /*
285                  * Assume this is a V5, V6 or V7 *Peek file, and byte
286                  * swap the rest of the fields in the secondary header.
287                  *
288                  * XXX - we could check the file length if the file were
289                  * uncompressed, but it might be compressed.
290                  */
291                 ep_hdr.secondary.v567.filelength =
292                     g_ntohl(ep_hdr.secondary.v567.filelength);
293                 ep_hdr.secondary.v567.numPackets =
294                     g_ntohl(ep_hdr.secondary.v567.numPackets);
295                 ep_hdr.secondary.v567.timeDate =
296                     g_ntohl(ep_hdr.secondary.v567.timeDate);
297                 ep_hdr.secondary.v567.timeStart =
298                     g_ntohl(ep_hdr.secondary.v567.timeStart);
299                 ep_hdr.secondary.v567.timeStop =
300                     g_ntohl(ep_hdr.secondary.v567.timeStop);
301                 ep_hdr.secondary.v567.appVers =
302                     g_ntohl(ep_hdr.secondary.v567.appVers);
303                 ep_hdr.secondary.v567.linkSpeed =
304                     g_ntohl(ep_hdr.secondary.v567.linkSpeed);
305
306                 /* Get the reference time as a "struct timeval" */
307                 reference_time.tv_sec  =
308                     ep_hdr.secondary.v567.timeDate - mac2unix;
309                 reference_time.tv_usec = 0;
310                 break;
311
312         default:
313                 /*
314                  * Assume this isn't a *Peek file.
315                  */
316                 return 0;
317         }
318
319         /*
320          * This is an EtherPeek (or TokenPeek or AiroPeek?) file.
321          *
322          * At this point we have recognised the file type and have populated
323          * the whole ep_hdr structure in host byte order.
324          */
325         wth->capture.etherpeek = g_malloc(sizeof(etherpeek_t));
326         wth->capture.etherpeek->reference_time = reference_time;
327         wth->subtype_close = etherpeek_close;
328         switch (ep_hdr.master.version) {
329
330         case 5:
331         case 6:
332                 wth->file_type = WTAP_FILE_ETHERPEEK_V56;
333                 /*
334                  * XXX - can we get the file encapsulation from the
335                  * header in the same way we do for V7 files?
336                  */
337                 wth->file_encap = WTAP_ENCAP_PER_PACKET;
338                 wth->subtype_read = etherpeek_read_v56;
339                 wth->subtype_seek_read = etherpeek_seek_read_v56;
340                 break;
341
342         case 7:
343                 wth->file_type = WTAP_FILE_ETHERPEEK_V7;
344                 wth->file_encap = file_encap;
345                 wth->subtype_read = etherpeek_read_v7;
346                 wth->subtype_seek_read = etherpeek_seek_read_v7;
347                 break;
348
349         default:
350                 /* this is impossible */
351                 g_assert_not_reached();
352         }
353
354         wth->snapshot_length   = 0; /* not available in header */
355     wth->tsprecision = WTAP_FILE_TSPREC_USEC;
356
357         return 1;
358 }
359
360 static void etherpeek_close(wtap *wth)
361 {
362         g_free(wth->capture.etherpeek);
363 }
364
365 static gboolean etherpeek_read_v7(wtap *wth, int *err, gchar **err_info,
366     gint64 *data_offset)
367 {
368         guchar ep_pkt[ETHERPEEK_V7_PKT_SIZE];
369         guint16 protoNum;
370         guint16 length;
371         guint16 sliceLength;
372         guint8  flags;
373         guint8  status;
374         guint64 timestamp;
375         time_t tsecs;
376         guint32 tusecs;
377         airopeek_radio_hdr_t radio_hdr;
378
379         *data_offset = wth->data_offset;
380
381         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->fh, err);
382         wth->data_offset += sizeof(ep_pkt);
383
384         /* Extract the fields from the packet */
385         protoNum = pntohs(&ep_pkt[ETHERPEEK_V7_PROTONUM_OFFSET]);
386         length = pntohs(&ep_pkt[ETHERPEEK_V7_LENGTH_OFFSET]);
387         sliceLength = pntohs(&ep_pkt[ETHERPEEK_V7_SLICE_LENGTH_OFFSET]);
388         flags = ep_pkt[ETHERPEEK_V7_FLAGS_OFFSET];
389         status = ep_pkt[ETHERPEEK_V7_STATUS_OFFSET];
390         timestamp = pntohll(&ep_pkt[ETHERPEEK_V7_TIMESTAMP_OFFSET]);
391
392         /* force sliceLength to be the actual length of the packet */
393         if (0 == sliceLength) {
394                 sliceLength = length;
395         }
396
397         /* fill in packet header length values before slicelength may be
398            adjusted */
399         wth->phdr.len    = length;
400         wth->phdr.caplen = sliceLength;
401
402         if (sliceLength % 2) /* packets are padded to an even length */
403                 sliceLength++;
404
405         switch (wth->file_encap) {
406
407         case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
408                 /*
409                  * The first 4 bytes of the packet data are radio
410                  * information (including a reserved byte).
411                  */
412                 if (sliceLength < 4) {
413                         /*
414                          * We don't *have* 4 bytes of packet data.
415                          */
416                         *err = WTAP_ERR_BAD_RECORD;
417                         *err_info = g_strdup("etherpeek: packet not long enough for 802.11 radio header");
418                         return FALSE;
419                 }
420                 wtap_file_read_expected_bytes(&radio_hdr, 4, wth->fh, err);
421
422                 /*
423                  * We don't treat the radio information as packet data.
424                  */
425                 sliceLength -= 4;
426                 wth->phdr.len -= 4;
427                 wth->phdr.caplen -= 4;
428                 wth->data_offset += 4;
429
430                 etherpeek_fill_pseudo_header_v7(&wth->pseudo_header,
431                     &radio_hdr);
432                 break;
433
434         case WTAP_ENCAP_ETHERNET:
435                 /* XXX - it appears that if the low-order bit of
436                    "status" is 0, there's an FCS in this frame,
437                    and if it's 1, there's 4 bytes of 0. */
438                 wth->pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4;
439                 break;
440         }
441
442         /* read the frame data */
443         buffer_assure_space(wth->frame_buffer, sliceLength);
444         wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
445                                       sliceLength, wth->fh, err);
446         wth->data_offset += sliceLength;
447
448         /* fill in packet header values */
449         tsecs = (time_t) (timestamp/1000000);
450         tusecs = (guint32) (timestamp - tsecs*1000000);
451         wth->phdr.ts.secs  = tsecs - mac2unix;
452         wth->phdr.ts.nsecs = tusecs * 1000;
453
454         if (wth->file_encap == WTAP_ENCAP_IEEE_802_11_WITH_RADIO) {
455                 /*
456                  * The last 4 bytes appear to be random data - the length
457                  * might include the FCS - so we reduce the length by 4.
458                  *
459                  * Or maybe this is just the same kind of random 4 bytes
460                  * of junk at the end you get in Wireless Sniffer
461                  * captures.
462                  */
463                  wth->phdr.len -= 4;
464                  wth->phdr.caplen -= 4;
465         }
466
467         return TRUE;
468 }
469
470 static gboolean
471 etherpeek_seek_read_v7(wtap *wth, gint64 seek_off,
472     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
473     int *err, gchar **err_info)
474 {
475         guchar ep_pkt[ETHERPEEK_V7_PKT_SIZE];
476         guint8  status;
477         airopeek_radio_hdr_t radio_hdr;
478
479         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
480                 return FALSE;
481
482         /* Read the packet header. */
483         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->random_fh,
484             err);
485         status = ep_pkt[ETHERPEEK_V7_STATUS_OFFSET];
486
487         switch (wth->file_encap) {
488
489         case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
490                 /*
491                  * The first 4 bytes of the packet data are radio
492                  * information (including a reserved byte).
493                  */
494                 if (length < 4) {
495                         /*
496                          * We don't *have* 4 bytes of packet data.
497                          */
498                         *err = WTAP_ERR_BAD_RECORD;
499                         *err_info = g_strdup("etherpeek: packet not long enough for 802.11 radio header");
500                         return FALSE;
501                 }
502                 wtap_file_read_expected_bytes(&radio_hdr, 4, wth->random_fh,
503                     err);
504
505                 etherpeek_fill_pseudo_header_v7(pseudo_header,
506                     &radio_hdr);
507                 break;
508
509         case WTAP_ENCAP_ETHERNET:
510                 /* XXX - it appears that if the low-order bit of
511                    "status" is 0, there's an FCS in this frame,
512                    and if it's 1, there's 4 bytes of 0. */
513                 pseudo_header->eth.fcs_len = (status & 0x01) ? 0 : 4;
514                 break;
515         }
516
517         /*
518          * XXX - should "errno" be set in "wtap_file_read_expected_bytes()"?
519          */
520         errno = WTAP_ERR_CANT_READ;
521         wtap_file_read_expected_bytes(pd, length, wth->random_fh, err);
522         return TRUE;
523 }
524
525 static void
526 etherpeek_fill_pseudo_header_v7(union wtap_pseudo_header *pseudo_header,
527     airopeek_radio_hdr_t *radio_hdr)
528 {
529         pseudo_header->ieee_802_11.fcs_len = 0;         /* no FCS */
530         pseudo_header->ieee_802_11.channel = radio_hdr->channel;
531         pseudo_header->ieee_802_11.data_rate = radio_hdr->data_rate;
532         pseudo_header->ieee_802_11.signal_level = radio_hdr->signal_level;
533 }
534
535 static gboolean etherpeek_read_v56(wtap *wth, int *err, gchar **err_info _U_,
536     gint64 *data_offset)
537 {
538         guchar ep_pkt[ETHERPEEK_V56_PKT_SIZE];
539         guint16 length;
540         guint16 sliceLength;
541         guint8  flags;
542         guint8  status;
543         guint32 timestamp;
544         guint16 destNum;
545         guint16 srcNum;
546         guint16 protoNum;
547         char    protoStr[8];
548         unsigned int i;
549
550         /*
551          * XXX - in order to figure out whether this packet is an
552          * Ethernet packet or not, we have to look at the packet
553          * header, so we have to remember the address of the header,
554          * not the address of the data, for random access.
555          *
556          * If we can determine that from the file header, rather than
557          * the packet header, we can remember the offset of the data,
558          * and not have the seek_read routine read the header.
559          */
560         *data_offset = wth->data_offset;
561
562         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->fh, err);
563         wth->data_offset += sizeof(ep_pkt);
564
565         /* Extract the fields from the packet */
566         length = pntohs(&ep_pkt[ETHERPEEK_V56_LENGTH_OFFSET]);
567         sliceLength = pntohs(&ep_pkt[ETHERPEEK_V56_SLICE_LENGTH_OFFSET]);
568         flags = ep_pkt[ETHERPEEK_V56_FLAGS_OFFSET];
569         status = ep_pkt[ETHERPEEK_V56_STATUS_OFFSET];
570         timestamp = pntohl(&ep_pkt[ETHERPEEK_V56_TIMESTAMP_OFFSET]);
571         destNum = pntohs(&ep_pkt[ETHERPEEK_V56_DESTNUM_OFFSET]);
572         srcNum = pntohs(&ep_pkt[ETHERPEEK_V56_SRCNUM_OFFSET]);
573         protoNum = pntohs(&ep_pkt[ETHERPEEK_V56_PROTONUM_OFFSET]);
574         memcpy(protoStr, &ep_pkt[ETHERPEEK_V56_PROTOSTR_OFFSET],
575             sizeof protoStr);
576
577         /*
578          * XXX - is the captured packet data padded to a multiple
579          * of 2 bytes?
580          */
581
582         /* force sliceLength to be the actual length of the packet */
583         if (0 == sliceLength) {
584                 sliceLength = length;
585         }
586
587         /* read the frame data */
588         buffer_assure_space(wth->frame_buffer, sliceLength);
589         wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
590                                       sliceLength, wth->fh, err);
591         wth->data_offset += sliceLength;
592
593         /* fill in packet header values */
594         wth->phdr.len        = length;
595         wth->phdr.caplen     = sliceLength;
596         /* timestamp is in milliseconds since reference_time */
597         wth->phdr.ts.secs  = wth->capture.etherpeek->reference_time.tv_sec
598             + (timestamp / 1000);
599         wth->phdr.ts.nsecs = 1000 * (timestamp % 1000) * 1000;
600
601         wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
602         for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
603                 if (etherpeek_encap[i].protoNum == protoNum) {
604                         wth->phdr.pkt_encap = etherpeek_encap[i].encap;
605                 }
606         }
607
608         switch (wth->phdr.pkt_encap) {
609
610         case WTAP_ENCAP_ETHERNET:
611                 /* We assume there's no FCS in this frame. */
612                 wth->pseudo_header.eth.fcs_len = 0;
613                 break;
614         }
615         return TRUE;
616 }
617
618 static gboolean
619 etherpeek_seek_read_v56(wtap *wth, gint64 seek_off,
620     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
621     int *err, gchar **err_info _U_)
622 {
623         guchar ep_pkt[ETHERPEEK_V56_PKT_SIZE];
624         int pkt_encap;
625         guint16 protoNum;
626         unsigned int i;
627
628         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
629                 return FALSE;
630
631         wtap_file_read_expected_bytes(ep_pkt, sizeof(ep_pkt), wth->random_fh,
632             err);
633
634         protoNum = pntohs(&ep_pkt[ETHERPEEK_V56_PROTONUM_OFFSET]);
635         pkt_encap = WTAP_ENCAP_UNKNOWN;
636         for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
637                 if (etherpeek_encap[i].protoNum == protoNum) {
638                         pkt_encap = etherpeek_encap[i].encap;
639                 }
640         }
641
642         switch (pkt_encap) {
643
644         case WTAP_ENCAP_ETHERNET:
645                 /* We assume there's no FCS in this frame. */
646                 pseudo_header->eth.fcs_len = 0;
647                 break;
648         }
649
650         /*
651          * XXX - should "errno" be set in "wtap_file_read_expected_bytes()"?
652          */
653         errno = WTAP_ERR_CANT_READ;
654         wtap_file_read_expected_bytes(pd, length, wth->random_fh, err);
655         return TRUE;
656 }