1 /* packet-ieee80211-prism.c
2 * Routines for Prism monitoring mode header dissection
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
8 * Copyright 2016 Cisco Meraki
10 * Copied from README.developer
12 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <epan/packet.h>
19 #include <epan/capture_dissectors.h>
20 #include <wsutil/pint.h>
21 #include <wsutil/802_11-utils.h>
22 #include "packet-ieee80211.h"
24 void proto_register_ieee80211_prism(void);
25 void proto_reg_handoff_ieee80211_prism(void);
29 static dissector_handle_t wlancap_handle
;
30 static dissector_handle_t ieee80211_handle
;
31 static dissector_handle_t ieee80211_radio_handle
;
33 static capture_dissector_handle_t ieee80211_cap_handle
;
34 static capture_dissector_handle_t wlancap_cap_handle
;
36 static int proto_prism
;
38 /* Prism radio header */
40 static int hf_ieee80211_prism_msgcode
;
41 static int hf_ieee80211_prism_msglen
;
42 static int hf_ieee80211_prism_devname
;
43 static int hf_ieee80211_prism_did
;
44 static int hf_ieee80211_prism_did_type
;
45 static int hf_ieee80211_prism_did_status
;
46 static int hf_ieee80211_prism_did_length
;
47 static int hf_ieee80211_prism_did_hosttime
;
48 static int hf_ieee80211_prism_did_mactime
;
49 static int hf_ieee80211_prism_did_channel
;
50 static int hf_ieee80211_prism_did_rssi
;
51 static int hf_ieee80211_prism_did_sq
;
52 static int hf_ieee80211_prism_did_signal
;
53 static int hf_ieee80211_prism_did_noise
;
54 static int hf_ieee80211_prism_did_rate
;
55 static int hf_ieee80211_prism_did_istx
;
56 static int hf_ieee80211_prism_did_frmlen
;
57 static int hf_ieee80211_prism_did_unknown
;
59 /* Qualcomm Extensions */
60 static int hf_ieee80211_prism_did_sig_a1
;
61 static int hf_ieee80211_prism_did_sig_a2
;
62 static int hf_ieee80211_prism_did_sig_b
;
63 static int hf_ieee80211_prism_did_sig_rate_field
;
67 static int ett_prism_did
;
68 static int ett_sig_ab
;
70 static dissector_handle_t prism_handle
;
73 * Prism II-based wlan devices have a monitoring mode that sticks
74 * a proprietary header on each packet with lots of good
75 * information. This file is responsible for decoding that
78 * Support by Tim Newsham
80 * A value from the header.
82 * It appears from looking at the linux-wlan-ng and Prism II HostAP
83 * drivers, and various patches to the orinoco_cs drivers to add
84 * Prism headers, that:
86 * the "did" identifies what the value is (i.e., what it's the value
89 * "status" is 0 if the value is present or 1 if it's absent;
91 * "len" is the length of the value (always 4, in that code);
93 * "data" is the value of the data (or 0 if not present).
95 * Note: all of those values are in the *host* byte order of the machine
96 * on which the capture was written.
101 * Header attached during Prism monitor mode.
103 * At least according to one paper I've seen, the Prism 2.5 chip set
106 * RSSI (receive signal strength indication) is "the total power
107 * received by the radio hardware while receiving the frame,
108 * including signal, interfereence, and background noise";
110 * "silence value" is "the total power observed just before the
111 * start of the frame".
113 * None of the drivers I looked at supply the "rssi" or "sq" value,
114 * but they do supply "signal" and "noise" values, along with a "rate"
115 * value that's 1/5 of the raw value from what is presumably a raw
116 * HFA384x frame descriptor, with the comment "set to 802.11 units",
117 * which presumably means the units are 500 Kb/s.
119 * I infer from the current NetBSD "wi" driver that "signal" and "noise"
120 * are adjusted dBm values, with the dBm value having 100 added to it
121 * for the Prism II cards (although the NetBSD code has an XXX comment
122 * for the #define for WI_PRISM_DBM_OFFSET) and 149 (with no XXX comment)
123 * for the Orinoco cards.
125 * XXX - what about other drivers that supply Prism headers, such as
126 * old versions of the MadWifi driver?
128 * I'm not sure where these DID values come from, but they work with
129 * at least one capture file. However, in
131 * https://ask.wireshark.org/questions/14963/how-to-get-the-field-did-unknown-4041-into-the-column
133 * somebody reports a capture where *different* DID values, corresponding
136 * http://www.martin.cc/linux/prism
138 * are used (and that's not a byte-order issue, as those values are *not*
139 * just byte-swapped versions of the other values).
142 #define PRISM_HEADER_LENGTH 144 /* Default Prism Header Length */
145 * Message code values.
147 * Some Prism captures have headers that begin with 0x00000044; those
148 * captures have the non-home.martin.cc values for the DID types,
149 * while a capture with 0x00000041 as the message code have the
150 * home.martin.cc values for the DID types, and the home.martin.cc
151 * page has 0x00000041 as the message code.
153 #define PRISM_TYPE1_MSGCODE 0x00000044 /* Monitor Frame */
154 #define PRISM_TYPE2_MSGCODE 0x00000041
157 * DID codes - PRISM_TYPE1_xxx are the non-home.martin.cc values, and
158 * PRISM_TYPE2_xxx are the home.martin.cc values.
160 #define PRISM_TYPE1_HOSTTIME 0x00010044 /* Host time element */
161 #define PRISM_TYPE2_HOSTTIME 0x00001041
162 #define PRISM_TYPE1_MACTIME 0x00020044 /* Mac time element */
163 #define PRISM_TYPE2_MACTIME 0x00002041
164 #define PRISM_TYPE1_CHANNEL 0x00030044 /* Channel element */
165 #define PRISM_TYPE2_CHANNEL 0x00003041
166 #define PRISM_TYPE1_RSSI 0x00040044 /* RSSI element */
167 #define PRISM_TYPE2_RSSI 0x00004041
168 #define PRISM_TYPE1_SQ 0x00050044 /* SQ element */
169 #define PRISM_TYPE2_SQ 0x00005041
170 #define PRISM_TYPE1_SIGNAL 0x00060044 /* Signal element */
171 #define PRISM_TYPE2_SIGNAL 0x00006041
172 #define PRISM_TYPE1_NOISE 0x00070044 /* Noise element */
173 #define PRISM_TYPE2_NOISE 0x00007041
174 #define PRISM_TYPE1_RATE 0x00080044 /* Rate element */
175 #define PRISM_TYPE2_RATE 0x00008041
176 #define PRISM_TYPE1_ISTX 0x00090044 /* Is Tx frame */
177 #define PRISM_TYPE2_ISTX 0x00009041
178 #define PRISM_TYPE1_FRMLEN 0x000A0044 /* Frame length */
179 #define PRISM_TYPE2_FRMLEN 0x0000A041
181 /* Qualcomm extensions */
182 #define PRISM_TYPE1_RATE_SIG_A1 0x000B0044 /* VHT SIGA1 element */
183 #define PRISM_TYPE2_RATE_SIG_A1 0x0000B044
184 #define PRISM_TYPE1_RATE_SIG_A2 0x000C0044 /* VHT SIGA2 element */
185 #define PRISM_TYPE2_RATE_SIG_A2 0x0000C044
186 #define PRISM_TYPE1_RATE_SIG_B 0x000D0044 /* VHT SIGB element */
187 #define PRISM_TYPE2_RATE_SIG_B 0x0000D044 /* VHT SIGB element */
189 static const value_string prism_did_vals
[] =
191 { PRISM_TYPE1_HOSTTIME
, "Host Time" },
192 { PRISM_TYPE2_HOSTTIME
, "Host Time" },
193 { PRISM_TYPE1_MACTIME
, "Mac Time" },
194 { PRISM_TYPE2_MACTIME
, "Mac Time" },
195 { PRISM_TYPE1_CHANNEL
, "Channel" },
196 { PRISM_TYPE2_CHANNEL
, "Channel" },
197 { PRISM_TYPE1_RSSI
, "RSSI" },
198 { PRISM_TYPE2_RSSI
, "RSSI" },
199 { PRISM_TYPE1_SQ
, "SQ" },
200 { PRISM_TYPE2_SQ
, "SQ" },
201 { PRISM_TYPE1_SIGNAL
, "Signal" },
202 { PRISM_TYPE2_SIGNAL
, "Signal" },
203 { PRISM_TYPE1_NOISE
, "Noise" },
204 { PRISM_TYPE2_NOISE
, "Noise" },
205 { PRISM_TYPE1_RATE
, "Rate" },
206 { PRISM_TYPE2_RATE
, "Rate" },
207 { PRISM_TYPE1_ISTX
, "Is Tx" },
208 { PRISM_TYPE2_ISTX
, "Is Tx" },
209 { PRISM_TYPE1_FRMLEN
, "Frame Length" },
210 { PRISM_TYPE2_FRMLEN
, "Frame Length" },
212 /* Qualcomm extensions */
213 { PRISM_TYPE1_RATE_SIG_A1
, "SIG A1" },
214 { PRISM_TYPE2_RATE_SIG_A1
, "SIG A1" },
215 { PRISM_TYPE1_RATE_SIG_A2
, "SIG A2" },
216 { PRISM_TYPE2_RATE_SIG_A2
, "SIG A2" },
217 { PRISM_TYPE1_RATE_SIG_B
, "SIG B" },
218 { PRISM_TYPE2_RATE_SIG_B
, "SIG B" },
223 * The header file mentioned above says 0 means "supplied" and 1 means
224 * "not supplied". I haven't seen a capture file with anything other
225 * than 0 there, but there is at least one driver that appears to use
226 * 1 for values it doesn't supply (the Linux acx-20080210 driver).
228 static const value_string prism_status_vals
[] =
231 { 1, "Not Supplied" },
235 static const value_string prism_istx_vals
[] =
243 prism_rate_base_custom(char *result
, uint32_t rate
)
245 snprintf(result
, ITEM_LABEL_LENGTH
, "%u.%u", rate
/2, rate
& 1 ? 5 : 0);
249 prism_rate_return(wmem_allocator_t
*scope
, uint32_t rate
)
252 result
= (char *)wmem_alloc(scope
, SHORT_STR
);
254 prism_rate_base_custom(result
, rate
);
260 /* HT20 Rate table MAX NSS = 4 */
261 static unsigned int ht_20_tbl
[32][2] =
263 { 65, 72 }, /* MCS 0 */
264 { 130, 144 }, /* MCS 1 */
265 { 195, 217 }, /* MCS 2 */
266 { 260, 289 }, /* MCS 3 */
267 { 390, 433 }, /* MCS 4 */
268 { 520, 578 }, /* MCS 5 */
269 { 585, 650 }, /* MCS 6 */
270 { 650, 722 }, /* MCS 7 */
271 { 130, 144 }, /* MCS 8 */
272 { 260, 289 }, /* MCS 9 */
273 { 390, 433 }, /* MCS 10 */
274 { 520, 578 }, /* MCS 11 */
275 { 780, 867 }, /* MCS 12 */
276 { 1040, 1156 }, /* MCS 13 */
277 { 1170, 1300 }, /* MCS 14 */
278 { 1300, 1444 }, /* MCS 15 */
279 { 195, 217 }, /* MCS 16 */
280 { 390, 433 }, /* MCS 17 */
281 { 585, 650 }, /* MCS 18 */
282 { 780, 867 }, /* MCS 19 */
283 { 1170, 1300 }, /* MCS 20 */
284 { 1560, 1733 }, /* MCS 21 */
285 { 1755, 1950 }, /* MCS 22 */
286 { 1950, 2167 }, /* MCS 23 */
287 { 260, 289 }, /* MCS 24 */
288 { 520, 578 }, /* MCS 25 */
289 { 780, 867 }, /* MCS 26 */
290 { 1040, 1156 }, /* MCS 27 */
291 { 1560, 1733 }, /* MCS 28 */
292 { 2080, 2311 }, /* MCS 29 */
293 { 2340, 2600 }, /* MCS 30 */
294 { 2600, 2889 } /* MCS 31 */
297 /* HT40 Rate table MAX NSS = 4 */
298 static unsigned int ht_40_tbl
[32][2] =
300 { 135, 150 }, /* MCS 0 */
301 { 270, 300 }, /* MCS 1 */
302 { 405, 450 }, /* MCS 2 */
303 { 540, 600 }, /* MCS 3 */
304 { 810, 900 }, /* MCS 4 */
305 { 1080, 1200 }, /* MCS 5 */
306 { 1215, 1350 }, /* MCS 6 */
307 { 1350, 1500 }, /* MCS 7 */
308 { 270, 300 }, /* MCS 8 */
309 { 540, 600 }, /* MCS 9 */
310 { 810, 900 }, /* MCS 10 */
311 { 1080, 1200 }, /* MCS 11 */
312 { 1620, 1800 }, /* MCS 12 */
313 { 2160, 2400 }, /* MCS 13 */
314 { 2430, 2700 }, /* MCS 14 */
315 { 2700, 3000 }, /* MCS 15 */
316 { 405, 450 }, /* MCS 16 */
317 { 810, 900 }, /* MCS 17 */
318 { 1215, 1350 }, /* MCS 18 */
319 { 1620, 1800 }, /* MCS 19 */
320 { 2430, 2700 }, /* MCS 20 */
321 { 3240, 3600 }, /* MCS 21 */
322 { 3645, 4050 }, /* MCS 22 */
323 { 4050, 4500 }, /* MCS 23 */
324 { 540, 600 }, /* MCS 24 */
325 { 1080, 1200 }, /* MCS 25 */
326 { 1620, 1800 }, /* MCS 26 */
327 { 2160, 2400 }, /* MCS 27 */
328 { 3240, 3600 }, /* MCS 28 */
329 { 4320, 4800 }, /* MCS 29 */
330 { 4860, 5400 }, /* MCS 30 */
331 { 5400, 6000 }}; /* MCS 31 */
333 /* VHT20 Rate Table MAX NSS = 4 */
334 static unsigned int vht_20_tbl
[10][8] =
336 { 65, 72, 130, 144, 195, 217, 260, 289}, /* MCS 0 */
337 { 130, 144, 260, 289, 390, 433, 520, 578}, /* MCS 1 */
338 { 195, 217, 390, 433, 585, 650, 780, 867}, /* MCS 2 */
339 { 260, 289, 520, 578, 780, 867, 1040, 1156}, /* MCS 3 */
340 { 390, 433, 780, 867, 1170, 1300, 1560, 1733}, /* MCS 4 */
341 { 520, 578, 1040, 1156, 1560, 1733, 2080, 2311}, /* MCS 5 */
342 { 585, 650, 1170, 1300, 1755, 1950, 2340, 2600}, /* MCS 6 */
343 { 650, 722, 1300, 1444, 1950, 2167, 2600, 2889}, /* MCS 7 */
344 { 780, 867, 1560, 1733, 2340, 2600, 3120, 3467}, /* MCS 8 */
345 { 0, 0, 0, 0, 2600, 2889, 0, 0} /* MCS 9 */
348 /* VHT40 Rate Table MAX NSS = 4 */
349 static unsigned int vht_40_tbl
[10][8] =
351 { 135, 150, 270, 300, 405, 450, 540, 600}, /* MCS 0 */
352 { 270, 300, 540, 600, 810, 900, 1080, 1200}, /* MCS 1 */
353 { 405, 450, 810, 900, 1215, 1350, 1620, 1800}, /* MCS 2 */
354 { 540, 600, 1080, 1200, 1620, 1800, 2160, 2400}, /* MCS 3 */
355 { 810, 900, 1620, 1800, 2430, 2700, 3240, 3600}, /* MCS 4 */
356 { 1080, 1200, 2160, 2400, 3240, 3600, 4320, 4800}, /* MCS 5 */
357 { 1215, 1350, 2430, 2700, 3645, 4050, 4860, 5400}, /* MCS 6 */
358 { 1350, 1500, 2700, 3000, 4050, 4500, 5400, 6000}, /* MCS 7 */
359 { 1620, 1800, 3240, 3600, 4860, 5400, 6480, 7200}, /* MCS 8 */
360 { 1800, 2000, 3600, 4000, 5400, 6000, 7200, 8000} /* MCS 9 */
363 /* VHT80 Rate Table MAX NSS = 4 */
364 static unsigned int vht_80_tbl
[10][8] =
366 { 293, 325, 585, 650, 878, 975, 1170, 1300}, /* MCS 0 */
367 { 585, 650, 1170, 1300, 1755, 1950, 2340, 2600}, /* MCS 1 */
368 { 878, 975, 1755, 1950, 2633, 2925, 3510, 3900}, /* MCS 2 */
369 { 1170, 1300, 2340, 2600, 3510, 3900, 4680, 5200}, /* MCS 3 */
370 { 1755, 1950, 3510, 3900, 5265, 5850, 7020, 7800}, /* MCS 4 */
371 { 2340, 2600, 4680, 5200, 7020, 7800, 9360, 10400}, /* MCS 5 */
372 { 2633, 2925, 5265, 5850, 0, 0, 10530, 11700}, /* MCS 6 */
373 { 2925, 3250, 5850, 6500, 8775, 9750, 11700, 13000}, /* MCS 7 */
374 { 3510, 3900, 7020, 7800, 10530, 11700, 14040, 15600}, /* MCS 8 */
375 { 3900, 4333, 7800, 8667, 11700, 13000, 15600, 17333} /* MCS 9 */
378 /* VHT160 Rate Table MAX NSS = 4 */
379 static unsigned int vht_160_tbl
[10][8] =
381 { 585, 650, 1170, 1300, 1755, 1950, 2340, 2600}, /* MCS 0 */
382 { 1170, 1300, 2340, 2600, 3510, 3900, 4680, 5200}, /* MCS 1 */
383 { 1755, 1950, 3510, 3900, 5265, 5850, 7020, 7800}, /* MCS 2 */
384 { 2340, 2600, 4680, 5200, 7020, 7800, 9360, 10400}, /* MCS 3 */
385 { 3510, 3900, 7020, 7800, 10530, 11700, 14040, 15600}, /* MCS 4 */
386 { 4680, 5200, 9360, 10400, 14040, 15600, 18720, 20800}, /* MCS 5 */
387 { 5265, 5850, 10530, 11700, 15795, 17550, 21060, 23400}, /* MCS 6 */
388 { 5850, 6500, 11700, 13000, 17550, 19500, 23400, 26000}, /* MCS 7 */
389 { 7020, 7800, 14040, 15600, 21060, 23400, 28080, 31200}, /* MCS 8 */
390 { 7800, 8667, 15600, 17333, 0, 0, 31200, 34667} /* MCS 9 */
395 prism_rate_return_sig(wmem_allocator_t
*scope
, uint32_t rate_phy1
, uint32_t rate_phy2
, struct ieee_802_11_phdr
*phdr
)
398 unsigned int mcs
, base
, pream_type
, disp_rate
, bw
, sgi
, ldpc
, stbc
, groupid
, txbf
;
399 bool su_ppdu
= false;
400 unsigned int partial_aid
, nsts_u1
, nsts_u2
, nsts_u3
, nsts_u4
;
401 unsigned int sig_a_1
, sig_a_2
, nss
= 1, nsts_su
, signal_type
;
402 unsigned int dsss_tbl
[] = {22, 11, 4, 2};
403 static const unsigned int bw_map
[] = { 0, 1, 4, 11 };
406 * Qualcomm Atheros: Display Nss, MCS/Rate, BW, sgi, LDPC, STBC info
408 pream_type
= rate_phy1
& 0xF;
409 switch (pream_type
) {
412 phdr
->phy
= PHDR_802_11_PHY_11A
; /* or 11g? */
413 mcs
= (rate_phy1
>> 4) & 0xF;
414 base
= (mcs
& 0x4) ? 9 : 6;
416 mcs
= base
<< (11 - mcs
);
417 mcs
= (mcs
> 54) ? 54 : mcs
;
418 phdr
->has_data_rate
= 1;
419 phdr
->data_rate
= mcs
* 2;
420 signal_type
= rate_phy1
& (1 << 12);
421 bw
= 20 << ((rate_phy1
>> 13) & 0x3);
422 result
= wmem_strdup_printf(scope
,
423 "Rate: %u.%u Mb/s OFDM Signaling:%s BW %d",
424 mcs
, 0, signal_type
? "Dynamic" : "Static", bw
429 phdr
->phy
= PHDR_802_11_PHY_11B
;
430 mcs
= (rate_phy1
>> 4) & 0xF;
431 base
= (mcs
& 0x4) ? 1 : 0;
432 phdr
->phy_info
.info_11b
.has_short_preamble
= 1;
433 phdr
->phy_info
.info_11b
.short_preamble
= base
;
435 mcs
= (mcs
- 8) & 0x3;
436 disp_rate
= dsss_tbl
[mcs
];
437 phdr
->has_data_rate
= 1;
438 phdr
->data_rate
= disp_rate
;
439 result
= wmem_strdup_printf(scope
, "Rate: %u.%u Mb/s DSSS %s",
441 (disp_rate
& 1) ? 5 : 0,
442 base
? "[SP]" : "[LP]");
446 phdr
->phy
= PHDR_802_11_PHY_11N
;
447 sig_a_1
= (rate_phy1
>> 4) & 0xFFFF;
448 sig_a_2
= (rate_phy2
) & 0xFFF;
449 mcs
= sig_a_1
& 0x7f;
450 phdr
->phy_info
.info_11n
.has_mcs_index
= 1;
451 phdr
->phy_info
.info_11n
.mcs_index
= mcs
;
452 bw
= 20 << ((sig_a_1
>> 7) & 1);
453 phdr
->phy_info
.info_11n
.has_bandwidth
= 1;
454 phdr
->phy_info
.info_11n
.bandwidth
= ((sig_a_1
>> 7) & 1);
455 sgi
= (sig_a_2
>> 7) & 1;
456 phdr
->phy_info
.info_11n
.has_short_gi
= 1;
457 phdr
->phy_info
.info_11n
.short_gi
= sgi
;
458 ldpc
= (sig_a_2
>> 6) & 1;
459 phdr
->phy_info
.info_11n
.has_fec
= 1;
460 phdr
->phy_info
.info_11n
.fec
= ldpc
;
461 stbc
= ((sig_a_2
>> 4) & 3)?1:0;
462 phdr
->phy_info
.info_11n
.has_stbc_streams
= 1;
463 phdr
->phy_info
.info_11n
.stbc_streams
= stbc
;
464 phdr
->phy_info
.info_11n
.has_ness
= 1;
465 phdr
->phy_info
.info_11n
.ness
= (sig_a_2
>> 8) & 3;
466 nss
= (mcs
>> 3) + 1;
469 if ((nss
<= 4) && (mcs
<= 31) && ((bw
== 20) || (bw
==40))){
474 disp_rate
= ht_20_tbl
[mcs
][1];
476 disp_rate
= ht_20_tbl
[mcs
][0];
482 disp_rate
= ht_40_tbl
[mcs
][1];
484 disp_rate
= ht_40_tbl
[mcs
][0];
489 result
= wmem_strdup_printf(scope
,
490 "Rate: %u.%u Mb/s HT MCS %d NSS %d BW %d MHz %s %s %s",
491 disp_rate
/10, disp_rate
%10, mcs
, nss
, bw
,
493 ldpc
? "[LDPC]" : "",
494 stbc
? "[STBC]" : "");
498 phdr
->phy
= PHDR_802_11_PHY_11AC
;
499 sig_a_1
= (rate_phy1
>> 4) & 0xFFFFFF;
500 sig_a_2
= (rate_phy2
) & 0xFFFFFF;
501 stbc
= (sig_a_1
>> 3) & 1;
502 phdr
->phy_info
.info_11ac
.has_stbc
= 1;
503 phdr
->phy_info
.info_11ac
.stbc
= stbc
;
505 phdr
->phy_info
.info_11ac
.has_short_gi
= 1;
506 phdr
->phy_info
.info_11ac
.short_gi
= sgi
;
507 bw
= 20 << (sig_a_1
& 3);
508 phdr
->phy_info
.info_11ac
.has_bandwidth
= 1;
509 phdr
->phy_info
.info_11ac
.bandwidth
= bw_map
[(sig_a_1
& 3)];
510 ldpc
= (sig_a_2
>> 2) & 1;
511 phdr
->phy_info
.info_11ac
.has_fec
= 1;
512 phdr
->phy_info
.info_11ac
.fec
= ldpc
;
513 groupid
= (sig_a_1
>> 4) & 0x3F;
514 phdr
->phy_info
.info_11ac
.has_group_id
= 1;
515 phdr
->phy_info
.info_11ac
.group_id
= groupid
;
517 if (groupid
== 0 || groupid
== 63)
523 nsts_su
= (sig_a_1
>> 10) & 0x7;
529 mcs
= (sig_a_2
>> 4) & 0xF;
530 phdr
->phy_info
.info_11ac
.mcs
[0] = mcs
;
531 phdr
->phy_info
.info_11ac
.nss
[0] = nss
;
532 txbf
= (sig_a_2
>> 8) & 1;
533 phdr
->phy_info
.info_11ac
.has_beamformed
= 1;
534 phdr
->phy_info
.info_11ac
.beamformed
= txbf
;
535 partial_aid
= (sig_a_1
>> 13) & 0x1FF;
536 phdr
->phy_info
.info_11ac
.has_partial_aid
= 1;
537 phdr
->phy_info
.info_11ac
.partial_aid
= partial_aid
;
540 if ((nss
<= 4) && (mcs
<= 9) && ((bw
== 20) || (bw
==40) || (bw
==80) || bw
==160)) {
545 disp_rate
= vht_20_tbl
[mcs
][(nss
* 2) - 1];
547 disp_rate
= vht_20_tbl
[mcs
][(nss
- 1) * 2];
553 disp_rate
= vht_40_tbl
[mcs
][(nss
* 2) - 1];
555 disp_rate
= vht_40_tbl
[mcs
][(nss
- 1) * 2];
561 disp_rate
= vht_80_tbl
[mcs
][(nss
* 2) - 1];
563 disp_rate
= vht_80_tbl
[mcs
][(nss
- 1) * 2];
569 disp_rate
= vht_160_tbl
[mcs
][(nss
* 2) - 1];
571 disp_rate
= vht_160_tbl
[mcs
][(nss
- 1) * 2];
577 result
= wmem_strdup_printf(scope
,
578 "Rate: %u.%u Mb/s VHT MCS %d NSS %d Partial AID %d BW %d MHz %s %s %s GroupID %d %s %s",
579 disp_rate
/10, disp_rate
%10,
580 mcs
, nss
, partial_aid
, bw
,
582 ldpc
? "[LDPC]" : "",
583 stbc
? "[STBC]" : "",
586 txbf
? "[TxBF]" : "");
588 nsts_u1
= (sig_a_1
>> 10) & 0x7;
589 nsts_u2
= (sig_a_1
>> 13) & 0x7;
590 nsts_u3
= (sig_a_1
>> 16) & 0x7;
591 nsts_u4
= (sig_a_1
>> 19) & 0x7;
593 result
= wmem_strdup_printf(scope
,
594 "VHT NSTS %d %d %d %d BW %d MHz %s %s %s GroupID %d %s",
595 nsts_u1
, nsts_u2
, nsts_u3
, nsts_u4
, bw
,
597 ldpc
? "[LDPC]" : "",
598 stbc
? "[STBC]" : "",
609 capture_prism(const unsigned char *pd
, int offset
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header _U_
)
613 if (!BYTES_ARE_IN_FRAME(offset
, len
, 4))
616 /* Some captures with DLT_PRISM have the AVS WLAN header */
617 cookie
= pntoh32(pd
);
618 if ((cookie
== WLANCAP_MAGIC_COOKIE_V1
) ||
619 (cookie
== WLANCAP_MAGIC_COOKIE_V2
)) {
620 return call_capture_dissector(wlancap_cap_handle
, pd
, offset
, len
, cpinfo
, pseudo_header
);
624 if (!BYTES_ARE_IN_FRAME(offset
, len
, PRISM_HEADER_LENGTH
))
627 offset
+= PRISM_HEADER_LENGTH
;
629 /* 802.11 header follows */
630 return call_capture_dissector(ieee80211_cap_handle
, pd
, offset
, len
, cpinfo
, pseudo_header
);
634 dissect_prism(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
636 proto_tree
*prism_tree
, *prism_did_tree
= NULL
;
637 proto_item
*ti
= NULL
, *ti_did
= NULL
;
640 uint32_t msgcode
, msglen
, did
, rate_phy1
= 0, rate_phy2
= 0;
643 const uint8_t *devname_p
;
648 struct ieee_802_11_phdr phdr
;
653 /* handle the AVS header */
654 msgcode
= tvb_get_ntohl(tvb
, offset
);
655 if ((msgcode
== WLANCAP_MAGIC_COOKIE_V1
) ||
656 (msgcode
== WLANCAP_MAGIC_COOKIE_V2
)) {
657 call_dissector(wlancap_handle
, tvb
, pinfo
, tree
);
658 return tvb_captured_length(tvb
);
662 * If we don't see a valid message type, assume the Prism or AVS
663 * header was omitted and just hand off to the 802.11 dissector;
664 * at least one capture has AVS headers on some packets and no
665 * radio headers on others (incoming vs. outgoing?).
667 * Check for both byte orders and use that to determine
668 * the byte order of the fields in the Prism header.
670 if ((msgcode
== PRISM_TYPE1_MSGCODE
) || (msgcode
== PRISM_TYPE2_MSGCODE
)) {
671 /* big-endian fetch matched */
672 byte_order
= ENC_BIG_ENDIAN
;
673 } else if (((msgcode
= tvb_get_letohl(tvb
, offset
)) == PRISM_TYPE1_MSGCODE
) ||
674 (msgcode
== PRISM_TYPE2_MSGCODE
)) {
675 /* little-endian fetch matched */
676 byte_order
= ENC_LITTLE_ENDIAN
;
678 /* neither matched - try it as just 802.11 with no Prism header */
679 call_dissector(ieee80211_handle
, tvb
, pinfo
, tree
);
680 return tvb_captured_length(tvb
);
683 /* We don't have any 802.11 metadata yet. */
684 memset(&phdr
, 0, sizeof(phdr
));
686 phdr
.decrypted
= false;
687 phdr
.datapad
= false;
688 phdr
.phy
= PHDR_802_11_PHY_UNKNOWN
;
690 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Prism");
691 col_clear(pinfo
->cinfo
, COL_INFO
);
693 ti
= proto_tree_add_item(tree
, proto_prism
, tvb
, 0, 144, ENC_NA
);
694 prism_tree
= proto_item_add_subtree(ti
, ett_prism
);
697 proto_tree_add_item_ret_uint(prism_tree
, hf_ieee80211_prism_msgcode
, tvb
, offset
, 4, byte_order
, &msgcode
);
701 proto_tree_add_item_ret_uint(prism_tree
, hf_ieee80211_prism_msglen
, tvb
, offset
, 4, byte_order
, &msglen
);
705 proto_tree_add_item_ret_string(prism_tree
, hf_ieee80211_prism_devname
, tvb
, offset
, 16, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &devname_p
);
708 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Device: %s, Message 0x%x, Length %d", devname_p
, msgcode
, msglen
);
710 while (offset
< PRISM_HEADER_LENGTH
)
714 ti_did
= proto_tree_add_item(prism_tree
, hf_ieee80211_prism_did
, tvb
, offset
, 12, ENC_NA
);
715 prism_did_tree
= proto_item_add_subtree(ti_did
, ett_prism_did
);
717 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_type
, tvb
, offset
, 4, byte_order
);
718 did
= tvb_get_uint32(tvb
, offset
, byte_order
);
719 proto_item_append_text(ti_did
, " %s", val_to_str(did
, prism_did_vals
, "Unknown %x") );
725 status
= tvb_get_uint16(tvb
, offset
, byte_order
);
726 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_status
, tvb
, offset
, 2, byte_order
);
730 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_length
, tvb
, offset
, 2, byte_order
);
733 /* Data, if present... */
737 case PRISM_TYPE1_HOSTTIME
:
738 case PRISM_TYPE2_HOSTTIME
:
740 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_hosttime
, tvb
, offset
, 4, byte_order
);
741 proto_item_append_text(ti_did
, " %d", tvb_get_uint32(tvb
, offset
, byte_order
) );
745 case PRISM_TYPE1_MACTIME
:
746 case PRISM_TYPE2_MACTIME
:
747 mactime
= tvb_get_uint32(tvb
, offset
, byte_order
);
748 phdr
.has_tsf_timestamp
= 1;
749 phdr
.tsf_timestamp
= mactime
;
751 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_mactime
, tvb
, offset
, 4, byte_order
);
752 proto_item_append_text(ti_did
, " %d", mactime
);
756 case PRISM_TYPE1_CHANNEL
:
757 case PRISM_TYPE2_CHANNEL
:
758 channel
= tvb_get_uint32(tvb
, offset
, byte_order
);
759 phdr
.has_channel
= true;
760 phdr
.channel
= channel
;
762 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_channel
, tvb
, offset
, 4, byte_order
);
763 proto_item_append_text(ti_did
, " %u", channel
);
765 col_add_fstr(pinfo
->cinfo
, COL_FREQ_CHAN
, "%u", channel
);
768 case PRISM_TYPE1_RSSI
:
769 case PRISM_TYPE2_RSSI
:
770 signal_dbm
= tvb_get_uint32(tvb
, offset
, byte_order
);
771 phdr
.has_signal_dbm
= 1;
772 phdr
.signal_dbm
= signal_dbm
;
774 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_rssi
, tvb
, offset
, 4, byte_order
);
775 proto_item_append_text(ti_did
, " %d", signal_dbm
);
777 col_add_fstr(pinfo
->cinfo
, COL_RSSI
, "%d", signal_dbm
);
783 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_sq
, tvb
, offset
, 4, byte_order
);
784 proto_item_append_text(ti_did
, " 0x%x", tvb_get_uint32(tvb
, offset
, byte_order
) );
788 case PRISM_TYPE1_SIGNAL
:
789 case PRISM_TYPE2_SIGNAL
:
791 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_signal
, tvb
, offset
, 4, byte_order
);
792 proto_item_append_text(ti_did
, " 0x%x", tvb_get_uint32(tvb
, offset
, byte_order
) );
796 case PRISM_TYPE1_NOISE
:
797 case PRISM_TYPE2_NOISE
:
799 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_noise
, tvb
, offset
, 4, byte_order
);
800 proto_item_append_text(ti_did
, " 0x%x", tvb_get_uint32(tvb
, offset
, byte_order
) );
804 case PRISM_TYPE1_RATE
:
805 case PRISM_TYPE2_RATE
:
806 rate
= tvb_get_uint32(tvb
, offset
, byte_order
);
807 phdr
.has_data_rate
= true;
808 phdr
.data_rate
= rate
;
810 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_rate
, tvb
, offset
, 4, byte_order
);
811 proto_item_append_text(ti_did
, " %s Mb/s", prism_rate_return(pinfo
->pool
, rate
));
813 col_add_str(pinfo
->cinfo
, COL_TX_RATE
, prism_rate_return(pinfo
->pool
, rate
));
816 case PRISM_TYPE1_RATE_SIG_A1
:
817 case PRISM_TYPE2_RATE_SIG_A1
:
819 * XXX - always little-endian, or same byte order as the
820 * rest of the Prism header?
822 rate_phy1
= tvb_get_letohl(tvb
, offset
);
824 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_sig_a1
, tvb
, offset
, 4, byte_order
);
825 proto_item_append_text(ti_did
, " 0x%x", tvb_get_letohl(tvb
, offset
));
829 case PRISM_TYPE1_RATE_SIG_A2
:
830 case PRISM_TYPE2_RATE_SIG_A2
:
832 * XXX - always little-endian, or same byte order as the
833 * rest of the Prism header?
835 rate_phy2
= tvb_get_letohl(tvb
, offset
);
837 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_sig_a2
, tvb
, offset
, 4, byte_order
);
838 proto_item_append_text(ti_did
, " 0x%x", tvb_get_letohl(tvb
, offset
));
842 case PRISM_TYPE1_RATE_SIG_B
:
843 case PRISM_TYPE2_RATE_SIG_B
:
844 if (tree
&& rate_phy1
&& rate_phy2
) {
845 proto_item
*sig_sub_item
;
847 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_sig_b
, tvb
, offset
, 4, byte_order
);
848 proto_item_append_text(ti_did
, " 0x%x", tvb_get_letohl(tvb
, offset
));
850 sig_sub_item
= proto_tree_add_item(prism_tree
, hf_ieee80211_prism_did_sig_rate_field
, tvb
, offset
, 4, byte_order
);
851 proto_item_append_text(sig_sub_item
, " %s", prism_rate_return_sig(pinfo
->pool
, rate_phy1
, rate_phy2
, &phdr
));
855 case PRISM_TYPE1_ISTX
:
856 case PRISM_TYPE2_ISTX
:
858 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_istx
, tvb
, offset
, 4, byte_order
);
859 proto_item_append_text(ti_did
, " 0x%x", tvb_get_uint32(tvb
, offset
, byte_order
) );
863 case PRISM_TYPE1_FRMLEN
:
864 case PRISM_TYPE2_FRMLEN
:
866 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_frmlen
, tvb
, offset
, 4, byte_order
);
867 proto_item_append_text(ti_did
, " %d", tvb_get_uint32(tvb
, offset
, byte_order
));
872 proto_tree_add_item(prism_did_tree
, hf_ieee80211_prism_did_unknown
, tvb
, offset
, 4, byte_order
);
880 * The only DIDs that directly indicate the packet modulation
881 * are the SIG_A1 and SIG_A2 DIDs; if they're not present, we
882 * ned to use some other way to determine the packet modulation,
883 * so, if the modulation is unknown at this point:
885 * if the data rate is 1 Mb/s or 2 Mb/s, the packet was
886 * transmitted using the 802.11 legacy DSSS modulation
887 * (we ignore the IR PHY - was it ever implemented?);
889 * if the data rate is 5 Mb/s or 11 Mb/s, the packet
890 * was transmitted using the 802.11b DSSS/CCK modulation
891 * (or the now-obsolete DSSS/PBCC modulation; *if* we can
892 * rely on the channel/xchannel field's "CCK channel" and
893 * "Dynamic CCK-OFDM channel" flags, the absence of either
894 * flag would presumably indicate DSSS/PBCC);
896 * if the data rate is 22 Mb/s or 33 Mb/s, the packet was
897 * transmitted using the 802.11b DSSS/PBCC modulation (as
898 * those speeds aren't supported by DSSS/CCK);
900 * if the data rate is one of the OFDM rates for the 11a
901 * OFDM PHY and the OFDM part of the 11g ERP PHY, the
902 * packet was transmitted with the 11g/11a OFDM modulation -
903 * we distinguish between them based on the channel, if we
906 * In addition, if they *are* present, and indicate that the
907 * modulation uses OFDM and isn't HT, VHT, or HE, all we know
908 * from that is that it's 11a or 11g, not which of those it
909 * is. We use the channel to distinguish between them.
911 if (phdr
.has_data_rate
) {
912 if (phdr
.phy
== PHDR_802_11_PHY_UNKNOWN
) {
914 * We don't know they PHY, but we do have the
915 * data rate; try to guess it based on the
916 * data rate and center frequency.
918 if (RATE_IS_DSSS(phdr
.data_rate
)) {
920 phdr
.phy
= PHDR_802_11_PHY_11B
;
921 } else if (RATE_IS_OFDM(phdr
.data_rate
)) {
922 /* 11a or 11g, depending on the band. */
923 if (phdr
.has_channel
) {
924 if (CHAN_IS_BG(phdr
.channel
)) {
926 phdr
.phy
= PHDR_802_11_PHY_11G
;
929 phdr
.phy
= PHDR_802_11_PHY_11A
;
933 } else if (phdr
.phy
== PHDR_802_11_PHY_11A
) {
935 * All we know is that it's OFDM; we guessed
936 * 11a in prism_rate_return_sig(), but if
937 * the channel is 2.4 GHz channel, it's
940 if (phdr
.has_channel
) {
941 if (CHAN_IS_BG(phdr
.channel
)) {
943 phdr
.phy
= PHDR_802_11_PHY_11G
;
946 if (RATE_IS_DSSS(phdr
.data_rate
)) {
948 phdr
.phy
= PHDR_802_11_PHY_11B
;
953 /* dissect the 802.11 header next */
954 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
955 call_dissector_with_data(ieee80211_radio_handle
, next_tvb
, pinfo
, tree
, (void *)&phdr
);
956 return tvb_captured_length(tvb
);
959 static hf_register_info hf_prism
[] = {
960 /* Prism-specific header fields
961 XXX - make as many of these generic as possible. */
962 { &hf_ieee80211_prism_msgcode
,
963 {"Message Code", "prism.msgcode", FT_UINT32
, BASE_HEX
, NULL
, 0x0,
966 { &hf_ieee80211_prism_msglen
,
967 {"Message Length", "prism.msglen", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
970 { &hf_ieee80211_prism_devname
,
971 {"Device Name", "prism.devname", FT_STRING
, BASE_NONE
, NULL
, 0x0,
974 { &hf_ieee80211_prism_did
,
975 {"DID", "prism.did", FT_NONE
, BASE_NONE
, NULL
, 0x0,
978 { &hf_ieee80211_prism_did_type
,
979 {"DID", "prism.did.type", FT_UINT32
, BASE_HEX
, VALS(prism_did_vals
), 0x0,
980 "Different ID for each parameter", HFILL
}},
982 { &hf_ieee80211_prism_did_status
,
983 {"Status", "prism.did.status", FT_UINT16
, BASE_DEC
, VALS(prism_status_vals
), 0x0,
984 "Supplied by the driver or not", HFILL
}},
986 { &hf_ieee80211_prism_did_length
,
987 {"Length", "prism.did.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
988 "Length of data", HFILL
}},
990 { &hf_ieee80211_prism_did_hosttime
,
991 {"Host Time", "prism.did.hosttime", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
992 "In jiffies - for our system this is in 10ms units", HFILL
}},
994 { &hf_ieee80211_prism_did_mactime
,
995 {"MAC timestamp (lower 32 bits)", "prism.did.mactime", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
996 "Lower 32 bits of value in microseconds of the MAC's Time Synchronization Function timer when the first bit of the MPDU arrived at the MAC.", HFILL
}},
998 { &hf_ieee80211_prism_did_channel
,
999 {"Channel", "prism.did.channel", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1002 { &hf_ieee80211_prism_did_rssi
,
1003 {"RSSI", "prism.did.rssi", FT_INT32
, BASE_DEC
, NULL
, 0x0,
1006 { &hf_ieee80211_prism_did_sq
,
1007 {"Signal Quality", "prism.did.sq", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1010 { &hf_ieee80211_prism_did_signal
,
1011 {"Signal", "prism.did.signal", FT_INT32
, BASE_DEC
, NULL
, 0x0,
1014 { &hf_ieee80211_prism_did_noise
,
1015 {"Noise", "prism.did.noise", FT_INT32
, BASE_DEC
, NULL
, 0x0,
1018 { &hf_ieee80211_prism_did_rate
,
1019 {"Data rate (Mb/s)", "prism.did.rate", FT_UINT32
, BASE_CUSTOM
, CF_FUNC(prism_rate_base_custom
), 0x0,
1020 "Speed this frame was sent/received at", HFILL
}},
1022 { &hf_ieee80211_prism_did_sig_a1
,
1023 {"SIG_A1", "prism.did.siga1", FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1026 { &hf_ieee80211_prism_did_sig_a2
,
1027 {"SIG_A2", "prism.did.siga2", FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1030 { &hf_ieee80211_prism_did_sig_b
,
1031 {"SIG", "prism.did.sigb", FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1034 { &hf_ieee80211_prism_did_sig_rate_field
,
1035 {"SIG Field", "prism.did.sigab", FT_NONE
, BASE_NONE
, 0, 0x0,
1038 { &hf_ieee80211_prism_did_istx
,
1039 {"IsTX", "prism.did.istx", FT_UINT32
, BASE_HEX
, VALS(prism_istx_vals
), 0x0,
1040 "Type of packet (RX or TX?)", HFILL
}},
1042 { &hf_ieee80211_prism_did_frmlen
,
1043 {"Frame Length", "prism.did.frmlen", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1044 "Length of the following frame in bytes", HFILL
}},
1046 { &hf_ieee80211_prism_did_unknown
,
1047 {"Unknown DID Field", "prism.did.unknown", FT_UINT32
, BASE_HEX_DEC
, NULL
, 0x0,
1051 static int *tree_array
[] = {
1057 void proto_register_ieee80211_prism(void)
1059 proto_prism
= proto_register_protocol("Prism capture header", "Prism",
1061 proto_register_field_array(proto_prism
, hf_prism
, array_length(hf_prism
));
1062 proto_register_subtree_array(tree_array
, array_length(tree_array
));
1064 prism_handle
= register_dissector("prism", dissect_prism
, proto_prism
);
1067 void proto_reg_handoff_ieee80211_prism(void)
1069 capture_dissector_handle_t ieee80211_prism_cap_handle
;
1071 dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE_802_11_PRISM
, prism_handle
);
1072 ieee80211_handle
= find_dissector_add_dependency("wlan", proto_prism
);
1073 ieee80211_radio_handle
= find_dissector_add_dependency("wlan_radio", proto_prism
);
1074 wlancap_handle
= find_dissector_add_dependency("wlancap", proto_prism
);
1076 ieee80211_prism_cap_handle
= create_capture_dissector_handle(capture_prism
, proto_prism
);
1077 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE_802_11_PRISM
, ieee80211_prism_cap_handle
);
1079 ieee80211_cap_handle
= find_capture_dissector("ieee80211");
1080 wlancap_cap_handle
= find_capture_dissector("wlancap");
1089 * indent-tabs-mode: nil
1092 * ex: set shiftwidth=4 tabstop=8 expandtab:
1093 * :indentSize=4:tabSize=8:noTabs=true: