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
20 * https://web.archive.org/web/20171022225753/http://www.tamos.com/htmlhelp/commview/logformat.htm
22 * if that doesn't display anything.
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
42 #define MEDIUM_TOKEN_RING 2
44 typedef struct commview_ncf_header
{
46 uint16_t source_data_len
;
55 uint8_t flags
; /* Bit-field positions defined below */
56 uint8_t signal_level_percent
;
60 uint8_t direction
; /* Or for WiFi, high order byte of
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 */
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
,
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);
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 ||
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 */
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
;
149 if(!commview_ncf_read_header(&cv_hdr
, fh
, err
, err_info
))
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
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 */
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
) {
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);
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);
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);
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);
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);
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);
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);
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?
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
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
)) {
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
)) {
282 rec
->rec_header
.packet_header
.pseudo_header
.ieee_802_11
.phy
= PHDR_802_11_PHY_11G
;
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
)) {
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;
298 case MEDIUM_TOKEN_RING
:
299 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_TOKEN_RING
;
303 *err
= WTAP_ERR_BAD_FILE
;
304 *err_info
= ws_strdup_printf("commview: unsupported encap for NCF: %u",
305 cv_hdr
.flags
& FLAGS_MEDIUM
);
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
;
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
);
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
);
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)
346 return commview_ncf_read_packet(wth
->random_fh
, rec
, buf
, err
, err_info
);
350 commview_ncf_read_header(commview_ncf_header_t
*cv_hdr
, FILE_T fh
, int *err
,
353 if (!wtap_read_bytes_or_eof(fh
, &cv_hdr
->data_len
, 2, err
, err_info
))
355 if (!wtap_read_bytes(fh
, &cv_hdr
->source_data_len
, 2, err
, err_info
))
357 if (!wtap_read_bytes(fh
, &cv_hdr
->version
, 1, err
, err_info
))
359 if (!wtap_read_bytes(fh
, &cv_hdr
->year
, 2, err
, err_info
))
361 if (!wtap_read_bytes(fh
, &cv_hdr
->month
, 1, err
, err_info
))
363 if (!wtap_read_bytes(fh
, &cv_hdr
->day
, 1, err
, err_info
))
365 if (!wtap_read_bytes(fh
, &cv_hdr
->hours
, 1, err
, err_info
))
367 if (!wtap_read_bytes(fh
, &cv_hdr
->minutes
, 1, err
, err_info
))
369 if (!wtap_read_bytes(fh
, &cv_hdr
->seconds
, 1, err
, err_info
))
371 if (!wtap_read_bytes(fh
, &cv_hdr
->usecs
, 4, err
, err_info
))
373 if (!wtap_read_bytes(fh
, &cv_hdr
->flags
, 1, err
, err_info
))
375 if (!wtap_read_bytes(fh
, &cv_hdr
->signal_level_percent
, 1, err
, err_info
))
377 if (!wtap_read_bytes(fh
, &cv_hdr
->rate
, 1, err
, err_info
))
379 if (!wtap_read_bytes(fh
, &cv_hdr
->band
, 1, err
, err_info
))
381 if (!wtap_read_bytes(fh
, &cv_hdr
->channel
, 1, err
, err_info
))
383 if (!wtap_read_bytes(fh
, &cv_hdr
->direction
, 1, err
, err_info
))
385 if (!wtap_read_bytes(fh
, &cv_hdr
->signal_level_dbm
, 1, err
, err_info
))
387 if (!wtap_read_bytes(fh
, &cv_hdr
->noise_level_dbm
, 1, err
, err_info
))
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
);
399 /* Returns 0 if we can write out the specified encapsulation type
400 * into a CommView format file. */
402 commview_ncf_dump_can_write_encap(int 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
:
414 return WTAP_ERR_UNWRITABLE_ENCAP
;
418 /* Returns true on success, false on failure;
419 sets "*err" to an error code on failure */
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 */
429 /* Write a record for a packet to a dump file.
430 * Returns true on success, false on failure. */
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};
438 /* We can only write packet records. */
439 if (rec
->rec_type
!= REC_TYPE_PACKET
) {
440 *err
= WTAP_ERR_UNWRITABLE_REC_TYPE
;
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
;
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
);
456 tm
= localtime(&rec
->ts
.secs
);
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);
467 * Second before the Epoch.
469 cv_hdr
.year
= GUINT16_TO_LE(1969);
478 switch(rec
->rec_header
.packet_header
.pkt_encap
) {
480 case WTAP_ENCAP_ETHERNET
:
481 cv_hdr
.flags
|= MEDIUM_ETHERNET
;
484 case WTAP_ENCAP_IEEE_802_11
:
485 cv_hdr
.flags
|= MEDIUM_WIFI
;
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
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
;
502 cv_hdr
.band
= BAND_11A_TURBO
;
505 case PHDR_802_11_PHY_11B
:
506 cv_hdr
.band
= BAND_11B
;
509 case PHDR_802_11_PHY_11G
:
511 * If we don't know whether it's Super G, say it's
514 if (!rec
->rec_header
.packet_header
.pseudo_header
.ieee_802_11
.phy_info
.info_11g
.has_mode
)
515 cv_hdr
.band
= BAND_11G
;
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
;
523 case PHDR_802_11G_MODE_SUPER_G
:
524 cv_hdr
.band
= BAND_SUPERG
;
528 cv_hdr
.band
= BAND_11G
;
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) {
541 cv_hdr
.band
= BAND_11N_5GHZ
;
544 cv_hdr
.band
= BAND_11N_2_4GHZ
;
547 /* Band is unknown. */
554 * It's not documented how they handle 11ac,
555 * and they don't support the older PHYs.
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
:
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) :
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
:
586 case WTAP_ENCAP_TOKEN_RING
:
587 cv_hdr
.flags
|= MEDIUM_TOKEN_RING
;
591 *err
= WTAP_ERR_UNWRITABLE_ENCAP
;
595 if (!wtap_dump_file_write(wdh
, &cv_hdr
.data_len
, 2, err
))
597 if (!wtap_dump_file_write(wdh
, &cv_hdr
.source_data_len
, 2, err
))
599 if (!wtap_dump_file_write(wdh
, &cv_hdr
.version
, 1, err
))
601 if (!wtap_dump_file_write(wdh
, &cv_hdr
.year
, 2, err
))
603 if (!wtap_dump_file_write(wdh
, &cv_hdr
.month
, 1, err
))
605 if (!wtap_dump_file_write(wdh
, &cv_hdr
.day
, 1, err
))
607 if (!wtap_dump_file_write(wdh
, &cv_hdr
.hours
, 1, err
))
609 if (!wtap_dump_file_write(wdh
, &cv_hdr
.minutes
, 1, err
))
611 if (!wtap_dump_file_write(wdh
, &cv_hdr
.seconds
, 1, err
))
613 if (!wtap_dump_file_write(wdh
, &cv_hdr
.usecs
, 4, err
))
615 if (!wtap_dump_file_write(wdh
, &cv_hdr
.flags
, 1, err
))
617 if (!wtap_dump_file_write(wdh
, &cv_hdr
.signal_level_percent
, 1, err
))
619 if (!wtap_dump_file_write(wdh
, &cv_hdr
.rate
, 1, err
))
621 if (!wtap_dump_file_write(wdh
, &cv_hdr
.band
, 1, err
))
623 if (!wtap_dump_file_write(wdh
, &cv_hdr
.channel
, 1, err
))
625 if (!wtap_dump_file_write(wdh
, &cv_hdr
.direction
, 1, err
))
627 if (!wtap_dump_file_write(wdh
, &cv_hdr
.signal_level_dbm
, 1, err
))
629 if (!wtap_dump_file_write(wdh
, &cv_hdr
.noise_level_dbm
, 1, err
))
631 if (!wtap_dump_file_write(wdh
, pd
, rec
->rec_header
.packet_header
.caplen
, err
))
636 typedef struct commview_ncfx_header
{
646 uint8_t decryption_flag
;
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
;
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
;
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
{
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
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
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
);
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
)) {
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;
727 wmem_free(NULL
, *err_info
);
729 return WTAP_OPEN_NOT_MINE
;
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 ||
740 cv_hdr
.minutes
> 59 ||
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 */
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 */
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 */
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
;
786 commview_ncfx_rf_header_t cv_rf_hdr
;
788 commview_ncfx_mcs_header_t cv_mcs_hdr
;
790 if (!commview_ncfx_read_header(&cv_hdr
, fh
, err
, err_info
))
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 */
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",
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
))
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
;
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
) {
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
;
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
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
;
869 rec
->rec_header
.packet_header
.pseudo_header
.ieee_802_11
.phy
= PHDR_802_11_PHY_11G
;
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
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
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
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",
924 length_remaining
-= COMMVIEW_NCFX_MCS_HEADER_SIZE
;
927 * Read the MCS header.
929 if (!commview_ncfx_read_mcs_header(&cv_mcs_hdr
, fh
,
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
) {
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
;
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
;
953 /* Guard interval? */
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
) {
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
;
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
;
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
;
983 /* Guard interval? */
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? */
1001 *err
= WTAP_ERR_BAD_FILE
;
1002 *err_info
= ws_strdup_printf("commview: unsupported encap for NCFX: %u",
1003 cv_hdr
.medium_type
);
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
;
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
);
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
);
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
);
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)
1055 return commview_ncfx_read_packet(wth
->random_fh
, rec
, buf
, err
, err_info
);
1059 commview_ncfx_read_header(commview_ncfx_header_t
*cv_hdr
, FILE_T fh
, int *err
,
1062 if (!wtap_read_bytes_or_eof(fh
, &cv_hdr
->data_len
, 4, err
, err_info
))
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",
1073 COMMVIEW_NCFX_HEADER_SIZE
);
1077 if (!wtap_read_bytes(fh
, &cv_hdr
->year
, 2, err
, err_info
))
1079 if (!wtap_read_bytes(fh
, &cv_hdr
->month
, 1, err
, err_info
))
1081 if (!wtap_read_bytes(fh
, &cv_hdr
->day
, 1, err
, err_info
))
1083 if (!wtap_read_bytes(fh
, &cv_hdr
->hours
, 1, err
, err_info
))
1085 if (!wtap_read_bytes(fh
, &cv_hdr
->minutes
, 1, err
, err_info
))
1087 if (!wtap_read_bytes(fh
, &cv_hdr
->seconds
, 1, err
, err_info
))
1089 if (!wtap_read_bytes(fh
, &cv_hdr
->usecs
, 4, err
, err_info
))
1091 if (!wtap_read_bytes(fh
, &cv_hdr
->medium_type
, 1, err
, err_info
))
1093 if (!wtap_read_bytes(fh
, &cv_hdr
->decryption_flag
, 1, err
, err_info
))
1095 if (!wtap_read_bytes(fh
, &cv_hdr
->direction
, 1, err
, err_info
))
1097 if (!wtap_read_bytes(fh
, &cv_hdr
->reserved1
, 1, err
, err_info
))
1099 if (!wtap_read_bytes(fh
, &cv_hdr
->reserved2
, 1, err
, err_info
))
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
);
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
))
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
))
1121 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->frequency_band
, 2, err
, err_info
))
1123 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->channel
, 2, err
, err_info
))
1125 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->noise_level_dbm
, 1, err
, err_info
))
1127 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->signal_level_dbm
, 1, err
, err_info
))
1129 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->signal_level_percent
, 1, err
, err_info
))
1131 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->reserved
, 1, err
, err_info
))
1133 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->phy_rate
, 4, err
, err_info
))
1135 if (!wtap_read_bytes(fh
, &cv_rf_hdr
->extensions_present
, 4, err
, err_info
))
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
);
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
))
1154 if (!wtap_read_bytes(fh
, &cv_mcs_hdr
->n_streams
, 1, err
, err_info
))
1156 if (!wtap_read_bytes(fh
, &cv_mcs_hdr
->channel_width
, 1, err
, err_info
))
1158 if (!wtap_read_bytes(fh
, &cv_mcs_hdr
->guard_interval
, 1, err
, err_info
))
1164 /* Returns 0 if we can write out the specified encapsulation type
1165 * into a CommView format file. */
1167 commview_ncfx_dump_can_write_encap(int 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
:
1178 return WTAP_ERR_UNWRITABLE_ENCAP
;
1182 /* Returns true on success, false on failure;
1183 sets "*err" to an error code on failure */
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 */
1193 /* Write a record for a packet to a dump file.
1194 * Returns true on success, false on failure. */
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};
1202 /* We can only write packet records. */
1203 if (rec
->rec_type
!= REC_TYPE_PACKET
) {
1204 *err
= WTAP_ERR_UNWRITABLE_REC_TYPE
;
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
;
1216 cv_hdr
.data_len
= GUINT32_TO_LE((uint32_t)rec
->rec_header
.packet_header
.caplen
);
1218 tm
= localtime(&rec
->ts
.secs
);
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);
1229 * Second before the Epoch.
1231 cv_hdr
.year
= GUINT16_TO_LE(1969);
1235 cv_hdr
.minutes
= 59;
1236 cv_hdr
.seconds
= 59;
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? */
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
;
1255 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO
:
1256 cv_hdr
.medium_type
= MEDIUM_WIFI
;
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
;
1265 case PHDR_802_11_PHY_11AC
:
1266 cv_hdr
.status_modulation
= STATUS_MODULATION_VHT_PHY
;
1269 case PHDR_802_11_PHY_11AX
:
1270 cv_hdr
.status_modulation
= STATUS_MODULATION_HE_PHY
;
1274 cv_hdr
.status_modulation
= 0;
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) {
1284 cv_hdr
.frequency_band
= BAND_5GHZ
;
1287 cv_hdr
.frequency_band
= BAND_2_4GHZ
;
1290 /* Band is unknown. */
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;
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) :
1319 *err
= WTAP_ERR_UNWRITABLE_ENCAP
;
1323 if (!wtap_dump_file_write(wdh
, &cv_hdr
.data_len
, 4, err
))
1325 if (!wtap_dump_file_write(wdh
, &cv_hdr
.year
, 2, err
))
1327 if (!wtap_dump_file_write(wdh
, &cv_hdr
.month
, 1, err
))
1329 if (!wtap_dump_file_write(wdh
, &cv_hdr
.day
, 1, err
))
1331 if (!wtap_dump_file_write(wdh
, &cv_hdr
.hours
, 1, err
))
1333 if (!wtap_dump_file_write(wdh
, &cv_hdr
.minutes
, 1, err
))
1335 if (!wtap_dump_file_write(wdh
, &cv_hdr
.seconds
, 1, err
))
1337 if (!wtap_dump_file_write(wdh
, &cv_hdr
.usecs
, 4, err
))
1339 if (!wtap_dump_file_write(wdh
, &cv_hdr
.medium_type
, 1, err
))
1341 if (!wtap_dump_file_write(wdh
, &cv_hdr
.decryption_flag
, 1, err
))
1343 if (!wtap_dump_file_write(wdh
, &cv_hdr
.direction
, 1, err
))
1345 if (!wtap_dump_file_write(wdh
, &cv_hdr
.reserved1
, 1, err
))
1347 if (!wtap_dump_file_write(wdh
, &cv_hdr
.reserved2
, 1, err
))
1350 /* XXX - RF and MCS headers */
1352 if (!wtap_dump_file_write(wdh
, pd
, rec
->rec_header
.packet_header
.caplen
, err
))
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
1401 * indent-tabs-mode: t
1404 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1405 * :indentSize=8:tabSize=8:noTabs=false: