Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/commview.c
Line
Count
Source
1
/* commview.c
2
 * Routines for opening CommView NCF and NCFX file format packet captures
3
 * Copyright 2007, Stephen Fisher (see AUTHORS file)
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * Based on csids.c and nettl.c
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
/* A brief description of these file formats is available at:
15
 *    https://www.tamos.com/htmlhelp/commview/logformat.htm
16
 *    https://www.tamos.com/htmlhelp/commwifi/logformat.htm
17
 *
18
 * Use
19
 *
20
 *    https://web.archive.org/web/20171022225753/http://www.tamos.com/htmlhelp/commview/logformat.htm
21
 *
22
 * if that doesn't display anything.
23
 */
24
25
#include "config.h"
26
#include "commview.h"
27
28
#include <stdlib.h>
29
#include <string.h>
30
31
#include "wtap_module.h"
32
#include "file_wrappers.h"
33
34
#include <wsutil/802_11-utils.h>
35
36
/*
37
 * Capture medium types used in NCF and NCFX;
38
 * Token Ring isn't used in NCFX.
39
 */
40
0
#define MEDIUM_ETHERNET   0
41
0
#define MEDIUM_WIFI   1
42
0
#define MEDIUM_TOKEN_RING 2
43
44
typedef struct commview_ncf_header {
45
  uint16_t  data_len;
46
  uint16_t  source_data_len;
47
  uint8_t   version;
48
  uint16_t  year;
49
  uint8_t   month;
50
  uint8_t   day;
51
  uint8_t   hours;
52
  uint8_t   minutes;
53
  uint8_t   seconds;
54
  uint32_t  usecs;
55
  uint8_t   flags;    /* Bit-field positions defined below */
56
  uint8_t   signal_level_percent;
57
  uint8_t   rate;
58
  uint8_t   band;
59
  uint8_t   channel;
60
  uint8_t   direction;  /* Or for WiFi, high order byte of
61
           * packet rate. */
62
  int8_t    signal_level_dbm; /* WiFi-only */
63
  int8_t    noise_level_dbm;  /* WiFi-only */
64
} commview_ncf_header_t;
65
66
#define COMMVIEW_NCF_HEADER_SIZE 24
67
68
/* Bit-field positions for various fields in the flags variable of the header */
69
0
#define FLAGS_MEDIUM    0x0F
70
#define FLAGS_DECRYPTED   0x10
71
#define FLAGS_BROKEN    0x20
72
#define FLAGS_COMPRESSED  0x40
73
0
#define FLAGS_RESERVED    0x80
74
75
/* Values for the band variable of the header */
76
0
#define BAND_11A    0x01
77
0
#define BAND_11B    0x02
78
0
#define BAND_11G    0x04
79
0
#define BAND_11A_TURBO    0x08
80
0
#define BAND_SUPERG   0x10
81
0
#define BAND_PUBLIC_SAFETY  0x20  /* 4.99 GHz public safety */
82
0
#define BAND_11N_5GHZ   0x40
83
0
#define BAND_11N_2_4GHZ   0x80
84
85
static bool commview_ncf_read(wtap *wth, wtap_rec *rec,
86
                              int *err, char **err_info, int64_t *data_offset);
87
static bool commview_ncf_seek_read(wtap *wth, int64_t seek_off,
88
           wtap_rec *rec,
89
           int *err, char **err_info);
90
static bool commview_ncf_read_header(commview_ncf_header_t *cv_hdr, FILE_T fh,
91
             int *err, char **err_info);
92
static bool commview_ncf_dump(wtap_dumper *wdh, const wtap_rec *rec,
93
            int *err, char **err_info);
94
95
static int commview_ncf_file_type_subtype = -1;
96
static int commview_ncfx_file_type_subtype = -1;
97
98
void register_commview(void);
99
100
wtap_open_return_val
101
commview_ncf_open(wtap *wth, int *err, char **err_info)
102
0
{
103
0
  commview_ncf_header_t cv_hdr;
104
105
0
  if(!commview_ncf_read_header(&cv_hdr, wth->fh, err, err_info)) {
106
0
    if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
107
0
      return WTAP_OPEN_ERROR;
108
0
    return WTAP_OPEN_NOT_MINE;
109
0
  }
110
111
  /* If any of these fields do not match what we expect, bail out. */
112
0
  if(cv_hdr.version != 0 ||
113
0
     cv_hdr.year < 1970 || cv_hdr.year >= 2038 ||
114
0
     cv_hdr.month < 1 || cv_hdr.month > 12 ||
115
0
     cv_hdr.day < 1 || cv_hdr.day > 31 ||
116
0
     cv_hdr.hours > 23 ||
117
0
     cv_hdr.minutes > 59 ||
118
0
     cv_hdr.seconds > 60 ||
119
0
     cv_hdr.signal_level_percent > 100 ||
120
0
     (cv_hdr.flags & FLAGS_RESERVED) != 0 ||
121
0
     ((cv_hdr.flags & FLAGS_MEDIUM) != MEDIUM_ETHERNET &&
122
0
      (cv_hdr.flags & FLAGS_MEDIUM) != MEDIUM_WIFI &&
123
0
      (cv_hdr.flags & FLAGS_MEDIUM) != MEDIUM_TOKEN_RING))
124
0
    return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
125
126
  /* No file header. Reset the fh to 0 so we can read the first packet */
127
0
  if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
128
0
    return WTAP_OPEN_ERROR;
129
130
  /* Set up the pointers to the handlers for this file type */
131
0
  wth->subtype_read = commview_ncf_read;
132
0
  wth->subtype_seek_read = commview_ncf_seek_read;
133
134
0
  wth->file_type_subtype = commview_ncf_file_type_subtype;
135
0
  wth->file_encap = WTAP_ENCAP_PER_PACKET;
136
0
  wth->file_tsprec = WTAP_TSPREC_USEC;
137
138
0
  return WTAP_OPEN_MINE; /* Our kind of file */
139
0
}
140
141
static int
142
commview_ncf_read_packet(FILE_T fh, wtap_rec *rec,
143
    int *err, char **err_info)
144
0
{
145
0
  commview_ncf_header_t cv_hdr;
146
0
  struct tm tm;
147
0
  unsigned frequency;
148
149
0
  if(!commview_ncf_read_header(&cv_hdr, fh, err, err_info))
150
0
    return false;
151
152
0
  wtap_setup_packet_rec(rec, WTAP_ENCAP_UNKNOWN);
153
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
154
155
  /*
156
   * The maximum value of cv_hdr.data_len is 65535, which is less
157
   * than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to
158
   * check it.
159
   */
160
161
0
  switch(cv_hdr.flags & FLAGS_MEDIUM) {
162
163
0
  case MEDIUM_ETHERNET :
164
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETHERNET;
165
0
    rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1; /* Unknown */
166
0
    break;
167
168
0
  case MEDIUM_WIFI :
169
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
170
0
    memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
171
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = -1; /* Unknown */
172
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = false;
173
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = false;
174
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
175
0
    switch (cv_hdr.band) {
176
177
0
    case BAND_11A:
178
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
179
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_channel_type = false;
180
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = true;
181
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.turbo_type =
182
0
          PHDR_802_11A_TURBO_TYPE_NORMAL;
183
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, false);
184
0
      break;
185
186
0
    case BAND_11B:
187
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
188
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
189
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
190
0
      break;
191
192
0
    case BAND_11G:
193
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
194
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = true;
195
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.mode =
196
0
          PHDR_802_11G_MODE_NORMAL;
197
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
198
0
      break;
199
200
0
    case BAND_11A_TURBO:
201
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
202
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = true;
203
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.turbo_type =
204
0
          PHDR_802_11A_TURBO_TYPE_TURBO;
205
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, false);
206
0
      break;
207
208
0
    case BAND_SUPERG:
209
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
210
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = true;
211
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.mode =
212
0
          PHDR_802_11G_MODE_SUPER_G;
213
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
214
0
      break;
215
216
0
    case BAND_11N_5GHZ:
217
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11N;
218
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, false);
219
0
      break;
220
221
0
    case BAND_11N_2_4GHZ:
222
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11N;
223
0
      frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
224
0
      break;
225
226
0
    case BAND_PUBLIC_SAFETY:
227
      /*
228
       * XXX - what do we do here?  What are the channel
229
       * numbers?  How do we distinguish the several
230
       * different flavors of 4.9 GHz frequencies?
231
       */
232
0
      frequency = 0;
233
0
      break;
234
235
0
    default:
236
0
      frequency = 0;
237
0
      break;
238
0
    }
239
0
    if (frequency != 0) {
240
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency = true;
241
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency = frequency;
242
0
    }
243
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = true;
244
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = cv_hdr.channel;
245
246
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = true;
247
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate =
248
0
        cv_hdr.rate | (cv_hdr.direction << 8);
249
250
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = true;
251
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = cv_hdr.signal_level_percent;
252
253
    /*
254
     * XXX - these are positive in captures I've seen; does
255
     * that mean that they are the negative of the actual
256
     * dBm value?  (80 dBm is a bit more power than most
257
     * countries' regulatory agencies are likely to allow
258
     * any individual to have in their home. :-))
259
     *
260
     * XXX - sometimes these are 0; assume that means that no
261
     * value is provided.
262
     */
263
0
    if (cv_hdr.signal_level_dbm != 0) {
264
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm = -cv_hdr.signal_level_dbm;
265
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm = true;
266
0
    }
267
0
    if (cv_hdr.noise_level_dbm != 0) {
268
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm = -cv_hdr.noise_level_dbm;
269
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm = true;
270
0
    }
271
0
    if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_UNKNOWN) {
272
      /*
273
       * We don't know they PHY, but we do have the
274
       * data rate; try to guess it based on the
275
       * data rate and center frequency.
276
       */
277
0
      if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
278
        /* 11b */
279
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
280
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
281
0
      } else if (RATE_IS_OFDM(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
282
        /* 11a or 11g, depending on the band. */
283
0
        if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency) {
284
0
          if (FREQ_IS_BG(rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency)) {
285
            /* 11g */
286
0
            rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
287
0
          } else {
288
            /* 11a */
289
0
            rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
290
0
          }
291
0
        }
292
0
      }
293
0
    } else if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_11G) {
294
0
      if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
295
        /* DSSS, so 11b. */
296
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
297
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
298
0
      }
299
0
    }
300
0
    break;
301
302
0
  case MEDIUM_TOKEN_RING :
303
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_TOKEN_RING;
304
0
    break;
305
306
0
  default :
307
0
    *err = WTAP_ERR_BAD_FILE;
308
0
    *err_info = ws_strdup_printf("commview: unsupported encap for NCF: %u",
309
0
              cv_hdr.flags & FLAGS_MEDIUM);
310
0
    return false;
311
0
  }
312
313
0
  tm.tm_year = cv_hdr.year - 1900;
314
0
  tm.tm_mon = cv_hdr.month - 1;
315
0
  tm.tm_mday = cv_hdr.day;
316
0
  tm.tm_hour = cv_hdr.hours;
317
0
  tm.tm_min = cv_hdr.minutes;
318
0
  tm.tm_sec = cv_hdr.seconds;
319
0
  tm.tm_isdst = -1;
320
321
0
  rec->presence_flags = WTAP_HAS_TS;
322
323
0
  rec->rec_header.packet_header.len = cv_hdr.data_len;
324
0
  rec->rec_header.packet_header.caplen = cv_hdr.data_len;
325
326
0
  rec->ts.secs = mktime(&tm);
327
0
  rec->ts.nsecs = cv_hdr.usecs * 1000;
328
329
0
  return wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info);
330
0
}
331
332
static bool
333
commview_ncf_read(wtap *wth, wtap_rec *rec, int *err,
334
    char **err_info, int64_t *data_offset)
335
0
{
336
0
  *data_offset = file_tell(wth->fh);
337
338
0
  return commview_ncf_read_packet(wth->fh, rec, err, err_info);
339
0
}
340
341
static bool
342
commview_ncf_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
343
    int *err, char **err_info)
344
0
{
345
0
  if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
346
0
    return false;
347
348
0
  return commview_ncf_read_packet(wth->random_fh, rec, err, err_info);
349
0
}
350
351
static bool
352
commview_ncf_read_header(commview_ncf_header_t *cv_hdr, FILE_T fh, int *err,
353
    char **err_info)
354
0
{
355
0
  if (!wtap_read_bytes_or_eof(fh, &cv_hdr->data_len, 2, err, err_info))
356
0
    return false;
357
0
  if (!wtap_read_bytes(fh, &cv_hdr->source_data_len, 2, err, err_info))
358
0
    return false;
359
0
  if (!wtap_read_bytes(fh, &cv_hdr->version, 1, err, err_info))
360
0
    return false;
361
0
  if (!wtap_read_bytes(fh, &cv_hdr->year, 2, err, err_info))
362
0
    return false;
363
0
  if (!wtap_read_bytes(fh, &cv_hdr->month, 1, err, err_info))
364
0
    return false;
365
0
  if (!wtap_read_bytes(fh, &cv_hdr->day, 1, err, err_info))
366
0
    return false;
367
0
  if (!wtap_read_bytes(fh, &cv_hdr->hours, 1, err, err_info))
368
0
    return false;
369
0
  if (!wtap_read_bytes(fh, &cv_hdr->minutes, 1, err, err_info))
370
0
    return false;
371
0
  if (!wtap_read_bytes(fh, &cv_hdr->seconds, 1, err, err_info))
372
0
    return false;
373
0
  if (!wtap_read_bytes(fh, &cv_hdr->usecs, 4, err, err_info))
374
0
    return false;
375
0
  if (!wtap_read_bytes(fh, &cv_hdr->flags, 1, err, err_info))
376
0
    return false;
377
0
  if (!wtap_read_bytes(fh, &cv_hdr->signal_level_percent, 1, err, err_info))
378
0
    return false;
379
0
  if (!wtap_read_bytes(fh, &cv_hdr->rate, 1, err, err_info))
380
0
    return false;
381
0
  if (!wtap_read_bytes(fh, &cv_hdr->band, 1, err, err_info))
382
0
    return false;
383
0
  if (!wtap_read_bytes(fh, &cv_hdr->channel, 1, err, err_info))
384
0
    return false;
385
0
  if (!wtap_read_bytes(fh, &cv_hdr->direction, 1, err, err_info))
386
0
    return false;
387
0
  if (!wtap_read_bytes(fh, &cv_hdr->signal_level_dbm, 1, err, err_info))
388
0
    return false;
389
0
  if (!wtap_read_bytes(fh, &cv_hdr->noise_level_dbm, 1, err, err_info))
390
0
    return false;
391
392
  /* Convert multi-byte values from little endian to host endian format */
393
0
  cv_hdr->data_len = GUINT16_FROM_LE(cv_hdr->data_len);
394
0
  cv_hdr->source_data_len = GUINT16_FROM_LE(cv_hdr->source_data_len);
395
0
  cv_hdr->year = GUINT16_FROM_LE(cv_hdr->year);
396
0
  cv_hdr->usecs = GUINT32_FROM_LE(cv_hdr->usecs);
397
398
0
  return true;
399
0
}
400
401
/* Returns 0 if we can write out the specified encapsulation type
402
 * into a CommView format file. */
403
static int
404
commview_ncf_dump_can_write_encap(int encap)
405
0
{
406
0
  switch (encap) {
407
408
0
  case WTAP_ENCAP_ETHERNET :
409
0
  case WTAP_ENCAP_IEEE_802_11 :
410
0
  case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
411
0
  case WTAP_ENCAP_TOKEN_RING :
412
0
  case WTAP_ENCAP_PER_PACKET :
413
0
    return 0;
414
415
0
  default:
416
0
    return WTAP_ERR_UNWRITABLE_ENCAP;
417
0
  }
418
0
}
419
420
/* Returns true on success, false on failure;
421
   sets "*err" to an error code on failure */
422
static bool
423
commview_ncf_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_)
424
0
{
425
0
  wdh->subtype_write = commview_ncf_dump;
426
427
  /* There is no file header to write out */
428
0
  return true;
429
0
}
430
431
/* Write a record for a packet to a dump file.
432
 * Returns true on success, false on failure. */
433
static bool
434
commview_ncf_dump(wtap_dumper *wdh, const wtap_rec *rec,
435
    int *err, char **err_info _U_)
436
0
{
437
0
  commview_ncf_header_t cv_hdr = {0};
438
0
  struct tm *tm;
439
440
  /* We can only write packet records. */
441
0
  if (rec->rec_type != REC_TYPE_PACKET) {
442
0
    *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
443
0
    *err_info = wtap_unwritable_rec_type_err_string(rec);
444
0
    return false;
445
0
  }
446
447
  /* Don't write out anything bigger than we can read.
448
   * (The length field in packet headers is 16 bits, which
449
   * imposes a hard limit.) */
450
0
  if (rec->rec_header.packet_header.caplen > 65535) {
451
0
    *err = WTAP_ERR_PACKET_TOO_LARGE;
452
0
    return false;
453
0
  }
454
455
0
  cv_hdr.data_len = GUINT16_TO_LE((uint16_t)rec->rec_header.packet_header.caplen);
456
0
  cv_hdr.source_data_len = GUINT16_TO_LE((uint16_t)rec->rec_header.packet_header.caplen);
457
0
  cv_hdr.version = 0;
458
459
0
  tm = localtime(&rec->ts.secs);
460
0
  if (tm != NULL) {
461
0
    cv_hdr.year = GUINT16_TO_LE(tm->tm_year + 1900);
462
0
    cv_hdr.month = tm->tm_mon + 1;
463
0
    cv_hdr.day = tm->tm_mday;
464
0
    cv_hdr.hours = tm->tm_hour;
465
0
    cv_hdr.minutes = tm->tm_min;
466
0
    cv_hdr.seconds = tm->tm_sec;
467
0
    cv_hdr.usecs = GUINT32_TO_LE(rec->ts.nsecs / 1000);
468
0
  } else {
469
    /*
470
     * Second before the Epoch.
471
     */
472
0
    cv_hdr.year = GUINT16_TO_LE(1969);
473
0
    cv_hdr.month = 12;
474
0
    cv_hdr.day = 31;
475
0
    cv_hdr.hours = 23;
476
0
    cv_hdr.minutes = 59;
477
0
    cv_hdr.seconds = 59;
478
0
    cv_hdr.usecs = 0;
479
0
  }
480
481
0
  switch(rec->rec_header.packet_header.pkt_encap) {
482
483
0
  case WTAP_ENCAP_ETHERNET :
484
0
    cv_hdr.flags |= MEDIUM_ETHERNET;
485
0
    break;
486
487
0
  case WTAP_ENCAP_IEEE_802_11 :
488
0
    cv_hdr.flags |=  MEDIUM_WIFI;
489
0
    break;
490
491
0
  case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
492
0
    cv_hdr.flags |=  MEDIUM_WIFI;
493
494
0
    switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy) {
495
496
0
    case PHDR_802_11_PHY_11A:
497
      /*
498
       * If we don't know whether it's turbo, say it's
499
       * not.
500
       */
501
0
      if (!rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type ||
502
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.turbo_type == PHDR_802_11A_TURBO_TYPE_NORMAL)
503
0
        cv_hdr.band = BAND_11A;
504
0
      else
505
0
        cv_hdr.band = BAND_11A_TURBO;
506
0
      break;
507
508
0
    case PHDR_802_11_PHY_11B:
509
0
      cv_hdr.band = BAND_11B;
510
0
      break;
511
512
0
    case PHDR_802_11_PHY_11G:
513
      /*
514
       * If we don't know whether it's Super G, say it's
515
       * not.
516
       */
517
0
      if (!rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode)
518
0
        cv_hdr.band = BAND_11G;
519
0
      else {
520
0
        switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.mode) {
521
522
0
        case PHDR_802_11G_MODE_NORMAL:
523
0
          cv_hdr.band = BAND_11G;
524
0
          break;
525
526
0
        case PHDR_802_11G_MODE_SUPER_G:
527
0
          cv_hdr.band = BAND_SUPERG;
528
0
          break;
529
530
0
        default:
531
0
          cv_hdr.band = BAND_11G;
532
0
          break;
533
0
        }
534
0
      }
535
0
      break;
536
537
0
    case PHDR_802_11_PHY_11N:
538
      /*
539
       * Pick the band based on the frequency.
540
       */
541
0
      if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency) {
542
0
        if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency > 2484) {
543
          /* 5 GHz band */
544
0
          cv_hdr.band = BAND_11N_5GHZ;
545
0
        } else {
546
          /* 2.4 GHz band */
547
0
          cv_hdr.band = BAND_11N_2_4GHZ;
548
0
        }
549
0
      } else {
550
        /* Band is unknown. */
551
0
        cv_hdr.band = 0;
552
0
      }
553
0
      break;
554
555
0
    default:
556
      /*
557
       * It's not documented how they handle 11ac,
558
       * and they don't support the older PHYs.
559
       */
560
0
      cv_hdr.band = 0;
561
0
      break;
562
0
    }
563
0
    cv_hdr.channel =
564
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel ?
565
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel :
566
0
          0;
567
0
    cv_hdr.rate =
568
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate ?
569
0
          (uint8_t)(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate & 0xFF) :
570
0
          0;
571
0
    cv_hdr.direction =
572
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate ?
573
0
          (uint8_t)((rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate >> 8) & 0xFF) :
574
0
          0;
575
0
    cv_hdr.signal_level_percent =
576
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent ?
577
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent :
578
0
          0;
579
0
    cv_hdr.signal_level_dbm =
580
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm ?
581
0
          -rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm :
582
0
          0;
583
0
    cv_hdr.noise_level_dbm =
584
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm ?
585
0
          -rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm :
586
0
          0;
587
0
    break;
588
589
0
  case WTAP_ENCAP_TOKEN_RING :
590
0
    cv_hdr.flags |= MEDIUM_TOKEN_RING;
591
0
    break;
592
593
0
  default :
594
0
    *err = WTAP_ERR_UNWRITABLE_ENCAP;
595
0
    return false;
596
0
  }
597
598
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.data_len, 2, err))
599
0
    return false;
600
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.source_data_len, 2, err))
601
0
    return false;
602
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.version, 1, err))
603
0
    return false;
604
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.year, 2, err))
605
0
    return false;
606
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.month, 1, err))
607
0
    return false;
608
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.day, 1, err))
609
0
    return false;
610
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.hours, 1, err))
611
0
    return false;
612
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.minutes, 1, err))
613
0
    return false;
614
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.seconds, 1, err))
615
0
    return false;
616
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.usecs, 4, err))
617
0
    return false;
618
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.flags, 1, err))
619
0
    return false;
620
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.signal_level_percent, 1, err))
621
0
    return false;
622
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.rate, 1, err))
623
0
    return false;
624
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.band, 1, err))
625
0
    return false;
626
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.channel, 1, err))
627
0
    return false;
628
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.direction, 1, err))
629
0
    return false;
630
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.signal_level_dbm, 1, err))
631
0
    return false;
632
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.noise_level_dbm, 1, err))
633
0
    return false;
634
0
  if (!wtap_dump_file_write(wdh, ws_buffer_start_ptr(&rec->data), rec->rec_header.packet_header.caplen, err))
635
0
    return false;
636
0
  return true;
637
0
}
638
639
typedef struct commview_ncfx_header {
640
  uint32_t  data_len;
641
  uint16_t  year;
642
  uint8_t   month;
643
  uint8_t   day;
644
  uint8_t   hours;
645
  uint8_t   minutes;
646
  uint8_t   seconds;
647
  uint32_t  usecs;
648
  uint8_t   medium_type;
649
  uint8_t   decryption_flag;
650
  uint8_t   direction;
651
  uint8_t   reserved1;
652
  uint8_t   reserved2;
653
} commview_ncfx_header_t;
654
655
0
#define COMMVIEW_NCFX_HEADER_SIZE 20
656
657
typedef struct commview_ncfx_rf_header {
658
  uint16_t  header_len;   /* includes extension headers */
659
  uint16_t  status_modulation;
660
  uint16_t  frequency_band;
661
  uint16_t  channel;
662
  uint8_t   noise_level_dbm;  /* abs(noise in dBm) */
663
  uint8_t   signal_level_dbm; /* abs(signal in dBm) */
664
  uint8_t   signal_level_percent;
665
  uint8_t   reserved;
666
  uint32_t  phy_rate;   /* in 100Kbps units */
667
  uint32_t  extensions_present;
668
} commview_ncfx_rf_header_t;
669
670
0
#define COMMVIEW_NCFX_RF_HEADER_SIZE  20
671
672
typedef struct commview_ncfx_mcs_header {
673
  uint8_t   mcs_index;
674
  uint8_t   n_streams;
675
  uint8_t   channel_width;
676
  uint8_t   guard_interval;
677
} commview_ncfx_mcs_header_t;
678
679
0
#define COMMVIEW_NCFX_MCS_HEADER_SIZE 4
680
681
/*
682
 * Bit-field positions for various fields in the status_modulation variable
683
 * of the header.
684
 */
685
#define STATUS_MODULATION_BAD_FCS 0x01
686
0
#define STATUS_MODULATION_HT_PHY  0x02
687
0
#define STATUS_MODULATION_VHT_PHY 0x04
688
0
#define STATUS_MODULATION_HE_PHY  0x08
689
#define STATUS_MODULATION_HE_OFDMA  0x10
690
691
/* Values for the frequency_band variable of the header */
692
0
#define BAND_5GHZ   0x40
693
0
#define BAND_2_4GHZ   0x80
694
695
/* Presence bits */
696
0
#define PRESENCE_MCS_HEADER 0x00000001  /* type 0, bit 0 */
697
698
static bool commview_ncfx_read(wtap *wth, wtap_rec *rec,
699
    int *err, char **err_info, int64_t *data_offset);
700
static bool commview_ncfx_seek_read(wtap *wth, int64_t seek_off,
701
    wtap_rec *rec, int *err, char **err_info);
702
static bool commview_ncfx_read_header(commview_ncfx_header_t *cv_hdr,
703
    FILE_T fh, int *err, char **err_info);
704
static bool commview_ncfx_read_rf_header(commview_ncfx_rf_header_t *cv_rf_hdr,
705
    FILE_T fh, int *err, char **err_info);
706
static bool commview_ncfx_read_mcs_header(commview_ncfx_mcs_header_t *cv_mcs_hdr,
707
    FILE_T fh, int *err, char **err_info);
708
static bool commview_ncfx_dump(wtap_dumper *wdh, const wtap_rec *rec,
709
    int *err, char **err_info);
710
711
wtap_open_return_val
712
commview_ncfx_open(wtap *wth, int *err, char **err_info)
713
0
{
714
0
  commview_ncfx_header_t cv_hdr;
715
716
0
  if(!commview_ncfx_read_header(&cv_hdr, wth->fh, err, err_info)) {
717
0
    if (*err == 0) {
718
      /* EOF - not our file */
719
0
      return WTAP_OPEN_NOT_MINE;
720
0
    }
721
0
    if (*err == WTAP_ERR_SHORT_READ) {
722
      /* Short read - not our file */
723
0
      return WTAP_OPEN_NOT_MINE;
724
0
    }
725
0
    if (*err == WTAP_ERR_BAD_FILE) {
726
      /*
727
       * Not a valid record header - not our file;
728
       * discard the error.
729
       */
730
0
      wmem_free(NULL, *err_info);
731
0
      *err_info = NULL;
732
0
      return WTAP_OPEN_NOT_MINE;
733
0
    }
734
    /* Hard error. */
735
0
    return WTAP_OPEN_ERROR;
736
0
  }
737
738
  /* If any of these fields do not match what we expect, bail out. */
739
0
  if(cv_hdr.year < 2000 || /* XXX - when was this format introduced? */
740
0
     cv_hdr.month < 1 || cv_hdr.month > 12 ||
741
0
     cv_hdr.day < 1 || cv_hdr.day > 31 ||
742
0
     cv_hdr.hours > 23 ||
743
0
     cv_hdr.minutes > 59 ||
744
0
     cv_hdr.seconds > 60)
745
0
    return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
746
0
  switch (cv_hdr.medium_type) {
747
748
0
  case MEDIUM_ETHERNET:
749
0
    if (cv_hdr.direction != 0x00 &&
750
0
        cv_hdr.direction != 0x01 &&
751
0
        cv_hdr.direction != 0x02)
752
0
      return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
753
0
    break;
754
755
0
  case MEDIUM_WIFI:
756
0
    if (cv_hdr.decryption_flag != 0x00 &&
757
0
        cv_hdr.decryption_flag != 0x01)
758
0
      return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
759
0
    if (cv_hdr.direction != 0x00)
760
0
      return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
761
0
    break;
762
763
0
  default:
764
0
    return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
765
0
  }
766
767
  /* No file header. Reset the fh to 0 so we can read the first packet */
768
0
  if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
769
0
    return WTAP_OPEN_ERROR;
770
771
  /* Set up the pointers to the handlers for this file type */
772
0
  wth->subtype_read = commview_ncfx_read;
773
0
  wth->subtype_seek_read = commview_ncfx_seek_read;
774
775
0
  wth->file_type_subtype = commview_ncfx_file_type_subtype;
776
0
  wth->file_encap = WTAP_ENCAP_PER_PACKET;
777
0
  wth->file_tsprec = WTAP_TSPREC_USEC;
778
779
0
  return WTAP_OPEN_MINE; /* Our kind of file */
780
0
}
781
782
static int
783
commview_ncfx_read_packet(FILE_T fh, wtap_rec *rec,
784
    int *err, char **err_info)
785
0
{
786
0
  commview_ncfx_header_t cv_hdr;
787
0
  uint32_t length_remaining;
788
0
  struct tm tm;
789
0
  commview_ncfx_rf_header_t cv_rf_hdr;
790
0
  unsigned frequency;
791
0
  commview_ncfx_mcs_header_t cv_mcs_hdr;
792
793
0
  if (!commview_ncfx_read_header(&cv_hdr, fh, err, err_info))
794
0
    return false;
795
796
0
  wtap_setup_packet_rec(rec, WTAP_ENCAP_UNKNOWN);
797
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
798
799
  /* Amount of data remaining in the record, after the header */
800
0
  length_remaining = cv_hdr.data_len - COMMVIEW_NCFX_HEADER_SIZE;
801
802
0
  switch(cv_hdr.medium_type) {
803
804
0
  case MEDIUM_ETHERNET :
805
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETHERNET;
806
0
    rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1; /* Unknown */
807
0
    break;
808
809
0
  case MEDIUM_WIFI :
810
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
811
0
    memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
812
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = 0; /* No FCS */
813
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = (cv_hdr.decryption_flag == 0x01);
814
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = false;
815
816
    /*
817
     * Make sure we have enough data left for the RF header.
818
     */
819
0
    if (length_remaining < COMMVIEW_NCFX_RF_HEADER_SIZE) {
820
0
      *err = WTAP_ERR_BAD_FILE;
821
0
      *err_info = ws_strdup_printf("commview: RF header goes past the NCFX data length %u",
822
0
          cv_hdr.data_len);
823
0
      return false;
824
0
    }
825
0
    length_remaining -= COMMVIEW_NCFX_RF_HEADER_SIZE;
826
827
    /*
828
     * Read the RF header.
829
     */
830
0
    if (!commview_ncfx_read_rf_header(&cv_rf_hdr, fh, err, err_info))
831
0
      return false;
832
0
    if (cv_rf_hdr.status_modulation & STATUS_MODULATION_HE_PHY)
833
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11AX;
834
0
    else if (cv_rf_hdr.status_modulation & STATUS_MODULATION_VHT_PHY)
835
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11AC;
836
0
    else if (cv_rf_hdr.status_modulation & STATUS_MODULATION_HT_PHY)
837
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11N;
838
0
    else {
839
      /*
840
       * Unknown PHY, for now.
841
       */
842
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
843
0
    }
844
0
    switch (cv_rf_hdr.frequency_band) {
845
846
0
    case BAND_5GHZ:
847
0
      frequency = ieee80211_chan_to_mhz(cv_rf_hdr.channel, false);
848
0
      if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_UNKNOWN) {
849
        /*
850
         * None of the modulation bits were set, so
851
         * this is presumably the 11a OFDM PHY.
852
         */
853
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
854
0
      }
855
0
      break;
856
857
0
    case BAND_2_4GHZ:
858
0
      frequency = ieee80211_chan_to_mhz(cv_rf_hdr.channel, true);
859
0
      if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_UNKNOWN) {
860
        /*
861
         * None of the modulation bits were set, so
862
         * guess the PHY based on the data rate.
863
         *
864
         * cv_rf_hdr.phy_rate is in units of 100
865
         * Kbits/s.
866
         */
867
0
        if (cv_rf_hdr.phy_rate == 10 /* 1 Mb/s */ ||
868
0
            cv_rf_hdr.phy_rate == 20 /* 2 Mb/s */ ||
869
0
            cv_rf_hdr.phy_rate == 55 /* 5.5 Mb/s */ ||
870
0
            cv_rf_hdr.phy_rate == 110 /* 11 Mb/s */ ||
871
0
            cv_rf_hdr.phy_rate == 220 /* 22 Mb/s */ ||
872
0
            cv_rf_hdr.phy_rate == 330 /* 33 Mb/s */)
873
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
874
0
        else
875
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
876
0
      }
877
0
      break;
878
879
0
    default:
880
0
      frequency = 0;
881
0
      break;
882
0
    }
883
0
    if (frequency != 0) {
884
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency = true;
885
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency = frequency;
886
0
    }
887
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = true;
888
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = cv_rf_hdr.channel;
889
890
    /*
891
     * cv_rf_hdr.phy_rate is in units of 100 Kbits/s.
892
     *
893
     * pseudo_header.ieee_802_11.data_rate is in units of 500
894
     * Kbits/s.
895
     */
896
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = true;
897
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate =
898
0
        cv_rf_hdr.phy_rate/5;
899
900
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = true;
901
0
    rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = cv_rf_hdr.signal_level_percent;
902
903
    /*
904
     * These is the absolute value of the signal and noise,
905
     * in dBm.  The value is the negative of that.
906
     *
907
     * XXX - sometimes these are 0; assume that means that no
908
     * value is provided.
909
     */
910
0
    if (cv_rf_hdr.signal_level_dbm != 0) {
911
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm = -cv_rf_hdr.signal_level_dbm;
912
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm = true;
913
0
    }
914
0
    if (cv_rf_hdr.noise_level_dbm != 0) {
915
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm = -cv_rf_hdr.noise_level_dbm;
916
0
      rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm = true;
917
0
    }
918
919
0
    if (cv_rf_hdr.extensions_present & PRESENCE_MCS_HEADER) {
920
      /*
921
       * Make sure we have enough data left for the
922
       * MCS header.
923
       */
924
0
      if (length_remaining < COMMVIEW_NCFX_MCS_HEADER_SIZE) {
925
0
        *err = WTAP_ERR_BAD_FILE;
926
0
        *err_info = ws_strdup_printf("commview: MCS header goes past the NCFX data length %u",
927
0
            cv_hdr.data_len);
928
0
        return false;
929
0
      }
930
0
      length_remaining -= COMMVIEW_NCFX_MCS_HEADER_SIZE;
931
932
      /*
933
       * Read the MCS header.
934
       */
935
0
      if (!commview_ncfx_read_mcs_header(&cv_mcs_hdr, fh,
936
0
          err, err_info))
937
0
        return false;
938
0
      switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy) {
939
940
0
      case PHDR_802_11_PHY_11N:
941
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.has_mcs_index = true;
942
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.mcs_index = cv_mcs_hdr.mcs_index;
943
        /* number of STBC streams? */
944
0
        switch (cv_mcs_hdr.channel_width) {
945
946
0
        case 0x00:
947
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.has_bandwidth = true;
948
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.bandwidth = PHDR_802_11_BANDWIDTH_20_MHZ;
949
0
          break;
950
951
0
        case 0x01:
952
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.has_bandwidth = true;
953
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.bandwidth = PHDR_802_11_BANDWIDTH_40_MHZ;
954
0
          break;
955
956
0
        default:
957
0
          break;
958
0
        }
959
        /* Guard interval? */
960
0
        break;
961
962
0
      case PHDR_802_11_PHY_11AC:
963
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[0] = cv_mcs_hdr.mcs_index;
964
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[1] = 0;
965
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[2] = 0;
966
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[3] = 0;
967
        /* Remaining MCS indices? */
968
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.nss[0] = cv_mcs_hdr.n_streams;
969
0
        switch (cv_mcs_hdr.channel_width) {
970
971
0
        case 0x00:
972
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.has_bandwidth = true;
973
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.bandwidth = PHDR_802_11_BANDWIDTH_20_MHZ;
974
0
          break;
975
976
0
        case 0x01:
977
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.has_bandwidth = true;
978
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.bandwidth = PHDR_802_11_BANDWIDTH_40_MHZ;
979
0
          break;
980
981
0
        case 0x02:
982
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.has_bandwidth = true;
983
0
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.bandwidth = PHDR_802_11_BANDWIDTH_80_MHZ;
984
0
          break;
985
986
0
        default:
987
0
          break;
988
0
        }
989
        /* Guard interval? */
990
0
        break;
991
992
0
      case PHDR_802_11_PHY_11AX:
993
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ax.has_mcs_index = true;
994
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ax.mcs = cv_mcs_hdr.mcs_index;
995
0
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ax.nsts = cv_mcs_hdr.n_streams;
996
        /* Bandwidth stuff? */
997
        /* Guard interval? */
998
0
        break;
999
1000
0
      default:
1001
0
        break;
1002
0
      }
1003
0
    }
1004
0
    break;
1005
1006
0
  default :
1007
0
    *err = WTAP_ERR_BAD_FILE;
1008
0
    *err_info = ws_strdup_printf("commview: unsupported encap for NCFX: %u",
1009
0
              cv_hdr.medium_type);
1010
0
    return false;
1011
0
  }
1012
1013
0
  tm.tm_year = cv_hdr.year - 1900;
1014
0
  tm.tm_mon = cv_hdr.month - 1;
1015
0
  tm.tm_mday = cv_hdr.day;
1016
0
  tm.tm_hour = cv_hdr.hours;
1017
0
  tm.tm_min = cv_hdr.minutes;
1018
0
  tm.tm_sec = cv_hdr.seconds;
1019
0
  tm.tm_isdst = -1;
1020
1021
0
  rec->presence_flags = WTAP_HAS_TS;
1022
1023
0
  if (length_remaining > WTAP_MAX_PACKET_SIZE_STANDARD) {
1024
    /*
1025
     * Probably a corrupt capture file; don't blow up trying
1026
     * to allocate space for an immensely-large packet.
1027
     */
1028
0
    *err = WTAP_ERR_BAD_FILE;
1029
0
    *err_info = ws_strdup_printf("commview: File has %u-byte packet, bigger than maximum of %u",
1030
0
        length_remaining, WTAP_MAX_PACKET_SIZE_STANDARD);
1031
0
    return false;
1032
0
  }
1033
1034
0
  rec->rec_header.packet_header.len = length_remaining;
1035
0
  rec->rec_header.packet_header.caplen = length_remaining;
1036
1037
0
  rec->ts.secs = mktime(&tm);
1038
0
  rec->ts.nsecs = cv_hdr.usecs * 1000;
1039
1040
0
  return wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info);
1041
0
}
1042
1043
static bool
1044
commview_ncfx_read(wtap *wth, wtap_rec *rec, int *err, char **err_info,
1045
    int64_t *data_offset)
1046
0
{
1047
0
  *data_offset = file_tell(wth->fh);
1048
1049
0
  return commview_ncfx_read_packet(wth->fh, rec, err, err_info);
1050
0
}
1051
1052
static bool
1053
commview_ncfx_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
1054
    int *err, char **err_info)
1055
0
{
1056
0
  if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1057
0
    return false;
1058
1059
0
  return commview_ncfx_read_packet(wth->random_fh, rec, err, err_info);
1060
0
}
1061
1062
static bool
1063
commview_ncfx_read_header(commview_ncfx_header_t *cv_hdr, FILE_T fh, int *err,
1064
    char **err_info)
1065
0
{
1066
0
  if (!wtap_read_bytes_or_eof(fh, &cv_hdr->data_len, 4, err, err_info))
1067
0
    return false;
1068
1069
  /* Convert data length from little endian to host endian format */
1070
0
  cv_hdr->data_len = GUINT32_FROM_LE(cv_hdr->data_len);
1071
1072
  /* It must be at least the length of the general header. */
1073
0
  if (cv_hdr->data_len < COMMVIEW_NCFX_HEADER_SIZE) {
1074
0
    *err = WTAP_ERR_BAD_FILE;
1075
0
    *err_info = ws_strdup_printf("commview: NCFX data length %u < %u",
1076
0
              cv_hdr->data_len,
1077
0
              COMMVIEW_NCFX_HEADER_SIZE);
1078
0
    return false;
1079
0
  }
1080
1081
0
  if (!wtap_read_bytes(fh, &cv_hdr->year, 2, err, err_info))
1082
0
    return false;
1083
0
  if (!wtap_read_bytes(fh, &cv_hdr->month, 1, err, err_info))
1084
0
    return false;
1085
0
  if (!wtap_read_bytes(fh, &cv_hdr->day, 1, err, err_info))
1086
0
    return false;
1087
0
  if (!wtap_read_bytes(fh, &cv_hdr->hours, 1, err, err_info))
1088
0
    return false;
1089
0
  if (!wtap_read_bytes(fh, &cv_hdr->minutes, 1, err, err_info))
1090
0
    return false;
1091
0
  if (!wtap_read_bytes(fh, &cv_hdr->seconds, 1, err, err_info))
1092
0
    return false;
1093
0
  if (!wtap_read_bytes(fh, &cv_hdr->usecs, 4, err, err_info))
1094
0
    return false;
1095
0
  if (!wtap_read_bytes(fh, &cv_hdr->medium_type, 1, err, err_info))
1096
0
    return false;
1097
0
  if (!wtap_read_bytes(fh, &cv_hdr->decryption_flag, 1, err, err_info))
1098
0
    return false;
1099
0
  if (!wtap_read_bytes(fh, &cv_hdr->direction, 1, err, err_info))
1100
0
    return false;
1101
0
  if (!wtap_read_bytes(fh, &cv_hdr->reserved1, 1, err, err_info))
1102
0
    return false;
1103
0
  if (!wtap_read_bytes(fh, &cv_hdr->reserved2, 1, err, err_info))
1104
0
    return false;
1105
1106
  /* Convert multi-byte values from little endian to host endian format */
1107
0
  cv_hdr->year = GUINT16_FROM_LE(cv_hdr->year);
1108
0
  cv_hdr->usecs = GUINT32_FROM_LE(cv_hdr->usecs);
1109
1110
0
  return true;
1111
0
}
1112
1113
static bool
1114
commview_ncfx_read_rf_header(commview_ncfx_rf_header_t *cv_rf_hdr, FILE_T fh,
1115
    int *err, char **err_info)
1116
0
{
1117
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->header_len, 2, err, err_info))
1118
0
    return false;
1119
1120
  /* Convert header length from little endian to host endian format */
1121
0
  cv_rf_hdr->header_len = GUINT16_FROM_LE(cv_rf_hdr->header_len);
1122
1123
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->status_modulation, 2, err, err_info))
1124
0
    return false;
1125
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->frequency_band, 2, err, err_info))
1126
0
    return false;
1127
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->channel, 2, err, err_info))
1128
0
    return false;
1129
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->noise_level_dbm, 1, err, err_info))
1130
0
    return false;
1131
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->signal_level_dbm, 1, err, err_info))
1132
0
    return false;
1133
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->signal_level_percent, 1, err, err_info))
1134
0
    return false;
1135
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->reserved, 1, err, err_info))
1136
0
    return false;
1137
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->phy_rate, 4, err, err_info))
1138
0
    return false;
1139
0
  if (!wtap_read_bytes(fh, &cv_rf_hdr->extensions_present, 4, err, err_info))
1140
0
    return false;
1141
1142
  /* Convert remaining multi-byte values from little endian to host endian format */
1143
0
  cv_rf_hdr->status_modulation = GUINT16_FROM_LE(cv_rf_hdr->status_modulation);
1144
0
  cv_rf_hdr->frequency_band = GUINT16_FROM_LE(cv_rf_hdr->frequency_band);
1145
0
  cv_rf_hdr->channel = GUINT16_FROM_LE(cv_rf_hdr->channel);
1146
0
  cv_rf_hdr->phy_rate = GUINT32_FROM_LE(cv_rf_hdr->phy_rate);
1147
0
  cv_rf_hdr->extensions_present = GUINT32_FROM_LE(cv_rf_hdr->extensions_present);
1148
1149
0
  return true;
1150
0
}
1151
1152
static bool
1153
commview_ncfx_read_mcs_header(commview_ncfx_mcs_header_t *cv_mcs_hdr, FILE_T fh,
1154
    int *err, char **err_info)
1155
0
{
1156
0
  if (!wtap_read_bytes(fh, &cv_mcs_hdr->mcs_index, 1, err, err_info))
1157
0
    return false;
1158
0
  if (!wtap_read_bytes(fh, &cv_mcs_hdr->n_streams, 1, err, err_info))
1159
0
    return false;
1160
0
  if (!wtap_read_bytes(fh, &cv_mcs_hdr->channel_width, 1, err, err_info))
1161
0
    return false;
1162
0
  if (!wtap_read_bytes(fh, &cv_mcs_hdr->guard_interval, 1, err, err_info))
1163
0
    return false;
1164
1165
0
  return true;
1166
0
}
1167
1168
/* Returns 0 if we can write out the specified encapsulation type
1169
 * into a CommView format file. */
1170
static int
1171
commview_ncfx_dump_can_write_encap(int encap)
1172
0
{
1173
0
  switch (encap) {
1174
1175
0
  case WTAP_ENCAP_ETHERNET :
1176
0
  case WTAP_ENCAP_IEEE_802_11 :
1177
0
  case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
1178
0
  case WTAP_ENCAP_PER_PACKET :
1179
0
    return 0;
1180
1181
0
  default:
1182
0
    return WTAP_ERR_UNWRITABLE_ENCAP;
1183
0
  }
1184
0
}
1185
1186
/* Returns true on success, false on failure;
1187
   sets "*err" to an error code on failure */
1188
static bool
1189
commview_ncfx_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_)
1190
0
{
1191
0
  wdh->subtype_write = commview_ncfx_dump;
1192
1193
  /* There is no file header to write out */
1194
0
  return true;
1195
0
}
1196
1197
/* Write a record for a packet to a dump file.
1198
 * Returns true on success, false on failure. */
1199
static bool
1200
commview_ncfx_dump(wtap_dumper *wdh, const wtap_rec *rec,
1201
    int *err, char **err_info _U_)
1202
0
{
1203
0
  commview_ncfx_header_t cv_hdr = {0};
1204
0
  struct tm *tm;
1205
1206
  /* We can only write packet records. */
1207
0
  if (rec->rec_type != REC_TYPE_PACKET) {
1208
0
    *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
1209
0
    *err_info = wtap_unwritable_rec_type_err_string(rec);
1210
0
    return false;
1211
0
  }
1212
1213
  /* Don't write out anything bigger than we can read.
1214
   * (The length field in packet headers is 16 bits, which
1215
   * imposes a hard limit.) */
1216
0
  if (rec->rec_header.packet_header.caplen > 65535) {
1217
0
    *err = WTAP_ERR_PACKET_TOO_LARGE;
1218
0
    return false;
1219
0
  }
1220
1221
0
  cv_hdr.data_len = GUINT32_TO_LE((uint32_t)rec->rec_header.packet_header.caplen);
1222
1223
0
  tm = localtime(&rec->ts.secs);
1224
0
  if (tm != NULL) {
1225
0
    cv_hdr.year = GUINT16_TO_LE(tm->tm_year + 1900);
1226
0
    cv_hdr.month = tm->tm_mon + 1;
1227
0
    cv_hdr.day = tm->tm_mday;
1228
0
    cv_hdr.hours = tm->tm_hour;
1229
0
    cv_hdr.minutes = tm->tm_min;
1230
0
    cv_hdr.seconds = tm->tm_sec;
1231
0
    cv_hdr.usecs = GUINT32_TO_LE(rec->ts.nsecs / 1000);
1232
0
  } else {
1233
    /*
1234
     * Second before the Epoch.
1235
     */
1236
0
    cv_hdr.year = GUINT16_TO_LE(1969);
1237
0
    cv_hdr.month = 12;
1238
0
    cv_hdr.day = 31;
1239
0
    cv_hdr.hours = 23;
1240
0
    cv_hdr.minutes = 59;
1241
0
    cv_hdr.seconds = 59;
1242
0
    cv_hdr.usecs = 0;
1243
0
  }
1244
0
  cv_hdr.reserved1 = 0;
1245
0
  cv_hdr.reserved2 = 0;
1246
1247
0
  switch(rec->rec_header.packet_header.pkt_encap) {
1248
1249
0
  case WTAP_ENCAP_ETHERNET :
1250
0
    cv_hdr.medium_type = MEDIUM_ETHERNET;
1251
0
    cv_hdr.decryption_flag = 0x00;
1252
0
    cv_hdr.direction = 0x00;  /* what does this mean? */
1253
0
    break;
1254
1255
0
  case WTAP_ENCAP_IEEE_802_11 :
1256
    /* XXX - the claim is that the RF header is mandatory */
1257
0
    cv_hdr.medium_type = MEDIUM_WIFI;
1258
0
    break;
1259
1260
0
  case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
1261
0
    cv_hdr.medium_type = MEDIUM_WIFI;
1262
1263
#if 0
1264
    switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy) {
1265
1266
    case PHDR_802_11_PHY_11N:
1267
      cv_hdr.status_modulation = STATUS_MODULATION_HT_PHY;
1268
      break;
1269
1270
    case PHDR_802_11_PHY_11AC:
1271
      cv_hdr.status_modulation = STATUS_MODULATION_VHT_PHY;
1272
      break;
1273
1274
    case PHDR_802_11_PHY_11AX:
1275
      cv_hdr.status_modulation = STATUS_MODULATION_HE_PHY;
1276
      break;
1277
1278
    default:
1279
      cv_hdr.status_modulation = 0;
1280
      break;
1281
    }
1282
1283
    /*
1284
     * Pick the band based on the frequency.
1285
     */
1286
    if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency) {
1287
      if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency > 2484) {
1288
        /* 5 GHz band */
1289
        cv_hdr.frequency_band = BAND_5GHZ;
1290
      } else {
1291
        /* 2.4 GHz band */
1292
        cv_hdr.frequency_band = BAND_2_4GHZ;
1293
      }
1294
    } else {
1295
      /* Band is unknown. */
1296
      cv_hdr.band = 0;
1297
    }
1298
1299
    cv_hdr.channel =
1300
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel ?
1301
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel :
1302
          0;
1303
    cv_hdr.noise_level_dbm =
1304
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm ?
1305
          -rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm :
1306
          0;
1307
    cv_hdr.signal_level_dbm =
1308
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm ?
1309
          -rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm :
1310
          0;
1311
    cv_hdr.signal_level_percent =
1312
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent ?
1313
          rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent :
1314
          0;
1315
    cv_hdr.reserved = 0;
1316
    cv_hdr.phy_rate =
1317
        rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate ?
1318
          (uint32_t)(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate & 0xFF) :
1319
          0;
1320
#endif
1321
0
    break;
1322
1323
0
  default :
1324
0
    *err = WTAP_ERR_UNWRITABLE_ENCAP;
1325
0
    return false;
1326
0
  }
1327
1328
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.data_len, 4, err))
1329
0
    return false;
1330
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.year, 2, err))
1331
0
    return false;
1332
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.month, 1, err))
1333
0
    return false;
1334
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.day, 1, err))
1335
0
    return false;
1336
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.hours, 1, err))
1337
0
    return false;
1338
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.minutes, 1, err))
1339
0
    return false;
1340
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.seconds, 1, err))
1341
0
    return false;
1342
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.usecs, 4, err))
1343
0
    return false;
1344
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.medium_type, 1, err))
1345
0
    return false;
1346
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.decryption_flag, 1, err))
1347
0
    return false;
1348
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.direction, 1, err))
1349
0
    return false;
1350
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.reserved1, 1, err))
1351
0
    return false;
1352
0
  if (!wtap_dump_file_write(wdh, &cv_hdr.reserved2, 1, err))
1353
0
    return false;
1354
1355
  /* XXX - RF and MCS headers */
1356
1357
0
  if (!wtap_dump_file_write(wdh, ws_buffer_start_ptr(&rec->data),
1358
0
      rec->rec_header.packet_header.caplen, err))
1359
0
    return false;
1360
1361
0
  return true;
1362
0
}
1363
1364
static const struct supported_block_type commview_blocks_supported[] = {
1365
  /*
1366
   * We support packet blocks, with no comments or other options.
1367
   */
1368
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
1369
};
1370
1371
static const struct file_type_subtype_info commview_ncf_info = {
1372
  "TamoSoft CommView NCF", "commview-ncf", "ncf", NULL,
1373
  false, BLOCKS_SUPPORTED(commview_blocks_supported),
1374
  commview_ncf_dump_can_write_encap, commview_ncf_dump_open, NULL
1375
};
1376
1377
static const struct file_type_subtype_info commview_ncfx_info = {
1378
  "TamoSoft CommView NCFX", "commview-ncfx", "ncfx", NULL,
1379
  false, BLOCKS_SUPPORTED(commview_blocks_supported),
1380
  commview_ncfx_dump_can_write_encap, commview_ncfx_dump_open, NULL
1381
};
1382
1383
void register_commview(void)
1384
15
{
1385
15
  commview_ncf_file_type_subtype = wtap_register_file_type_subtype(&commview_ncf_info);
1386
15
  commview_ncfx_file_type_subtype = wtap_register_file_type_subtype(&commview_ncfx_info);
1387
1388
  /*
1389
   * Register name for backwards compatibility with the
1390
   * wtap_filetypes table in Lua.
1391
   *
1392
   * We don't need to register the new type, as the Wireshark
1393
   * version with which we're providing backwards compatibility
1394
   * didn't support the NCFX format.  New code should fetch
1395
   * the file type/subtype with wtap_name_to_file_type_subtype().
1396
   */
1397
15
  wtap_register_backwards_compatibility_lua_name("COMMVIEW",
1398
15
      commview_ncf_file_type_subtype);
1399
15
}
1400
1401
/*
1402
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1403
 *
1404
 * Local variables:
1405
 * c-basic-offset: 8
1406
 * tab-width: 8
1407
 * indent-tabs-mode: t
1408
 * End:
1409
 *
1410
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1411
 * :indentSize=8:tabSize=8:noTabs=false:
1412
 */