Coverage Report

Created: 2026-01-02 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/peekclassic.c
Line
Count
Source
1
/* peekclassic.c
2
 * Routines for opening files in what Savvius (formerly WildPackets) calls
3
 * the classic file format in the description of their "PeekRdr Sample
4
 * Application" (C++ source code to read their capture files, downloading
5
 * of which requires a maintenance contract, so it's not free as in beer
6
 * and probably not 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
 * Wiretap Library
19
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
20
 *
21
 * SPDX-License-Identifier: GPL-2.0-or-later
22
 */
23
24
#include "config.h"
25
#include "peekclassic.h"
26
27
#include <string.h>
28
29
#include <wsutil/epochs.h>
30
#include <wsutil/802_11-utils.h>
31
#include <wsutil/ws_assert.h>
32
#include <wsutil/pint.h>
33
34
#include "wtap_module.h"
35
#include "file_wrappers.h"
36
37
/* CREDITS
38
 *
39
 * This file decoder could not have been written without examining how
40
 * tcptrace (http://www.tcptrace.org/) handles EtherPeek files.
41
 */
42
43
/* master header */
44
typedef struct peekclassic_master_header {
45
  uint8_t version;
46
  uint8_t status;
47
} peekclassic_master_header_t;
48
#define PEEKCLASSIC_MASTER_HDR_SIZE 2
49
50
/* secondary header (V5,V6,V7) */
51
typedef struct peekclassic_v567_header {
52
  uint32_t filelength;
53
  uint32_t numPackets;
54
  uint32_t timeDate;
55
  uint32_t timeStart;
56
  uint32_t timeStop;
57
  uint32_t mediaType;  /* Media Type Ethernet=0 Token Ring = 1 */
58
  uint32_t physMedium; /* Physical Medium native=0 802.1=1 */
59
  uint32_t appVers;    /* App Version Number Maj.Min.Bug.Build */
60
  uint32_t linkSpeed;  /* Link Speed Bits/sec */
61
  uint32_t reserved[3];
62
} peekclassic_v567_header_t;
63
#define PEEKCLASSIC_V567_HDR_SIZE 48
64
65
/* full header */
66
typedef struct peekclassic_header {
67
  peekclassic_master_header_t master;
68
  union {
69
    peekclassic_v567_header_t v567;
70
  } secondary;
71
} peekclassic_header_t;
72
73
/*
74
 * Packet header (V5, V6).
75
 *
76
 * NOTE: the time stamp, although it's a 32-bit number, is only aligned
77
 * on a 16-bit boundary.  (Does this date back to 68K Macs?  The 68000
78
 * only required 16-bit alignment of 32-bit quantities, as did the 68010,
79
 * and the 68020/68030/68040 required no alignment.)
80
 *
81
 * As such, we cannot declare this as a C structure, as compilers on
82
 * most platforms will put 2 bytes of padding before the time stamp to
83
 * align it on a 32-bit boundary.
84
 *
85
 * So, instead, we #define numbers as the offsets of the fields.
86
 */
87
0
#define PEEKCLASSIC_V56_LENGTH_OFFSET   0
88
0
#define PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET 2
89
0
#define PEEKCLASSIC_V56_FLAGS_OFFSET    4
90
#define PEEKCLASSIC_V56_STATUS_OFFSET   5
91
0
#define PEEKCLASSIC_V56_TIMESTAMP_OFFSET  6
92
#define PEEKCLASSIC_V56_DESTNUM_OFFSET    10
93
#define PEEKCLASSIC_V56_SRCNUM_OFFSET   12
94
#define PEEKCLASSIC_V56_PROTONUM_OFFSET   14
95
#define PEEKCLASSIC_V56_PROTOSTR_OFFSET   16
96
#define PEEKCLASSIC_V56_FILTERNUM_OFFSET  24
97
#define PEEKCLASSIC_V56_PKT_SIZE    26
98
99
/* 64-bit time in micro seconds from the (Mac) epoch */
100
typedef struct peekclassic_utime {
101
  uint32_t upper;
102
  uint32_t lower;
103
} peekclassic_utime;
104
105
/*
106
 * Packet header (V7).
107
 *
108
 * This doesn't have the same alignment problem, but we do it with
109
 * #defines anyway.
110
 */
111
#define PEEKCLASSIC_V7_PROTONUM_OFFSET    0
112
0
#define PEEKCLASSIC_V7_LENGTH_OFFSET    2
113
0
#define PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET  4
114
0
#define PEEKCLASSIC_V7_FLAGS_OFFSET   6
115
0
#define PEEKCLASSIC_V7_STATUS_OFFSET    7
116
0
#define PEEKCLASSIC_V7_TIMESTAMP_OFFSET   8
117
#define PEEKCLASSIC_V7_PKT_SIZE     16
118
119
/*
120
 * Flag bits.
121
 */
122
#define FLAGS_CONTROL_FRAME 0x01  /* Frame is a control frame */
123
0
#define FLAGS_HAS_CRC_ERROR 0x02  /* Frame has a CRC error */
124
#define FLAGS_HAS_FRAME_ERROR 0x04  /* Frame has a frame error */
125
#define FLAGS_ROUTE_INFO  0x08  /* Frame has token ring routing information */
126
0
#define FLAGS_FRAME_TOO_LONG  0x10  /* Frame too long */
127
0
#define FLAGS_FRAME_TOO_SHORT 0x20  /* Frame too short (runt) */
128
#define FLAGS_TRIGGER   0x40  /* Trigger packet (?) */
129
#define FLAGS_SNAP    0x80  /* SNAP packet (SNAP header?) */
130
131
/*
132
 * Status bits.
133
 */
134
#define STATUS_SELECTED   0x01  /* Selected (in the *Peek GUI?) */
135
#define STATUS_TRUNCATED  0x02  /* Truncated (?) */
136
#define STATUS_APPLEPEEK  0x10  /* ApplePeek packet (?) */
137
#define STATUS_SLICED   0x20  /* Sliced (cut short by snaplen?) */
138
#define STATUS_HIDDEN   0x80  /* Hidden (in the *Peek GUI?) */
139
140
typedef struct {
141
  time_t reference_time;
142
} peekclassic_t;
143
144
static bool peekclassic_read_v7(wtap *wth, wtap_rec *rec,
145
    int *err, char **err_info, int64_t *data_offset);
146
static bool peekclassic_seek_read_v7(wtap *wth, int64_t seek_off,
147
    wtap_rec *rec, int *err, char **err_info);
148
static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh,
149
    wtap_rec *rec, int *err, char **err_info);
150
static bool peekclassic_read_v56(wtap *wth, wtap_rec *rec,
151
    int *err, char **err_info, int64_t *data_offset);
152
static bool peekclassic_seek_read_v56(wtap *wth, int64_t seek_off,
153
    wtap_rec *rec, int *err, char **err_info);
154
static bool peekclassic_read_packet_v56(wtap *wth, FILE_T fh,
155
    wtap_rec *rec, int *err, char **err_info);
156
157
static int peekclassic_v56_file_type_subtype = -1;
158
static int peekclassic_v7_file_type_subtype = -1;
159
160
void register_peekclassic(void);
161
162
wtap_open_return_val peekclassic_open(wtap *wth, int *err, char **err_info)
163
0
{
164
0
  peekclassic_header_t ep_hdr;
165
0
  time_t reference_time;
166
0
  int file_encap;
167
0
  peekclassic_t *peekclassic;
168
169
  /* Peek classic 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
0
  ws_assert(sizeof(ep_hdr.master) == PEEKCLASSIC_MASTER_HDR_SIZE);
178
0
  if (!wtap_read_bytes(wth->fh, &ep_hdr.master,
179
0
      (int)sizeof(ep_hdr.master), err, err_info)) {
180
0
    if (*err != WTAP_ERR_SHORT_READ)
181
0
      return WTAP_OPEN_ERROR;
182
0
    return WTAP_OPEN_NOT_MINE;
183
0
  }
184
185
  /*
186
   * It appears that EtherHelp (a free application from WildPackets
187
   * that did blind capture, saving to a file, so that you could
188
   * give the resulting file to somebody with EtherPeek) saved
189
   * captures in EtherPeek format except that it ORed the 0x80
190
   * bit on in the version number.
191
   *
192
   * We therefore strip off the 0x80 bit in the version number.
193
   * Perhaps there's some reason to care whether the capture
194
   * came from EtherHelp; if we discover one, we should check
195
   * that bit.
196
   */
197
0
  ep_hdr.master.version &= ~0x80;
198
199
  /* switch on the file version */
200
0
  switch (ep_hdr.master.version) {
201
202
0
  case 5:
203
0
  case 6:
204
0
  case 7:
205
    /* get the secondary header */
206
0
    ws_assert(sizeof(ep_hdr.secondary.v567) ==
207
0
            PEEKCLASSIC_V567_HDR_SIZE);
208
0
    if (!wtap_read_bytes(wth->fh, &ep_hdr.secondary.v567,
209
0
        (int)sizeof(ep_hdr.secondary.v567), err, err_info)) {
210
0
      if (*err != WTAP_ERR_SHORT_READ)
211
0
        return WTAP_OPEN_ERROR;
212
0
      return WTAP_OPEN_NOT_MINE;
213
0
    }
214
215
0
    if ((0 != ep_hdr.secondary.v567.reserved[0]) ||
216
0
        (0 != ep_hdr.secondary.v567.reserved[1]) ||
217
0
        (0 != ep_hdr.secondary.v567.reserved[2])) {
218
      /* still unknown */
219
0
      return WTAP_OPEN_NOT_MINE;
220
0
    }
221
222
    /*
223
     * Check the mediaType and physMedium fields.
224
     * We assume it's not a Peek classic file if
225
     * these aren't values we know, rather than
226
     * reporting them as invalid Peek classic files,
227
     * as, given the lack of a magic number, we need
228
     * all the checks we can get.
229
     */
230
0
    ep_hdr.secondary.v567.mediaType =
231
0
        g_ntohl(ep_hdr.secondary.v567.mediaType);
232
0
    ep_hdr.secondary.v567.physMedium =
233
0
        g_ntohl(ep_hdr.secondary.v567.physMedium);
234
235
0
    switch (ep_hdr.secondary.v567.physMedium) {
236
237
0
    case 0:
238
      /*
239
       * "Native" format, presumably meaning
240
       * Ethernet or Token Ring.
241
       */
242
0
      switch (ep_hdr.secondary.v567.mediaType) {
243
244
0
      case 0:
245
0
        file_encap = WTAP_ENCAP_ETHERNET;
246
0
        break;
247
248
0
      case 1:
249
0
        file_encap = WTAP_ENCAP_TOKEN_RING;
250
0
        break;
251
252
0
      default:
253
        /*
254
         * Assume this isn't a Peek classic file.
255
         */
256
0
        return WTAP_OPEN_NOT_MINE;
257
0
      }
258
0
      break;
259
260
0
    case 1:
261
0
      switch (ep_hdr.secondary.v567.mediaType) {
262
263
0
      case 0:
264
        /*
265
         * 802.11, with a private header giving
266
         * some radio information.  Presumably
267
         * this is from AiroPeek.
268
         */
269
0
        file_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
270
0
        break;
271
272
0
      default:
273
        /*
274
         * Assume this isn't a Peek classic file.
275
         */
276
0
        return WTAP_OPEN_NOT_MINE;
277
0
      }
278
0
      break;
279
280
0
    default:
281
      /*
282
       * Assume this isn't a Peek classic file.
283
       */
284
0
      return WTAP_OPEN_NOT_MINE;
285
0
    }
286
287
288
    /*
289
     * Assume this is a V5, V6 or V7 Peek classic file, and
290
     * byte 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
0
    ep_hdr.secondary.v567.filelength =
296
0
        g_ntohl(ep_hdr.secondary.v567.filelength);
297
0
    ep_hdr.secondary.v567.numPackets =
298
0
        g_ntohl(ep_hdr.secondary.v567.numPackets);
299
0
    ep_hdr.secondary.v567.timeDate =
300
0
        g_ntohl(ep_hdr.secondary.v567.timeDate);
301
0
    ep_hdr.secondary.v567.timeStart =
302
0
        g_ntohl(ep_hdr.secondary.v567.timeStart);
303
0
    ep_hdr.secondary.v567.timeStop =
304
0
        g_ntohl(ep_hdr.secondary.v567.timeStop);
305
0
    ep_hdr.secondary.v567.appVers =
306
0
        g_ntohl(ep_hdr.secondary.v567.appVers);
307
0
    ep_hdr.secondary.v567.linkSpeed =
308
0
        g_ntohl(ep_hdr.secondary.v567.linkSpeed);
309
310
    /* Get the reference time as a time_t */
311
0
    reference_time = ep_hdr.secondary.v567.timeDate - EPOCH_DELTA_1904_01_01_00_00_00_UTC;
312
0
    break;
313
314
0
  default:
315
    /*
316
     * Assume this isn't a Peek classic file.
317
     */
318
0
    return WTAP_OPEN_NOT_MINE;
319
0
  }
320
321
  /*
322
   * This is a Peek classic file.
323
   *
324
   * At this point we have recognised the file type and have populated
325
   * the whole ep_hdr structure in host byte order.
326
   */
327
0
  peekclassic = g_new(peekclassic_t, 1);
328
0
  wth->priv = (void *)peekclassic;
329
0
  peekclassic->reference_time = reference_time;
330
0
  wth->file_encap = file_encap;
331
0
  switch (ep_hdr.master.version) {
332
333
0
  case 5:
334
0
  case 6:
335
0
    wth->file_type_subtype = peekclassic_v56_file_type_subtype;
336
0
    wth->subtype_read = peekclassic_read_v56;
337
0
    wth->subtype_seek_read = peekclassic_seek_read_v56;
338
0
    break;
339
340
0
  case 7:
341
0
    wth->file_type_subtype = peekclassic_v7_file_type_subtype;
342
0
    wth->subtype_read = peekclassic_read_v7;
343
0
    wth->subtype_seek_read = peekclassic_seek_read_v7;
344
0
    break;
345
346
0
  default:
347
    /* this is impossible */
348
0
    ws_assert_not_reached();
349
0
  }
350
351
0
  wth->snapshot_length   = 0; /* not available in header */
352
0
  wth->file_tsprec = WTAP_TSPREC_USEC;
353
354
  /*
355
   * Add an IDB; we don't know how many interfaces were
356
   * involved, so we just say one interface, about which
357
   * we only know the link-layer type, snapshot length,
358
   * and time stamp resolution.
359
   */
360
0
  wtap_add_generated_idb(wth);
361
362
0
  return WTAP_OPEN_MINE;
363
0
}
364
365
static bool peekclassic_read_v7(wtap *wth, wtap_rec *rec,
366
    int *err, char **err_info, int64_t *data_offset)
367
0
{
368
0
  int sliceLength;
369
370
0
  *data_offset = file_tell(wth->fh);
371
372
  /* Read the packet. */
373
0
  sliceLength = peekclassic_read_packet_v7(wth, wth->fh, rec, err,
374
0
      err_info);
375
0
  if (sliceLength < 0)
376
0
    return false;
377
378
  /* Skip extra ignored data at the end of the packet. */
379
0
  if ((uint32_t)sliceLength > rec->rec_header.packet_header.caplen) {
380
0
    if (!wtap_read_bytes(wth->fh, NULL, sliceLength - rec->rec_header.packet_header.caplen,
381
0
        err, err_info))
382
0
      return false;
383
0
  }
384
385
  /* Records are padded to an even length, so if the slice length
386
     is odd, read the padding byte. */
387
0
  if (sliceLength & 0x01) {
388
0
    if (!wtap_read_bytes(wth->fh, NULL, 1, err, err_info))
389
0
      return false;
390
0
  }
391
392
0
  return true;
393
0
}
394
395
static bool peekclassic_seek_read_v7(wtap *wth, int64_t seek_off,
396
    wtap_rec *rec, int *err, char **err_info)
397
0
{
398
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
399
0
    return false;
400
401
  /* Read the packet. */
402
0
  if (peekclassic_read_packet_v7(wth, wth->random_fh, rec, err,
403
0
      err_info) == -1) {
404
0
    if (*err == 0)
405
0
      *err = WTAP_ERR_SHORT_READ;
406
0
    return false;
407
0
  }
408
0
  return true;
409
0
}
410
411
0
#define RADIO_INFO_SIZE 4
412
413
static int peekclassic_read_packet_v7(wtap *wth, FILE_T fh, wtap_rec *rec,
414
    int *err, char **err_info)
415
0
{
416
0
  uint8_t ep_pkt[PEEKCLASSIC_V7_PKT_SIZE];
417
#if 0
418
  uint16_t protoNum;
419
#endif
420
0
  uint16_t length;
421
0
  uint16_t sliceLength;
422
0
  uint8_t flags;
423
0
  uint8_t status;
424
0
  uint64_t timestamp;
425
0
  time_t tsecs;
426
0
  uint32_t tusecs;
427
0
  uint32_t pack_flags;
428
0
  uint8_t radio_info[RADIO_INFO_SIZE];
429
430
0
  if (!wtap_read_bytes_or_eof(fh, ep_pkt, sizeof(ep_pkt), err, err_info))
431
0
    return -1;
432
433
  /* Extract the fields from the packet */
434
#if 0
435
  protoNum = pntohu16(&ep_pkt[PEEKCLASSIC_V7_PROTONUM_OFFSET]);
436
#endif
437
0
  length = pntohu16(&ep_pkt[PEEKCLASSIC_V7_LENGTH_OFFSET]);
438
0
  sliceLength = pntohu16(&ep_pkt[PEEKCLASSIC_V7_SLICE_LENGTH_OFFSET]);
439
0
  flags = ep_pkt[PEEKCLASSIC_V7_FLAGS_OFFSET];
440
0
  status = ep_pkt[PEEKCLASSIC_V7_STATUS_OFFSET];
441
0
  timestamp = pntohu64(&ep_pkt[PEEKCLASSIC_V7_TIMESTAMP_OFFSET]);
442
443
  /* force sliceLength to be the actual length of the packet */
444
0
  if (0 == sliceLength) {
445
0
    sliceLength = length;
446
0
  }
447
  /*
448
   * The maximum value of sliceLength and length are 65535, which
449
   * are less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't
450
   * need to check them.
451
   */
452
453
  /* fill in packet header values */
454
0
  wtap_setup_packet_rec(rec, wth->file_encap);
455
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
456
0
  rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
457
0
  tsecs = (time_t) (timestamp/1000000);
458
0
  tusecs = (uint32_t) (timestamp - tsecs*1000000);
459
0
  rec->ts.secs  = tsecs - EPOCH_DELTA_1904_01_01_00_00_00_UTC;
460
0
  rec->ts.nsecs = tusecs * 1000;
461
0
  rec->rec_header.packet_header.len    = length;
462
0
  rec->rec_header.packet_header.caplen = sliceLength;
463
0
  pack_flags = 0;
464
0
  if (flags & FLAGS_HAS_CRC_ERROR)
465
0
    pack_flags |= PACK_FLAGS_CRC_ERROR;
466
0
  if (flags & FLAGS_FRAME_TOO_LONG)
467
0
    pack_flags |= PACK_FLAGS_PACKET_TOO_LONG;
468
0
  if (flags & FLAGS_FRAME_TOO_SHORT)
469
0
    pack_flags |= PACK_FLAGS_PACKET_TOO_SHORT;
470
0
  wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, pack_flags);
471
472
0
  switch (wth->file_encap) {
473
474
0
  case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
475
0
    memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
476
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = 0;    /* no FCS */
477
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = false;
478
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = false;
479
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
480
481
    /*
482
     * Now process the radio information pseudo-header.
483
     * It's a 4-byte pseudo-header, consisting of:
484
     *
485
     *   1 byte of data rate, in units of 500 kb/s;
486
     *
487
     *   1 byte of channel number;
488
     *
489
     *   1 byte of signal strength as a percentage of
490
     *   the maximum, i.e. (RXVECTOR RSSI/RXVECTOR RSSI_Max)*100,
491
     *   or, at least, that's what I infer it is, given what
492
     *   the WildPackets note "Converting Signal Strength
493
     *   Percentage to dBm Values" says (it also says that
494
     *   the conversion the percentage to a dBm value is
495
     *   an adapter-dependent process, so, as we don't know
496
     *   what type of adapter was used to do the capture,
497
     *   we can't do the conversion);
498
     *
499
     *   1 byte of unknown content (padding?).
500
     */
501
0
    if (rec->rec_header.packet_header.len < RADIO_INFO_SIZE || rec->rec_header.packet_header.caplen < RADIO_INFO_SIZE) {
502
0
      *err = WTAP_ERR_BAD_FILE;
503
0
      *err_info = ws_strdup_printf("peekclassic: 802.11 packet has length < 4");
504
0
      return -1;
505
0
    }
506
0
    rec->rec_header.packet_header.len -= RADIO_INFO_SIZE;
507
0
    rec->rec_header.packet_header.caplen -= RADIO_INFO_SIZE;
508
0
    sliceLength -= RADIO_INFO_SIZE;
509
510
    /* read the pseudo-header */
511
0
    if (!wtap_read_bytes(fh, radio_info, RADIO_INFO_SIZE, err, err_info))
512
0
      return -1;
513
514
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = true;
515
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate = radio_info[0];
516
517
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = true;
518
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = radio_info[1];
519
520
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = true;
521
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = radio_info[2];
522
523
    /*
524
     * We don't know they PHY, but we do have the data rate;
525
     * try to guess it based on the data rate and channel.
526
     */
527
0
    if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
528
      /* 11b */
529
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
530
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
531
0
    } else if (RATE_IS_OFDM(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
532
      /* 11a or 11g, depending on the band. */
533
0
      if (CHAN_IS_BG(rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel)) {
534
        /* 11g */
535
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
536
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = false;
537
0
      } else {
538
        /* 11a */
539
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
540
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_channel_type = false;
541
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = false;
542
0
      }
543
0
    }
544
545
    /*
546
     * The last 4 bytes appear to be random data - the length
547
     * might include the FCS - so we reduce the length by 4.
548
     *
549
     * Or maybe this is just the same kind of random 4 bytes
550
     * of junk at the end you get in Wireless Sniffer
551
     * captures.
552
     */
553
0
    if (rec->rec_header.packet_header.len < 4 || rec->rec_header.packet_header.caplen < 4) {
554
0
      *err = WTAP_ERR_BAD_FILE;
555
0
      *err_info = ws_strdup_printf("peekclassic: 802.11 packet has length < 8");
556
0
      return -1;
557
0
    }
558
0
    rec->rec_header.packet_header.len -= 4;
559
0
    rec->rec_header.packet_header.caplen -= 4;
560
0
    break;
561
562
0
  case WTAP_ENCAP_ETHERNET:
563
    /* XXX - it appears that if the low-order bit of
564
       "status" is 0, there's an FCS in this frame,
565
       and if it's 1, there's 4 bytes of 0. */
566
0
    rec->rec_header.packet_header.pseudo_header.eth.fcs_len = (status & 0x01) ? 0 : 4;
567
0
    break;
568
0
  }
569
570
  /* read the packet data */
571
0
  if (!wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info))
572
0
    return -1;
573
574
0
  return sliceLength;
575
0
}
576
577
static bool peekclassic_read_v56(wtap *wth, wtap_rec *rec,
578
    int *err, char **err_info, int64_t *data_offset)
579
0
{
580
0
  *data_offset = file_tell(wth->fh);
581
582
  /* read the packet */
583
0
  if (!peekclassic_read_packet_v56(wth, wth->fh, rec, err, err_info))
584
0
    return false;
585
586
  /*
587
   * XXX - is the captured packet data padded to a multiple
588
   * of 2 bytes?
589
   */
590
0
  return true;
591
0
}
592
593
static bool peekclassic_seek_read_v56(wtap *wth, int64_t seek_off,
594
    wtap_rec *rec, int *err, char **err_info)
595
0
{
596
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
597
0
    return false;
598
599
  /* read the packet */
600
0
  if (!peekclassic_read_packet_v56(wth, wth->random_fh, rec, err,
601
0
      err_info)) {
602
0
    if (*err == 0)
603
0
      *err = WTAP_ERR_SHORT_READ;
604
0
    return false;
605
0
  }
606
0
  return true;
607
0
}
608
609
static bool peekclassic_read_packet_v56(wtap *wth, FILE_T fh, wtap_rec *rec,
610
    int *err, char **err_info)
611
0
{
612
0
  peekclassic_t *peekclassic = (peekclassic_t *)wth->priv;
613
0
  uint8_t ep_pkt[PEEKCLASSIC_V56_PKT_SIZE];
614
0
  uint16_t length;
615
0
  uint16_t sliceLength;
616
0
  uint8_t flags;
617
#if 0
618
  uint8_t status;
619
#endif
620
0
  uint32_t timestamp;
621
#if 0
622
  uint16_t destNum;
623
  uint16_t srcNum;
624
#endif
625
#if 0
626
  uint16_t protoNum;
627
  char    protoStr[8];
628
#endif
629
0
  uint32_t pack_flags;
630
631
0
  if (!wtap_read_bytes_or_eof(fh, ep_pkt, sizeof(ep_pkt), err, err_info))
632
0
    return false;
633
634
  /* Extract the fields from the packet */
635
0
  length = pntohu16(&ep_pkt[PEEKCLASSIC_V56_LENGTH_OFFSET]);
636
0
  sliceLength = pntohu16(&ep_pkt[PEEKCLASSIC_V56_SLICE_LENGTH_OFFSET]);
637
0
  flags = ep_pkt[PEEKCLASSIC_V56_FLAGS_OFFSET];
638
#if 0
639
  status = ep_pkt[PEEKCLASSIC_V56_STATUS_OFFSET];
640
#endif
641
0
  timestamp = pntohu32(&ep_pkt[PEEKCLASSIC_V56_TIMESTAMP_OFFSET]);
642
#if 0
643
  destNum = pntohu16(&ep_pkt[PEEKCLASSIC_V56_DESTNUM_OFFSET]);
644
  srcNum = pntohu16(&ep_pkt[PEEKCLASSIC_V56_SRCNUM_OFFSET]);
645
  protoNum = pntohu16(&ep_pkt[PEEKCLASSIC_V56_PROTONUM_OFFSET]);
646
  memcpy(protoStr, &ep_pkt[PEEKCLASSIC_V56_PROTOSTR_OFFSET],
647
      sizeof protoStr);
648
#endif
649
650
  /*
651
   * XXX - is the captured packet data padded to a multiple
652
   * of 2 bytes?
653
   */
654
655
  /* force sliceLength to be the actual length of the packet */
656
0
  if (0 == sliceLength) {
657
0
    sliceLength = length;
658
0
  }
659
  /*
660
   * The maximum value of sliceLength and length are 65535, which
661
   * are less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't
662
   * need to check them.
663
   */
664
665
  /* fill in packet header values */
666
0
  wtap_setup_packet_rec(rec, wth->file_encap);
667
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
668
0
  rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
669
  /* timestamp is in milliseconds since reference_time */
670
0
  rec->ts.secs  = peekclassic->reference_time + (timestamp / 1000);
671
0
  rec->ts.nsecs = 1000 * (timestamp % 1000) * 1000;
672
0
  rec->rec_header.packet_header.len      = length;
673
0
  rec->rec_header.packet_header.caplen   = sliceLength;
674
0
  pack_flags = 0;
675
0
  if (flags & FLAGS_HAS_CRC_ERROR)
676
0
    pack_flags |= PACK_FLAGS_CRC_ERROR;
677
0
  if (flags & FLAGS_FRAME_TOO_LONG)
678
0
    pack_flags |= PACK_FLAGS_PACKET_TOO_LONG;
679
0
  if (flags & FLAGS_FRAME_TOO_SHORT)
680
0
    pack_flags |= PACK_FLAGS_PACKET_TOO_SHORT;
681
0
  wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, pack_flags);
682
683
0
  switch (wth->file_encap) {
684
685
0
  case WTAP_ENCAP_ETHERNET:
686
    /* We assume there's no FCS in this frame. */
687
0
    rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
688
0
    break;
689
0
  }
690
691
  /* read the packet data */
692
0
  return wtap_read_bytes_buffer(fh, &rec->data, sliceLength, err, err_info);
693
0
}
694
695
static const struct supported_block_type peekclassic_v56_blocks_supported[] = {
696
  /*
697
   * We support packet blocks, with no comments or other options.
698
   */
699
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
700
};
701
702
static const struct file_type_subtype_info peekclassic_v56_info = {
703
  "Savvius classic (V5 and V6)", "peekclassic56", "pkt", "tpc;apc;wpz",
704
  false, BLOCKS_SUPPORTED(peekclassic_v56_blocks_supported),
705
  NULL, NULL, NULL
706
};
707
708
static const struct supported_block_type peekclassic_v7_blocks_supported[] = {
709
  /*
710
   * We support packet blocks, with no comments or other options.
711
   */
712
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
713
};
714
715
static const struct file_type_subtype_info peekclassic_v7_info = {
716
  "Savvius classic (V7)", "peekclassic7", "pkt", "tpc;apc;wpz",
717
  false, BLOCKS_SUPPORTED(peekclassic_v7_blocks_supported),
718
  NULL, NULL, NULL
719
};
720
721
void register_peekclassic(void)
722
14
{
723
14
  peekclassic_v56_file_type_subtype = wtap_register_file_type_subtype(&peekclassic_v56_info);
724
14
  peekclassic_v7_file_type_subtype = wtap_register_file_type_subtype(&peekclassic_v7_info);
725
726
  /*
727
   * Register names for backwards compatibility with the
728
   * wtap_filetypes table in Lua.
729
   */
730
14
  wtap_register_backwards_compatibility_lua_name("PEEKCLASSIC_V56",
731
14
      peekclassic_v56_file_type_subtype);
732
14
  wtap_register_backwards_compatibility_lua_name("PEEKCLASSIC_V7",
733
14
      peekclassic_v7_file_type_subtype);
734
14
}
735
736
/*
737
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
738
 *
739
 * Local variables:
740
 * c-basic-offset: 8
741
 * tab-width: 8
742
 * indent-tabs-mode: t
743
 * End:
744
 *
745
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
746
 * :indentSize=8:tabSize=8:noTabs=false:
747
 */