/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 | | */ |