Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / wiretap / commview.c
blob81e17c9112aeeea3d9be5c87f95156ba7fa69d78
1 /* commview.c
2 * Routines for opening CommView NCF and NCFX file format packet captures
3 * Copyright 2007, Stephen Fisher (see AUTHORS file)
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Based on csids.c and nettl.c
11 * SPDX-License-Identifier: GPL-2.0-or-later
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
18 * Use
20 * https://web.archive.org/web/20171022225753/http://www.tamos.com/htmlhelp/commview/logformat.htm
22 * if that doesn't display anything.
25 #include "config.h"
26 #include "commview.h"
28 #include <stdlib.h>
29 #include <string.h>
31 #include "wtap-int.h"
32 #include "file_wrappers.h"
34 #include <wsutil/802_11-utils.h>
37 * Capture medium types used in NCF and NCFX;
38 * Token Ring isn't used in NCFX.
40 #define MEDIUM_ETHERNET 0
41 #define MEDIUM_WIFI 1
42 #define MEDIUM_TOKEN_RING 2
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;
66 #define COMMVIEW_NCF_HEADER_SIZE 24
68 /* Bit-field positions for various fields in the flags variable of the header */
69 #define FLAGS_MEDIUM 0x0F
70 #define FLAGS_DECRYPTED 0x10
71 #define FLAGS_BROKEN 0x20
72 #define FLAGS_COMPRESSED 0x40
73 #define FLAGS_RESERVED 0x80
75 /* Values for the band variable of the header */
76 #define BAND_11A 0x01
77 #define BAND_11B 0x02
78 #define BAND_11G 0x04
79 #define BAND_11A_TURBO 0x08
80 #define BAND_SUPERG 0x10
81 #define BAND_PUBLIC_SAFETY 0x20 /* 4.99 GHz public safety */
82 #define BAND_11N_5GHZ 0x40
83 #define BAND_11N_2_4GHZ 0x80
85 static bool commview_ncf_read(wtap *wth, wtap_rec *rec, Buffer *buf,
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 Buffer *buf, 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 const uint8_t *pd, int *err, char **err_info);
95 static int commview_ncf_file_type_subtype = -1;
96 static int commview_ncfx_file_type_subtype = -1;
98 void register_commview(void);
100 wtap_open_return_val
101 commview_ncf_open(wtap *wth, int *err, char **err_info)
103 commview_ncf_header_t cv_hdr;
105 if(!commview_ncf_read_header(&cv_hdr, wth->fh, err, err_info)) {
106 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
107 return WTAP_OPEN_ERROR;
108 return WTAP_OPEN_NOT_MINE;
111 /* If any of these fields do not match what we expect, bail out. */
112 if(cv_hdr.version != 0 ||
113 cv_hdr.year < 1970 || cv_hdr.year >= 2038 ||
114 cv_hdr.month < 1 || cv_hdr.month > 12 ||
115 cv_hdr.day < 1 || cv_hdr.day > 31 ||
116 cv_hdr.hours > 23 ||
117 cv_hdr.minutes > 59 ||
118 cv_hdr.seconds > 60 ||
119 cv_hdr.signal_level_percent > 100 ||
120 (cv_hdr.flags & FLAGS_RESERVED) != 0 ||
121 ((cv_hdr.flags & FLAGS_MEDIUM) != MEDIUM_ETHERNET &&
122 (cv_hdr.flags & FLAGS_MEDIUM) != MEDIUM_WIFI &&
123 (cv_hdr.flags & FLAGS_MEDIUM) != MEDIUM_TOKEN_RING))
124 return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
126 /* No file header. Reset the fh to 0 so we can read the first packet */
127 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
128 return WTAP_OPEN_ERROR;
130 /* Set up the pointers to the handlers for this file type */
131 wth->subtype_read = commview_ncf_read;
132 wth->subtype_seek_read = commview_ncf_seek_read;
134 wth->file_type_subtype = commview_ncf_file_type_subtype;
135 wth->file_encap = WTAP_ENCAP_PER_PACKET;
136 wth->file_tsprec = WTAP_TSPREC_USEC;
138 return WTAP_OPEN_MINE; /* Our kind of file */
141 static int
142 commview_ncf_read_packet(FILE_T fh, wtap_rec *rec, Buffer *buf,
143 int *err, char **err_info)
145 commview_ncf_header_t cv_hdr;
146 struct tm tm;
147 unsigned frequency;
149 if(!commview_ncf_read_header(&cv_hdr, fh, err, err_info))
150 return false;
152 * The maximum value of cv_hdr.data_len is 65535, which is less
153 * than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to
154 * check it.
157 switch(cv_hdr.flags & FLAGS_MEDIUM) {
159 case MEDIUM_ETHERNET :
160 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETHERNET;
161 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1; /* Unknown */
162 break;
164 case MEDIUM_WIFI :
165 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
166 memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
167 rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = -1; /* Unknown */
168 rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = false;
169 rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = false;
170 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
171 switch (cv_hdr.band) {
173 case BAND_11A:
174 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
175 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_channel_type = false;
176 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = true;
177 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.turbo_type =
178 PHDR_802_11A_TURBO_TYPE_NORMAL;
179 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, false);
180 break;
182 case BAND_11B:
183 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
184 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
185 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
186 break;
188 case BAND_11G:
189 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
190 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = true;
191 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.mode =
192 PHDR_802_11G_MODE_NORMAL;
193 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
194 break;
196 case BAND_11A_TURBO:
197 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
198 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type = true;
199 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.turbo_type =
200 PHDR_802_11A_TURBO_TYPE_TURBO;
201 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, false);
202 break;
204 case BAND_SUPERG:
205 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
206 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode = true;
207 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.mode =
208 PHDR_802_11G_MODE_SUPER_G;
209 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
210 break;
212 case BAND_11N_5GHZ:
213 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11N;
214 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, false);
215 break;
217 case BAND_11N_2_4GHZ:
218 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11N;
219 frequency = ieee80211_chan_to_mhz(cv_hdr.channel, true);
220 break;
222 case BAND_PUBLIC_SAFETY:
224 * XXX - what do we do here? What are the channel
225 * numbers? How do we distinguish the several
226 * different flavors of 4.9 GHz frequencies?
228 frequency = 0;
229 break;
231 default:
232 frequency = 0;
233 break;
235 if (frequency != 0) {
236 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency = true;
237 rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency = frequency;
239 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = true;
240 rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = cv_hdr.channel;
242 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = true;
243 rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate =
244 cv_hdr.rate | (cv_hdr.direction << 8);
246 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = true;
247 rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = cv_hdr.signal_level_percent;
250 * XXX - these are positive in captures I've seen; does
251 * that mean that they are the negative of the actual
252 * dBm value? (80 dBm is a bit more power than most
253 * countries' regulatory agencies are likely to allow
254 * any individual to have in their home. :-))
256 * XXX - sometimes these are 0; assume that means that no
257 * value is provided.
259 if (cv_hdr.signal_level_dbm != 0) {
260 rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm = -cv_hdr.signal_level_dbm;
261 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm = true;
263 if (cv_hdr.noise_level_dbm != 0) {
264 rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm = -cv_hdr.noise_level_dbm;
265 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm = true;
267 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_UNKNOWN) {
269 * We don't know they PHY, but we do have the
270 * data rate; try to guess it based on the
271 * data rate and center frequency.
273 if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
274 /* 11b */
275 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
276 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
277 } else if (RATE_IS_OFDM(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
278 /* 11a or 11g, depending on the band. */
279 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency) {
280 if (FREQ_IS_BG(rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency)) {
281 /* 11g */
282 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
283 } else {
284 /* 11a */
285 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
289 } else if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_11G) {
290 if (RATE_IS_DSSS(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate)) {
291 /* DSSS, so 11b. */
292 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
293 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11b.has_short_preamble = false;
296 break;
298 case MEDIUM_TOKEN_RING :
299 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_TOKEN_RING;
300 break;
302 default :
303 *err = WTAP_ERR_BAD_FILE;
304 *err_info = ws_strdup_printf("commview: unsupported encap for NCF: %u",
305 cv_hdr.flags & FLAGS_MEDIUM);
306 return false;
309 tm.tm_year = cv_hdr.year - 1900;
310 tm.tm_mon = cv_hdr.month - 1;
311 tm.tm_mday = cv_hdr.day;
312 tm.tm_hour = cv_hdr.hours;
313 tm.tm_min = cv_hdr.minutes;
314 tm.tm_sec = cv_hdr.seconds;
315 tm.tm_isdst = -1;
317 rec->rec_type = REC_TYPE_PACKET;
318 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
319 rec->presence_flags = WTAP_HAS_TS;
321 rec->rec_header.packet_header.len = cv_hdr.data_len;
322 rec->rec_header.packet_header.caplen = cv_hdr.data_len;
324 rec->ts.secs = mktime(&tm);
325 rec->ts.nsecs = cv_hdr.usecs * 1000;
327 return wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info);
330 static bool
331 commview_ncf_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
332 char **err_info, int64_t *data_offset)
334 *data_offset = file_tell(wth->fh);
336 return commview_ncf_read_packet(wth->fh, rec, buf, err, err_info);
339 static bool
340 commview_ncf_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
341 Buffer *buf, int *err, char **err_info)
343 if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
344 return false;
346 return commview_ncf_read_packet(wth->random_fh, rec, buf, err, err_info);
349 static bool
350 commview_ncf_read_header(commview_ncf_header_t *cv_hdr, FILE_T fh, int *err,
351 char **err_info)
353 if (!wtap_read_bytes_or_eof(fh, &cv_hdr->data_len, 2, err, err_info))
354 return false;
355 if (!wtap_read_bytes(fh, &cv_hdr->source_data_len, 2, err, err_info))
356 return false;
357 if (!wtap_read_bytes(fh, &cv_hdr->version, 1, err, err_info))
358 return false;
359 if (!wtap_read_bytes(fh, &cv_hdr->year, 2, err, err_info))
360 return false;
361 if (!wtap_read_bytes(fh, &cv_hdr->month, 1, err, err_info))
362 return false;
363 if (!wtap_read_bytes(fh, &cv_hdr->day, 1, err, err_info))
364 return false;
365 if (!wtap_read_bytes(fh, &cv_hdr->hours, 1, err, err_info))
366 return false;
367 if (!wtap_read_bytes(fh, &cv_hdr->minutes, 1, err, err_info))
368 return false;
369 if (!wtap_read_bytes(fh, &cv_hdr->seconds, 1, err, err_info))
370 return false;
371 if (!wtap_read_bytes(fh, &cv_hdr->usecs, 4, err, err_info))
372 return false;
373 if (!wtap_read_bytes(fh, &cv_hdr->flags, 1, err, err_info))
374 return false;
375 if (!wtap_read_bytes(fh, &cv_hdr->signal_level_percent, 1, err, err_info))
376 return false;
377 if (!wtap_read_bytes(fh, &cv_hdr->rate, 1, err, err_info))
378 return false;
379 if (!wtap_read_bytes(fh, &cv_hdr->band, 1, err, err_info))
380 return false;
381 if (!wtap_read_bytes(fh, &cv_hdr->channel, 1, err, err_info))
382 return false;
383 if (!wtap_read_bytes(fh, &cv_hdr->direction, 1, err, err_info))
384 return false;
385 if (!wtap_read_bytes(fh, &cv_hdr->signal_level_dbm, 1, err, err_info))
386 return false;
387 if (!wtap_read_bytes(fh, &cv_hdr->noise_level_dbm, 1, err, err_info))
388 return false;
390 /* Convert multi-byte values from little endian to host endian format */
391 cv_hdr->data_len = GUINT16_FROM_LE(cv_hdr->data_len);
392 cv_hdr->source_data_len = GUINT16_FROM_LE(cv_hdr->source_data_len);
393 cv_hdr->year = GUINT16_FROM_LE(cv_hdr->year);
394 cv_hdr->usecs = GUINT32_FROM_LE(cv_hdr->usecs);
396 return true;
399 /* Returns 0 if we can write out the specified encapsulation type
400 * into a CommView format file. */
401 static int
402 commview_ncf_dump_can_write_encap(int encap)
404 switch (encap) {
406 case WTAP_ENCAP_ETHERNET :
407 case WTAP_ENCAP_IEEE_802_11 :
408 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
409 case WTAP_ENCAP_TOKEN_RING :
410 case WTAP_ENCAP_PER_PACKET :
411 return 0;
413 default:
414 return WTAP_ERR_UNWRITABLE_ENCAP;
418 /* Returns true on success, false on failure;
419 sets "*err" to an error code on failure */
420 static bool
421 commview_ncf_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_)
423 wdh->subtype_write = commview_ncf_dump;
425 /* There is no file header to write out */
426 return true;
429 /* Write a record for a packet to a dump file.
430 * Returns true on success, false on failure. */
431 static bool
432 commview_ncf_dump(wtap_dumper *wdh, const wtap_rec *rec, const uint8_t *pd,
433 int *err, char **err_info _U_)
435 commview_ncf_header_t cv_hdr = {0};
436 struct tm *tm;
438 /* We can only write packet records. */
439 if (rec->rec_type != REC_TYPE_PACKET) {
440 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
441 return false;
444 /* Don't write out anything bigger than we can read.
445 * (The length field in packet headers is 16 bits, which
446 * imposes a hard limit.) */
447 if (rec->rec_header.packet_header.caplen > 65535) {
448 *err = WTAP_ERR_PACKET_TOO_LARGE;
449 return false;
452 cv_hdr.data_len = GUINT16_TO_LE((uint16_t)rec->rec_header.packet_header.caplen);
453 cv_hdr.source_data_len = GUINT16_TO_LE((uint16_t)rec->rec_header.packet_header.caplen);
454 cv_hdr.version = 0;
456 tm = localtime(&rec->ts.secs);
457 if (tm != NULL) {
458 cv_hdr.year = GUINT16_TO_LE(tm->tm_year + 1900);
459 cv_hdr.month = tm->tm_mon + 1;
460 cv_hdr.day = tm->tm_mday;
461 cv_hdr.hours = tm->tm_hour;
462 cv_hdr.minutes = tm->tm_min;
463 cv_hdr.seconds = tm->tm_sec;
464 cv_hdr.usecs = GUINT32_TO_LE(rec->ts.nsecs / 1000);
465 } else {
467 * Second before the Epoch.
469 cv_hdr.year = GUINT16_TO_LE(1969);
470 cv_hdr.month = 12;
471 cv_hdr.day = 31;
472 cv_hdr.hours = 23;
473 cv_hdr.minutes = 59;
474 cv_hdr.seconds = 59;
475 cv_hdr.usecs = 0;
478 switch(rec->rec_header.packet_header.pkt_encap) {
480 case WTAP_ENCAP_ETHERNET :
481 cv_hdr.flags |= MEDIUM_ETHERNET;
482 break;
484 case WTAP_ENCAP_IEEE_802_11 :
485 cv_hdr.flags |= MEDIUM_WIFI;
486 break;
488 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
489 cv_hdr.flags |= MEDIUM_WIFI;
491 switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy) {
493 case PHDR_802_11_PHY_11A:
495 * If we don't know whether it's turbo, say it's
496 * not.
498 if (!rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.has_turbo_type ||
499 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11a.turbo_type == PHDR_802_11A_TURBO_TYPE_NORMAL)
500 cv_hdr.band = BAND_11A;
501 else
502 cv_hdr.band = BAND_11A_TURBO;
503 break;
505 case PHDR_802_11_PHY_11B:
506 cv_hdr.band = BAND_11B;
507 break;
509 case PHDR_802_11_PHY_11G:
511 * If we don't know whether it's Super G, say it's
512 * not.
514 if (!rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.has_mode)
515 cv_hdr.band = BAND_11G;
516 else {
517 switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11g.mode) {
519 case PHDR_802_11G_MODE_NORMAL:
520 cv_hdr.band = BAND_11G;
521 break;
523 case PHDR_802_11G_MODE_SUPER_G:
524 cv_hdr.band = BAND_SUPERG;
525 break;
527 default:
528 cv_hdr.band = BAND_11G;
529 break;
532 break;
534 case PHDR_802_11_PHY_11N:
536 * Pick the band based on the frequency.
538 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency) {
539 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency > 2484) {
540 /* 5 GHz band */
541 cv_hdr.band = BAND_11N_5GHZ;
542 } else {
543 /* 2.4 GHz band */
544 cv_hdr.band = BAND_11N_2_4GHZ;
546 } else {
547 /* Band is unknown. */
548 cv_hdr.band = 0;
550 break;
552 default:
554 * It's not documented how they handle 11ac,
555 * and they don't support the older PHYs.
557 cv_hdr.band = 0;
558 break;
560 cv_hdr.channel =
561 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel ?
562 rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel :
564 cv_hdr.rate =
565 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate ?
566 (uint8_t)(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate & 0xFF) :
568 cv_hdr.direction =
569 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate ?
570 (uint8_t)((rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate >> 8) & 0xFF) :
572 cv_hdr.signal_level_percent =
573 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent ?
574 rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent :
576 cv_hdr.signal_level_dbm =
577 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm ?
578 -rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm :
580 cv_hdr.noise_level_dbm =
581 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm ?
582 -rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm :
584 break;
586 case WTAP_ENCAP_TOKEN_RING :
587 cv_hdr.flags |= MEDIUM_TOKEN_RING;
588 break;
590 default :
591 *err = WTAP_ERR_UNWRITABLE_ENCAP;
592 return false;
595 if (!wtap_dump_file_write(wdh, &cv_hdr.data_len, 2, err))
596 return false;
597 if (!wtap_dump_file_write(wdh, &cv_hdr.source_data_len, 2, err))
598 return false;
599 if (!wtap_dump_file_write(wdh, &cv_hdr.version, 1, err))
600 return false;
601 if (!wtap_dump_file_write(wdh, &cv_hdr.year, 2, err))
602 return false;
603 if (!wtap_dump_file_write(wdh, &cv_hdr.month, 1, err))
604 return false;
605 if (!wtap_dump_file_write(wdh, &cv_hdr.day, 1, err))
606 return false;
607 if (!wtap_dump_file_write(wdh, &cv_hdr.hours, 1, err))
608 return false;
609 if (!wtap_dump_file_write(wdh, &cv_hdr.minutes, 1, err))
610 return false;
611 if (!wtap_dump_file_write(wdh, &cv_hdr.seconds, 1, err))
612 return false;
613 if (!wtap_dump_file_write(wdh, &cv_hdr.usecs, 4, err))
614 return false;
615 if (!wtap_dump_file_write(wdh, &cv_hdr.flags, 1, err))
616 return false;
617 if (!wtap_dump_file_write(wdh, &cv_hdr.signal_level_percent, 1, err))
618 return false;
619 if (!wtap_dump_file_write(wdh, &cv_hdr.rate, 1, err))
620 return false;
621 if (!wtap_dump_file_write(wdh, &cv_hdr.band, 1, err))
622 return false;
623 if (!wtap_dump_file_write(wdh, &cv_hdr.channel, 1, err))
624 return false;
625 if (!wtap_dump_file_write(wdh, &cv_hdr.direction, 1, err))
626 return false;
627 if (!wtap_dump_file_write(wdh, &cv_hdr.signal_level_dbm, 1, err))
628 return false;
629 if (!wtap_dump_file_write(wdh, &cv_hdr.noise_level_dbm, 1, err))
630 return false;
631 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
632 return false;
633 return true;
636 typedef struct commview_ncfx_header {
637 uint32_t data_len;
638 uint16_t year;
639 uint8_t month;
640 uint8_t day;
641 uint8_t hours;
642 uint8_t minutes;
643 uint8_t seconds;
644 uint32_t usecs;
645 uint8_t medium_type;
646 uint8_t decryption_flag;
647 uint8_t direction;
648 uint8_t reserved1;
649 uint8_t reserved2;
650 } commview_ncfx_header_t;
652 #define COMMVIEW_NCFX_HEADER_SIZE 20
654 typedef struct commview_ncfx_rf_header {
655 uint16_t header_len; /* includes extension headers */
656 uint16_t status_modulation;
657 uint16_t frequency_band;
658 uint16_t channel;
659 uint8_t noise_level_dbm; /* abs(noise in dBm) */
660 uint8_t signal_level_dbm; /* abs(signal in dBm) */
661 uint8_t signal_level_percent;
662 uint8_t reserved;
663 uint32_t phy_rate; /* in 100Kbps units */
664 uint32_t extensions_present;
665 } commview_ncfx_rf_header_t;
667 #define COMMVIEW_NCFX_RF_HEADER_SIZE 20
669 typedef struct commview_ncfx_mcs_header {
670 uint8_t mcs_index;
671 uint8_t n_streams;
672 uint8_t channel_width;
673 uint8_t guard_interval;
674 } commview_ncfx_mcs_header_t;
676 #define COMMVIEW_NCFX_MCS_HEADER_SIZE 4
679 * Bit-field positions for various fields in the status_modulation variable
680 * of the header.
682 #define STATUS_MODULATION_BAD_FCS 0x01
683 #define STATUS_MODULATION_HT_PHY 0x02
684 #define STATUS_MODULATION_VHT_PHY 0x04
685 #define STATUS_MODULATION_HE_PHY 0x08
686 #define STATUS_MODULATION_HE_OFDMA 0x10
688 /* Values for the frequency_band variable of the header */
689 #define BAND_5GHZ 0x40
690 #define BAND_2_4GHZ 0x80
692 /* Presence bits */
693 #define PRESENCE_MCS_HEADER 0x00000001 /* type 0, bit 0 */
695 static bool commview_ncfx_read(wtap *wth, wtap_rec *rec, Buffer *buf,
696 int *err, char **err_info, int64_t *data_offset);
697 static bool commview_ncfx_seek_read(wtap *wth, int64_t seek_off,
698 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
699 static bool commview_ncfx_read_header(commview_ncfx_header_t *cv_hdr,
700 FILE_T fh, int *err, char **err_info);
701 static bool commview_ncfx_read_rf_header(commview_ncfx_rf_header_t *cv_rf_hdr,
702 FILE_T fh, int *err, char **err_info);
703 static bool commview_ncfx_read_mcs_header(commview_ncfx_mcs_header_t *cv_mcs_hdr,
704 FILE_T fh, int *err, char **err_info);
705 static bool commview_ncfx_dump(wtap_dumper *wdh, const wtap_rec *rec,
706 const uint8_t *pd, int *err, char **err_info);
708 wtap_open_return_val
709 commview_ncfx_open(wtap *wth, int *err, char **err_info)
711 commview_ncfx_header_t cv_hdr;
713 if(!commview_ncfx_read_header(&cv_hdr, wth->fh, err, err_info)) {
714 if (*err == 0) {
715 /* EOF - not our file */
716 return WTAP_OPEN_NOT_MINE;
718 if (*err == WTAP_ERR_SHORT_READ) {
719 /* Short read - not our file */
720 return WTAP_OPEN_NOT_MINE;
722 if (*err == WTAP_ERR_BAD_FILE) {
724 * Not a valid record header - not our file;
725 * discard the error.
727 wmem_free(NULL, *err_info);
728 *err_info = NULL;
729 return WTAP_OPEN_NOT_MINE;
731 /* Hard error. */
732 return WTAP_OPEN_ERROR;
735 /* If any of these fields do not match what we expect, bail out. */
736 if(cv_hdr.year < 2000 || /* XXX - when was this format introduced? */
737 cv_hdr.month < 1 || cv_hdr.month > 12 ||
738 cv_hdr.day < 1 || cv_hdr.day > 31 ||
739 cv_hdr.hours > 23 ||
740 cv_hdr.minutes > 59 ||
741 cv_hdr.seconds > 60)
742 return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
743 switch (cv_hdr.medium_type) {
745 case MEDIUM_ETHERNET:
746 if (cv_hdr.direction != 0x00 &&
747 cv_hdr.direction != 0x01 &&
748 cv_hdr.direction != 0x02)
749 return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
750 break;
752 case MEDIUM_WIFI:
753 if (cv_hdr.decryption_flag != 0x00 &&
754 cv_hdr.decryption_flag != 0x01)
755 return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
756 if (cv_hdr.direction != 0x00)
757 return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
758 break;
760 default:
761 return WTAP_OPEN_NOT_MINE; /* Not our kind of file */
764 /* No file header. Reset the fh to 0 so we can read the first packet */
765 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
766 return WTAP_OPEN_ERROR;
768 /* Set up the pointers to the handlers for this file type */
769 wth->subtype_read = commview_ncfx_read;
770 wth->subtype_seek_read = commview_ncfx_seek_read;
772 wth->file_type_subtype = commview_ncfx_file_type_subtype;
773 wth->file_encap = WTAP_ENCAP_PER_PACKET;
774 wth->file_tsprec = WTAP_TSPREC_USEC;
776 return WTAP_OPEN_MINE; /* Our kind of file */
779 static int
780 commview_ncfx_read_packet(FILE_T fh, wtap_rec *rec, Buffer *buf,
781 int *err, char **err_info)
783 commview_ncfx_header_t cv_hdr;
784 uint32_t length_remaining;
785 struct tm tm;
786 commview_ncfx_rf_header_t cv_rf_hdr;
787 unsigned frequency;
788 commview_ncfx_mcs_header_t cv_mcs_hdr;
790 if (!commview_ncfx_read_header(&cv_hdr, fh, err, err_info))
791 return false;
793 /* Amount of data remaining in the record, after the header */
794 length_remaining = cv_hdr.data_len - COMMVIEW_NCFX_HEADER_SIZE;
796 switch(cv_hdr.medium_type) {
798 case MEDIUM_ETHERNET :
799 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETHERNET;
800 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1; /* Unknown */
801 break;
803 case MEDIUM_WIFI :
804 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
805 memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
806 rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = 0; /* No FCS */
807 rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = (cv_hdr.decryption_flag == 0x01);
808 rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = false;
811 * Make sure we have enough data left for the RF header.
813 if (length_remaining < COMMVIEW_NCFX_RF_HEADER_SIZE) {
814 *err = WTAP_ERR_BAD_FILE;
815 *err_info = ws_strdup_printf("commview: RF header goes past the NCFX data length %u",
816 cv_hdr.data_len);
817 return false;
819 length_remaining -= COMMVIEW_NCFX_RF_HEADER_SIZE;
822 * Read the RF header.
824 if (!commview_ncfx_read_rf_header(&cv_rf_hdr, fh, err, err_info))
825 return false;
826 if (cv_rf_hdr.status_modulation & STATUS_MODULATION_HE_PHY)
827 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11AX;
828 else if (cv_rf_hdr.status_modulation & STATUS_MODULATION_VHT_PHY)
829 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11AC;
830 else if (cv_rf_hdr.status_modulation & STATUS_MODULATION_HT_PHY)
831 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11N;
832 else {
834 * Unknown PHY, for now.
836 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
838 switch (cv_rf_hdr.frequency_band) {
840 case BAND_5GHZ:
841 frequency = ieee80211_chan_to_mhz(cv_rf_hdr.channel, false);
842 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_UNKNOWN) {
844 * None of the modulation bits were set, so
845 * this is presumably the 11a OFDM PHY.
847 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11A;
849 break;
851 case BAND_2_4GHZ:
852 frequency = ieee80211_chan_to_mhz(cv_rf_hdr.channel, true);
853 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy == PHDR_802_11_PHY_UNKNOWN) {
855 * None of the modulation bits were set, so
856 * guess the PHY based on the data rate.
858 * cv_rf_hdr.phy_rate is in units of 100
859 * Kbits/s.
861 if (cv_rf_hdr.phy_rate == 10 /* 1 Mb/s */ ||
862 cv_rf_hdr.phy_rate == 20 /* 2 Mb/s */ ||
863 cv_rf_hdr.phy_rate == 55 /* 5.5 Mb/s */ ||
864 cv_rf_hdr.phy_rate == 110 /* 11 Mb/s */ ||
865 cv_rf_hdr.phy_rate == 220 /* 22 Mb/s */ ||
866 cv_rf_hdr.phy_rate == 330 /* 33 Mb/s */)
867 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11B;
868 else
869 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_11G;
871 break;
873 default:
874 frequency = 0;
875 break;
877 if (frequency != 0) {
878 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency = true;
879 rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency = frequency;
881 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel = true;
882 rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel = cv_rf_hdr.channel;
885 * cv_rf_hdr.phy_rate is in units of 100 Kbits/s.
887 * pseudo_header.ieee_802_11.data_rate is in units of 500
888 * Kbits/s.
890 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate = true;
891 rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate =
892 cv_rf_hdr.phy_rate/5;
894 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent = true;
895 rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent = cv_rf_hdr.signal_level_percent;
898 * These is the absolute value of the signal and noise,
899 * in dBm. The value is the negative of that.
901 * XXX - sometimes these are 0; assume that means that no
902 * value is provided.
904 if (cv_rf_hdr.signal_level_dbm != 0) {
905 rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm = -cv_rf_hdr.signal_level_dbm;
906 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm = true;
908 if (cv_rf_hdr.noise_level_dbm != 0) {
909 rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm = -cv_rf_hdr.noise_level_dbm;
910 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm = true;
913 if (cv_rf_hdr.extensions_present & PRESENCE_MCS_HEADER) {
915 * Make sure we have enough data left for the
916 * MCS header.
918 if (length_remaining < COMMVIEW_NCFX_MCS_HEADER_SIZE) {
919 *err = WTAP_ERR_BAD_FILE;
920 *err_info = ws_strdup_printf("commview: MCS header goes past the NCFX data length %u",
921 cv_hdr.data_len);
922 return false;
924 length_remaining -= COMMVIEW_NCFX_MCS_HEADER_SIZE;
927 * Read the MCS header.
929 if (!commview_ncfx_read_mcs_header(&cv_mcs_hdr, fh,
930 err, err_info))
931 return false;
932 switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy) {
934 case PHDR_802_11_PHY_11N:
935 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.has_mcs_index = true;
936 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.mcs_index = cv_mcs_hdr.mcs_index;
937 /* number of STBC streams? */
938 switch (cv_mcs_hdr.channel_width) {
940 case 0x00:
941 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.has_bandwidth = true;
942 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.bandwidth = PHDR_802_11_BANDWIDTH_20_MHZ;
943 break;
945 case 0x01:
946 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.has_bandwidth = true;
947 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11n.bandwidth = PHDR_802_11_BANDWIDTH_40_MHZ;
948 break;
950 default:
951 break;
953 /* Guard interval? */
954 break;
956 case PHDR_802_11_PHY_11AC:
957 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[0] = cv_mcs_hdr.mcs_index;
958 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[1] = 0;
959 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[2] = 0;
960 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.mcs[3] = 0;
961 /* Remaining MCS indices? */
962 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.nss[0] = cv_mcs_hdr.n_streams;
963 switch (cv_mcs_hdr.channel_width) {
965 case 0x00:
966 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.has_bandwidth = true;
967 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.bandwidth = PHDR_802_11_BANDWIDTH_20_MHZ;
968 break;
970 case 0x01:
971 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.has_bandwidth = true;
972 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.bandwidth = PHDR_802_11_BANDWIDTH_40_MHZ;
973 break;
975 case 0x02:
976 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.has_bandwidth = true;
977 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ac.bandwidth = PHDR_802_11_BANDWIDTH_80_MHZ;
978 break;
980 default:
981 break;
983 /* Guard interval? */
984 break;
986 case PHDR_802_11_PHY_11AX:
987 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ax.has_mcs_index = true;
988 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ax.mcs = cv_mcs_hdr.mcs_index;
989 rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy_info.info_11ax.nsts = cv_mcs_hdr.n_streams;
990 /* Bandwidth stuff? */
991 /* Guard interval? */
992 break;
994 default:
995 break;
998 break;
1000 default :
1001 *err = WTAP_ERR_BAD_FILE;
1002 *err_info = ws_strdup_printf("commview: unsupported encap for NCFX: %u",
1003 cv_hdr.medium_type);
1004 return false;
1007 tm.tm_year = cv_hdr.year - 1900;
1008 tm.tm_mon = cv_hdr.month - 1;
1009 tm.tm_mday = cv_hdr.day;
1010 tm.tm_hour = cv_hdr.hours;
1011 tm.tm_min = cv_hdr.minutes;
1012 tm.tm_sec = cv_hdr.seconds;
1013 tm.tm_isdst = -1;
1015 rec->rec_type = REC_TYPE_PACKET;
1016 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
1017 rec->presence_flags = WTAP_HAS_TS;
1019 if (length_remaining > WTAP_MAX_PACKET_SIZE_STANDARD) {
1021 * Probably a corrupt capture file; don't blow up trying
1022 * to allocate space for an immensely-large packet.
1024 *err = WTAP_ERR_BAD_FILE;
1025 *err_info = ws_strdup_printf("commview: File has %u-byte packet, bigger than maximum of %u",
1026 length_remaining, WTAP_MAX_PACKET_SIZE_STANDARD);
1027 return false;
1030 rec->rec_header.packet_header.len = length_remaining;
1031 rec->rec_header.packet_header.caplen = length_remaining;
1033 rec->ts.secs = mktime(&tm);
1034 rec->ts.nsecs = cv_hdr.usecs * 1000;
1036 return wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info);
1039 static bool
1040 commview_ncfx_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
1041 char **err_info, int64_t *data_offset)
1043 *data_offset = file_tell(wth->fh);
1045 return commview_ncfx_read_packet(wth->fh, rec, buf, err, err_info);
1048 static bool
1049 commview_ncfx_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
1050 Buffer *buf, int *err, char **err_info)
1052 if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1053 return false;
1055 return commview_ncfx_read_packet(wth->random_fh, rec, buf, err, err_info);
1058 static bool
1059 commview_ncfx_read_header(commview_ncfx_header_t *cv_hdr, FILE_T fh, int *err,
1060 char **err_info)
1062 if (!wtap_read_bytes_or_eof(fh, &cv_hdr->data_len, 4, err, err_info))
1063 return false;
1065 /* Convert data length from little endian to host endian format */
1066 cv_hdr->data_len = GUINT32_FROM_LE(cv_hdr->data_len);
1068 /* It must be at least the length of the general header. */
1069 if (cv_hdr->data_len < COMMVIEW_NCFX_HEADER_SIZE) {
1070 *err = WTAP_ERR_BAD_FILE;
1071 *err_info = ws_strdup_printf("commview: NCFX data length %u < %u",
1072 cv_hdr->data_len,
1073 COMMVIEW_NCFX_HEADER_SIZE);
1074 return false;
1077 if (!wtap_read_bytes(fh, &cv_hdr->year, 2, err, err_info))
1078 return false;
1079 if (!wtap_read_bytes(fh, &cv_hdr->month, 1, err, err_info))
1080 return false;
1081 if (!wtap_read_bytes(fh, &cv_hdr->day, 1, err, err_info))
1082 return false;
1083 if (!wtap_read_bytes(fh, &cv_hdr->hours, 1, err, err_info))
1084 return false;
1085 if (!wtap_read_bytes(fh, &cv_hdr->minutes, 1, err, err_info))
1086 return false;
1087 if (!wtap_read_bytes(fh, &cv_hdr->seconds, 1, err, err_info))
1088 return false;
1089 if (!wtap_read_bytes(fh, &cv_hdr->usecs, 4, err, err_info))
1090 return false;
1091 if (!wtap_read_bytes(fh, &cv_hdr->medium_type, 1, err, err_info))
1092 return false;
1093 if (!wtap_read_bytes(fh, &cv_hdr->decryption_flag, 1, err, err_info))
1094 return false;
1095 if (!wtap_read_bytes(fh, &cv_hdr->direction, 1, err, err_info))
1096 return false;
1097 if (!wtap_read_bytes(fh, &cv_hdr->reserved1, 1, err, err_info))
1098 return false;
1099 if (!wtap_read_bytes(fh, &cv_hdr->reserved2, 1, err, err_info))
1100 return false;
1102 /* Convert multi-byte values from little endian to host endian format */
1103 cv_hdr->year = GUINT16_FROM_LE(cv_hdr->year);
1104 cv_hdr->usecs = GUINT32_FROM_LE(cv_hdr->usecs);
1106 return true;
1109 static bool
1110 commview_ncfx_read_rf_header(commview_ncfx_rf_header_t *cv_rf_hdr, FILE_T fh,
1111 int *err, char **err_info)
1113 if (!wtap_read_bytes(fh, &cv_rf_hdr->header_len, 2, err, err_info))
1114 return false;
1116 /* Convert header length from little endian to host endian format */
1117 cv_rf_hdr->header_len = GUINT16_FROM_LE(cv_rf_hdr->header_len);
1119 if (!wtap_read_bytes(fh, &cv_rf_hdr->status_modulation, 2, err, err_info))
1120 return false;
1121 if (!wtap_read_bytes(fh, &cv_rf_hdr->frequency_band, 2, err, err_info))
1122 return false;
1123 if (!wtap_read_bytes(fh, &cv_rf_hdr->channel, 2, err, err_info))
1124 return false;
1125 if (!wtap_read_bytes(fh, &cv_rf_hdr->noise_level_dbm, 1, err, err_info))
1126 return false;
1127 if (!wtap_read_bytes(fh, &cv_rf_hdr->signal_level_dbm, 1, err, err_info))
1128 return false;
1129 if (!wtap_read_bytes(fh, &cv_rf_hdr->signal_level_percent, 1, err, err_info))
1130 return false;
1131 if (!wtap_read_bytes(fh, &cv_rf_hdr->reserved, 1, err, err_info))
1132 return false;
1133 if (!wtap_read_bytes(fh, &cv_rf_hdr->phy_rate, 4, err, err_info))
1134 return false;
1135 if (!wtap_read_bytes(fh, &cv_rf_hdr->extensions_present, 4, err, err_info))
1136 return false;
1138 /* Convert remaining multi-byte values from little endian to host endian format */
1139 cv_rf_hdr->status_modulation = GUINT16_FROM_LE(cv_rf_hdr->status_modulation);
1140 cv_rf_hdr->frequency_band = GUINT16_FROM_LE(cv_rf_hdr->frequency_band);
1141 cv_rf_hdr->channel = GUINT16_FROM_LE(cv_rf_hdr->channel);
1142 cv_rf_hdr->phy_rate = GUINT32_FROM_LE(cv_rf_hdr->phy_rate);
1143 cv_rf_hdr->extensions_present = GUINT32_FROM_LE(cv_rf_hdr->extensions_present);
1145 return true;
1148 static bool
1149 commview_ncfx_read_mcs_header(commview_ncfx_mcs_header_t *cv_mcs_hdr, FILE_T fh,
1150 int *err, char **err_info)
1152 if (!wtap_read_bytes(fh, &cv_mcs_hdr->mcs_index, 1, err, err_info))
1153 return false;
1154 if (!wtap_read_bytes(fh, &cv_mcs_hdr->n_streams, 1, err, err_info))
1155 return false;
1156 if (!wtap_read_bytes(fh, &cv_mcs_hdr->channel_width, 1, err, err_info))
1157 return false;
1158 if (!wtap_read_bytes(fh, &cv_mcs_hdr->guard_interval, 1, err, err_info))
1159 return false;
1161 return true;
1164 /* Returns 0 if we can write out the specified encapsulation type
1165 * into a CommView format file. */
1166 static int
1167 commview_ncfx_dump_can_write_encap(int encap)
1169 switch (encap) {
1171 case WTAP_ENCAP_ETHERNET :
1172 case WTAP_ENCAP_IEEE_802_11 :
1173 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
1174 case WTAP_ENCAP_PER_PACKET :
1175 return 0;
1177 default:
1178 return WTAP_ERR_UNWRITABLE_ENCAP;
1182 /* Returns true on success, false on failure;
1183 sets "*err" to an error code on failure */
1184 static bool
1185 commview_ncfx_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_)
1187 wdh->subtype_write = commview_ncfx_dump;
1189 /* There is no file header to write out */
1190 return true;
1193 /* Write a record for a packet to a dump file.
1194 * Returns true on success, false on failure. */
1195 static bool
1196 commview_ncfx_dump(wtap_dumper *wdh, const wtap_rec *rec, const uint8_t *pd,
1197 int *err, char **err_info _U_)
1199 commview_ncfx_header_t cv_hdr = {0};
1200 struct tm *tm;
1202 /* We can only write packet records. */
1203 if (rec->rec_type != REC_TYPE_PACKET) {
1204 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
1205 return false;
1208 /* Don't write out anything bigger than we can read.
1209 * (The length field in packet headers is 16 bits, which
1210 * imposes a hard limit.) */
1211 if (rec->rec_header.packet_header.caplen > 65535) {
1212 *err = WTAP_ERR_PACKET_TOO_LARGE;
1213 return false;
1216 cv_hdr.data_len = GUINT32_TO_LE((uint32_t)rec->rec_header.packet_header.caplen);
1218 tm = localtime(&rec->ts.secs);
1219 if (tm != NULL) {
1220 cv_hdr.year = GUINT16_TO_LE(tm->tm_year + 1900);
1221 cv_hdr.month = tm->tm_mon + 1;
1222 cv_hdr.day = tm->tm_mday;
1223 cv_hdr.hours = tm->tm_hour;
1224 cv_hdr.minutes = tm->tm_min;
1225 cv_hdr.seconds = tm->tm_sec;
1226 cv_hdr.usecs = GUINT32_TO_LE(rec->ts.nsecs / 1000);
1227 } else {
1229 * Second before the Epoch.
1231 cv_hdr.year = GUINT16_TO_LE(1969);
1232 cv_hdr.month = 12;
1233 cv_hdr.day = 31;
1234 cv_hdr.hours = 23;
1235 cv_hdr.minutes = 59;
1236 cv_hdr.seconds = 59;
1237 cv_hdr.usecs = 0;
1239 cv_hdr.reserved1 = 0;
1240 cv_hdr.reserved2 = 0;
1242 switch(rec->rec_header.packet_header.pkt_encap) {
1244 case WTAP_ENCAP_ETHERNET :
1245 cv_hdr.medium_type = MEDIUM_ETHERNET;
1246 cv_hdr.decryption_flag = 0x00;
1247 cv_hdr.direction = 0x00; /* what does this mean? */
1248 break;
1250 case WTAP_ENCAP_IEEE_802_11 :
1251 /* XXX - the claim is that the RF header is mandatory */
1252 cv_hdr.medium_type = MEDIUM_WIFI;
1253 break;
1255 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO :
1256 cv_hdr.medium_type = MEDIUM_WIFI;
1258 #if 0
1259 switch (rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy) {
1261 case PHDR_802_11_PHY_11N:
1262 cv_hdr.status_modulation = STATUS_MODULATION_HT_PHY;
1263 break;
1265 case PHDR_802_11_PHY_11AC:
1266 cv_hdr.status_modulation = STATUS_MODULATION_VHT_PHY;
1267 break;
1269 case PHDR_802_11_PHY_11AX:
1270 cv_hdr.status_modulation = STATUS_MODULATION_HE_PHY;
1271 break;
1273 default:
1274 cv_hdr.status_modulation = 0;
1275 break;
1279 * Pick the band based on the frequency.
1281 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_frequency) {
1282 if (rec->rec_header.packet_header.pseudo_header.ieee_802_11.frequency > 2484) {
1283 /* 5 GHz band */
1284 cv_hdr.frequency_band = BAND_5GHZ;
1285 } else {
1286 /* 2.4 GHz band */
1287 cv_hdr.frequency_band = BAND_2_4GHZ;
1289 } else {
1290 /* Band is unknown. */
1291 cv_hdr.band = 0;
1294 cv_hdr.channel =
1295 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_channel ?
1296 rec->rec_header.packet_header.pseudo_header.ieee_802_11.channel :
1298 cv_hdr.noise_level_dbm =
1299 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_noise_dbm ?
1300 -rec->rec_header.packet_header.pseudo_header.ieee_802_11.noise_dbm :
1302 cv_hdr.signal_level_dbm =
1303 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_dbm ?
1304 -rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_dbm :
1306 cv_hdr.signal_level_percent =
1307 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_signal_percent ?
1308 rec->rec_header.packet_header.pseudo_header.ieee_802_11.signal_percent :
1310 cv_hdr.reserved = 0;
1311 cv_hdr.phy_rate =
1312 rec->rec_header.packet_header.pseudo_header.ieee_802_11.has_data_rate ?
1313 (uint32_t)(rec->rec_header.packet_header.pseudo_header.ieee_802_11.data_rate & 0xFF) :
1315 #endif
1316 break;
1318 default :
1319 *err = WTAP_ERR_UNWRITABLE_ENCAP;
1320 return false;
1323 if (!wtap_dump_file_write(wdh, &cv_hdr.data_len, 4, err))
1324 return false;
1325 if (!wtap_dump_file_write(wdh, &cv_hdr.year, 2, err))
1326 return false;
1327 if (!wtap_dump_file_write(wdh, &cv_hdr.month, 1, err))
1328 return false;
1329 if (!wtap_dump_file_write(wdh, &cv_hdr.day, 1, err))
1330 return false;
1331 if (!wtap_dump_file_write(wdh, &cv_hdr.hours, 1, err))
1332 return false;
1333 if (!wtap_dump_file_write(wdh, &cv_hdr.minutes, 1, err))
1334 return false;
1335 if (!wtap_dump_file_write(wdh, &cv_hdr.seconds, 1, err))
1336 return false;
1337 if (!wtap_dump_file_write(wdh, &cv_hdr.usecs, 4, err))
1338 return false;
1339 if (!wtap_dump_file_write(wdh, &cv_hdr.medium_type, 1, err))
1340 return false;
1341 if (!wtap_dump_file_write(wdh, &cv_hdr.decryption_flag, 1, err))
1342 return false;
1343 if (!wtap_dump_file_write(wdh, &cv_hdr.direction, 1, err))
1344 return false;
1345 if (!wtap_dump_file_write(wdh, &cv_hdr.reserved1, 1, err))
1346 return false;
1347 if (!wtap_dump_file_write(wdh, &cv_hdr.reserved2, 1, err))
1348 return false;
1350 /* XXX - RF and MCS headers */
1352 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
1353 return false;
1355 return true;
1358 static const struct supported_block_type commview_blocks_supported[] = {
1360 * We support packet blocks, with no comments or other options.
1362 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
1365 static const struct file_type_subtype_info commview_ncf_info = {
1366 "TamoSoft CommView NCF", "commview-ncf", "ncf", NULL,
1367 false, BLOCKS_SUPPORTED(commview_blocks_supported),
1368 commview_ncf_dump_can_write_encap, commview_ncf_dump_open, NULL
1371 static const struct file_type_subtype_info commview_ncfx_info = {
1372 "TamoSoft CommView NCFX", "commview-ncfx", "ncfx", NULL,
1373 false, BLOCKS_SUPPORTED(commview_blocks_supported),
1374 commview_ncfx_dump_can_write_encap, commview_ncfx_dump_open, NULL
1377 void register_commview(void)
1379 commview_ncf_file_type_subtype = wtap_register_file_type_subtype(&commview_ncf_info);
1380 commview_ncfx_file_type_subtype = wtap_register_file_type_subtype(&commview_ncfx_info);
1383 * Register name for backwards compatibility with the
1384 * wtap_filetypes table in Lua.
1386 * We don't need to register the new type, as the Wireshark
1387 * version with which we're providing backwards compatibility
1388 * didn't support the NCFX format. New code should fetch
1389 * the file type/subtype with wtap_name_to_file_type_subtype().
1391 wtap_register_backwards_compatibility_lua_name("COMMVIEW",
1392 commview_ncf_file_type_subtype);
1396 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1398 * Local variables:
1399 * c-basic-offset: 8
1400 * tab-width: 8
1401 * indent-tabs-mode: t
1402 * End:
1404 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1405 * :indentSize=8:tabSize=8:noTabs=false: