/src/wireshark/epan/dissectors/packet-ieee80211-prism.c
Line | Count | Source |
1 | | /* packet-ieee80211-prism.c |
2 | | * Routines for Prism monitoring mode header dissection |
3 | | * |
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 |
9 | | * |
10 | | * Copied from README.developer |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | * |
14 | | */ |
15 | | |
16 | | #include "config.h" |
17 | | |
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" |
23 | | |
24 | | void proto_register_ieee80211_prism(void); |
25 | | void proto_reg_handoff_ieee80211_prism(void); |
26 | | |
27 | 0 | #define SHORT_STR 256 |
28 | | |
29 | | static dissector_handle_t wlancap_handle; |
30 | | static dissector_handle_t ieee80211_handle; |
31 | | static dissector_handle_t ieee80211_radio_handle; |
32 | | |
33 | | static capture_dissector_handle_t ieee80211_cap_handle; |
34 | | static capture_dissector_handle_t wlancap_cap_handle; |
35 | | |
36 | | static int proto_prism; |
37 | | |
38 | | /* Prism radio header */ |
39 | | |
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; |
58 | | |
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; |
64 | | |
65 | | |
66 | | static int ett_prism; |
67 | | static int ett_prism_did; |
68 | | static int ett_sig_ab; |
69 | | |
70 | | static dissector_handle_t prism_handle; |
71 | | |
72 | | /* |
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 |
76 | | * data. |
77 | | * |
78 | | * Support by Tim Newsham |
79 | | * |
80 | | * A value from the header. |
81 | | * |
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: |
85 | | * |
86 | | * the "did" identifies what the value is (i.e., what it's the value |
87 | | * of); |
88 | | * |
89 | | * "status" is 0 if the value is present or 1 if it's absent; |
90 | | * |
91 | | * "len" is the length of the value (always 4, in that code); |
92 | | * |
93 | | * "data" is the value of the data (or 0 if not present). |
94 | | * |
95 | | * Note: all of those values are in the *host* byte order of the machine |
96 | | * on which the capture was written. |
97 | | */ |
98 | | |
99 | | |
100 | | /* |
101 | | * Header attached during Prism monitor mode. |
102 | | * |
103 | | * At least according to one paper I've seen, the Prism 2.5 chip set |
104 | | * provides: |
105 | | * |
106 | | * RSSI (receive signal strength indication) is "the total power |
107 | | * received by the radio hardware while receiving the frame, |
108 | | * including signal, interference, and background noise"; |
109 | | * |
110 | | * "silence value" is "the total power observed just before the |
111 | | * start of the frame". |
112 | | * |
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. |
118 | | * |
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. |
124 | | * |
125 | | * XXX - what about other drivers that supply Prism headers, such as |
126 | | * old versions of the MadWifi driver? |
127 | | * |
128 | | * I'm not sure where these DID values come from, but they work with |
129 | | * at least one capture file. However, in |
130 | | * |
131 | | * https://ask.wireshark.org/questions/14963/how-to-get-the-field-did-unknown-4041-into-the-column |
132 | | * |
133 | | * somebody reports a capture where *different* DID values, corresponding |
134 | | * to |
135 | | * |
136 | | * http://www.martin.cc/linux/prism |
137 | | * |
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). |
140 | | */ |
141 | | |
142 | 0 | #define PRISM_HEADER_LENGTH 144 /* Default Prism Header Length */ |
143 | | |
144 | | /* |
145 | | * Message code values. |
146 | | * |
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. |
152 | | */ |
153 | 6 | #define PRISM_TYPE1_MSGCODE 0x00000044 /* Monitor Frame */ |
154 | 4 | #define PRISM_TYPE2_MSGCODE 0x00000041 |
155 | | |
156 | | /* |
157 | | * DID codes - PRISM_TYPE1_xxx are the non-home.martin.cc values, and |
158 | | * PRISM_TYPE2_xxx are the home.martin.cc values. |
159 | | */ |
160 | 0 | #define PRISM_TYPE1_HOSTTIME 0x00010044 /* Host time element */ |
161 | 0 | #define PRISM_TYPE2_HOSTTIME 0x00001041 |
162 | 0 | #define PRISM_TYPE1_MACTIME 0x00020044 /* Mac time element */ |
163 | 0 | #define PRISM_TYPE2_MACTIME 0x00002041 |
164 | 0 | #define PRISM_TYPE1_CHANNEL 0x00030044 /* Channel element */ |
165 | 0 | #define PRISM_TYPE2_CHANNEL 0x00003041 |
166 | 0 | #define PRISM_TYPE1_RSSI 0x00040044 /* RSSI element */ |
167 | 0 | #define PRISM_TYPE2_RSSI 0x00004041 |
168 | 0 | #define PRISM_TYPE1_SQ 0x00050044 /* SQ element */ |
169 | 0 | #define PRISM_TYPE2_SQ 0x00005041 |
170 | 0 | #define PRISM_TYPE1_SIGNAL 0x00060044 /* Signal element */ |
171 | 0 | #define PRISM_TYPE2_SIGNAL 0x00006041 |
172 | 0 | #define PRISM_TYPE1_NOISE 0x00070044 /* Noise element */ |
173 | 0 | #define PRISM_TYPE2_NOISE 0x00007041 |
174 | 0 | #define PRISM_TYPE1_RATE 0x00080044 /* Rate element */ |
175 | 0 | #define PRISM_TYPE2_RATE 0x00008041 |
176 | 0 | #define PRISM_TYPE1_ISTX 0x00090044 /* Is Tx frame */ |
177 | 0 | #define PRISM_TYPE2_ISTX 0x00009041 |
178 | 0 | #define PRISM_TYPE1_FRMLEN 0x000A0044 /* Frame length */ |
179 | 0 | #define PRISM_TYPE2_FRMLEN 0x0000A041 |
180 | | |
181 | | /* Qualcomm extensions */ |
182 | 0 | #define PRISM_TYPE1_RATE_SIG_A1 0x000B0044 /* VHT SIGA1 element */ |
183 | 0 | #define PRISM_TYPE2_RATE_SIG_A1 0x0000B044 |
184 | 0 | #define PRISM_TYPE1_RATE_SIG_A2 0x000C0044 /* VHT SIGA2 element */ |
185 | 0 | #define PRISM_TYPE2_RATE_SIG_A2 0x0000C044 |
186 | 0 | #define PRISM_TYPE1_RATE_SIG_B 0x000D0044 /* VHT SIGB element */ |
187 | 0 | #define PRISM_TYPE2_RATE_SIG_B 0x0000D044 /* VHT SIGB element */ |
188 | | |
189 | | static const value_string prism_did_vals[] = |
190 | | { |
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" }, |
211 | | |
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" }, |
219 | | { 0, NULL} |
220 | | }; |
221 | | |
222 | | /* |
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). |
227 | | */ |
228 | | static const value_string prism_status_vals[] = |
229 | | { |
230 | | { 0, "Supplied" }, |
231 | | { 1, "Not Supplied" }, |
232 | | { 0, NULL} |
233 | | }; |
234 | | |
235 | | static const value_string prism_istx_vals[] = |
236 | | { |
237 | | { 0, "Rx Packet" }, |
238 | | { 1, "Tx Packet" }, |
239 | | { 0, NULL} |
240 | | }; |
241 | | |
242 | | static void |
243 | | prism_rate_base_custom(char *result, uint32_t rate) |
244 | 0 | { |
245 | 0 | snprintf(result, ITEM_LABEL_LENGTH, "%u.%u", rate /2, rate & 1 ? 5 : 0); |
246 | 0 | } |
247 | | |
248 | | static char * |
249 | | prism_rate_return(wmem_allocator_t *scope, uint32_t rate) |
250 | 0 | { |
251 | 0 | char *result=NULL; |
252 | 0 | result = (char *)wmem_alloc(scope, SHORT_STR); |
253 | 0 | result[0] = '\0'; |
254 | 0 | prism_rate_base_custom(result, rate); |
255 | |
|
256 | 0 | return result; |
257 | 0 | } |
258 | | |
259 | | |
260 | | /* HT20 Rate table MAX NSS = 4 */ |
261 | | static const unsigned int ht_20_tbl[32][2] = |
262 | | { |
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 */ |
295 | | }; |
296 | | |
297 | | /* HT40 Rate table MAX NSS = 4 */ |
298 | | static const unsigned int ht_40_tbl[32][2] = |
299 | | { |
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 */ |
332 | | |
333 | | /* VHT20 Rate Table MAX NSS = 4 */ |
334 | | static const unsigned int vht_20_tbl[10][8] = |
335 | | { |
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 */ |
346 | | }; |
347 | | |
348 | | /* VHT40 Rate Table MAX NSS = 4 */ |
349 | | static const unsigned int vht_40_tbl[10][8] = |
350 | | { |
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 */ |
361 | | }; |
362 | | |
363 | | /* VHT80 Rate Table MAX NSS = 4 */ |
364 | | static const unsigned int vht_80_tbl[10][8] = |
365 | | { |
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 */ |
376 | | }; |
377 | | |
378 | | /* VHT160 Rate Table MAX NSS = 4 */ |
379 | | static const unsigned int vht_160_tbl[10][8] = |
380 | | { |
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 */ |
391 | | }; |
392 | | |
393 | | |
394 | | static char * |
395 | | prism_rate_return_sig(wmem_allocator_t *scope, uint32_t rate_phy1, uint32_t rate_phy2, struct ieee_802_11_phdr *phdr) |
396 | 0 | { |
397 | 0 | char *result = NULL; |
398 | 0 | unsigned int mcs, base, pream_type, disp_rate, bw, sgi, ldpc, stbc, groupid, txbf; |
399 | 0 | bool su_ppdu = false; |
400 | 0 | unsigned int partial_aid, nsts_u1, nsts_u2, nsts_u3, nsts_u4; |
401 | 0 | unsigned int sig_a_1, sig_a_2, nss = 1, nsts_su, signal_type; |
402 | 0 | unsigned int dsss_tbl[] = {22, 11, 4, 2}; |
403 | 0 | static const unsigned int bw_map[] = { 0, 1, 4, 11 }; |
404 | | |
405 | | /* |
406 | | * Qualcomm Atheros: Display Nss, MCS/Rate, BW, sgi, LDPC, STBC info |
407 | | */ |
408 | 0 | pream_type = rate_phy1 & 0xF; |
409 | 0 | switch (pream_type) { |
410 | | |
411 | 0 | case 0: /* OFDM */ |
412 | 0 | phdr->phy = PHDR_802_11_PHY_11A; /* or 11g? */ |
413 | 0 | mcs = (rate_phy1 >> 4) & 0xF; |
414 | 0 | base = (mcs & 0x4) ? 9 : 6; |
415 | 0 | mcs &= ~0x4; |
416 | 0 | mcs = base << (11 - mcs); |
417 | 0 | mcs = (mcs > 54) ? 54 : mcs; |
418 | 0 | phdr->has_data_rate = 1; |
419 | 0 | phdr->data_rate = mcs * 2; |
420 | 0 | signal_type = rate_phy1 & (1 << 12); |
421 | 0 | bw = 20 << ((rate_phy1 >> 13) & 0x3); |
422 | 0 | result = wmem_strdup_printf(scope, |
423 | 0 | "Rate: %u.%u Mb/s OFDM Signaling:%s BW %d", |
424 | 0 | mcs, 0, signal_type ? "Dynamic" : "Static", bw |
425 | 0 | ); |
426 | 0 | break; |
427 | | |
428 | 0 | case 1: /* DSSS */ |
429 | 0 | phdr->phy = PHDR_802_11_PHY_11B; |
430 | 0 | mcs = (rate_phy1 >> 4) & 0xF; |
431 | 0 | base = (mcs & 0x4) ? 1 : 0; |
432 | 0 | phdr->phy_info.info_11b.has_short_preamble = 1; |
433 | 0 | phdr->phy_info.info_11b.short_preamble = base; |
434 | 0 | mcs &= ~0x4; |
435 | 0 | mcs = (mcs - 8) & 0x3; |
436 | 0 | disp_rate = dsss_tbl[mcs]; |
437 | 0 | phdr->has_data_rate = 1; |
438 | 0 | phdr->data_rate = disp_rate; |
439 | 0 | result = wmem_strdup_printf(scope, "Rate: %u.%u Mb/s DSSS %s", |
440 | 0 | disp_rate / 2, |
441 | 0 | (disp_rate & 1) ? 5 : 0, |
442 | 0 | base ? "[SP]" : "[LP]"); |
443 | 0 | break; |
444 | | |
445 | 0 | case 2: /* HT */ |
446 | 0 | phdr->phy = PHDR_802_11_PHY_11N; |
447 | 0 | sig_a_1 = (rate_phy1 >> 4) & 0xFFFF; |
448 | 0 | sig_a_2 = (rate_phy2) & 0xFFF; |
449 | 0 | mcs = sig_a_1 & 0x7f; |
450 | 0 | phdr->phy_info.info_11n.has_mcs_index = 1; |
451 | 0 | phdr->phy_info.info_11n.mcs_index = mcs; |
452 | 0 | bw = 20 << ((sig_a_1 >> 7) & 1); |
453 | 0 | phdr->phy_info.info_11n.has_bandwidth = 1; |
454 | 0 | phdr->phy_info.info_11n.bandwidth = ((sig_a_1 >> 7) & 1); |
455 | 0 | sgi = (sig_a_2 >> 7) & 1; |
456 | 0 | phdr->phy_info.info_11n.has_short_gi = 1; |
457 | 0 | phdr->phy_info.info_11n.short_gi = sgi; |
458 | 0 | ldpc = (sig_a_2 >> 6) & 1; |
459 | 0 | phdr->phy_info.info_11n.has_fec = 1; |
460 | 0 | phdr->phy_info.info_11n.fec = ldpc; |
461 | 0 | stbc = ((sig_a_2 >> 4) & 3)?1:0; |
462 | 0 | phdr->phy_info.info_11n.has_stbc_streams = 1; |
463 | 0 | phdr->phy_info.info_11n.stbc_streams = stbc; |
464 | 0 | phdr->phy_info.info_11n.has_ness = 1; |
465 | 0 | phdr->phy_info.info_11n.ness = (sig_a_2 >> 8) & 3; |
466 | 0 | nss = (mcs >> 3) + 1; |
467 | | /* Check limits */ |
468 | 0 | disp_rate = 0; |
469 | 0 | if ((nss <= 4) && (mcs <= 31) && ((bw == 20) || (bw==40))){ |
470 | 0 | switch (bw) { |
471 | | |
472 | 0 | case 20: |
473 | 0 | if (sgi) { |
474 | 0 | disp_rate = ht_20_tbl[mcs][1]; |
475 | 0 | } else { |
476 | 0 | disp_rate = ht_20_tbl[mcs][0]; |
477 | 0 | } |
478 | 0 | break; |
479 | | |
480 | 0 | case 40: |
481 | 0 | if (sgi) { |
482 | 0 | disp_rate = ht_40_tbl[mcs][1]; |
483 | 0 | } else { |
484 | 0 | disp_rate = ht_40_tbl[mcs][0]; |
485 | 0 | } |
486 | 0 | break; |
487 | 0 | } |
488 | 0 | } |
489 | 0 | result = wmem_strdup_printf(scope, |
490 | 0 | "Rate: %u.%u Mb/s HT MCS %d NSS %d BW %d MHz %s %s %s", |
491 | 0 | disp_rate/10, disp_rate%10, mcs, nss, bw, |
492 | 0 | sgi ? "[SGI]" : "", |
493 | 0 | ldpc ? "[LDPC]" : "", |
494 | 0 | stbc ? "[STBC]" : ""); |
495 | 0 | break; |
496 | | |
497 | 0 | case 3: /* VHT */ |
498 | 0 | phdr->phy = PHDR_802_11_PHY_11AC; |
499 | 0 | sig_a_1 = (rate_phy1 >> 4) & 0xFFFFFF; |
500 | 0 | sig_a_2 = (rate_phy2) & 0xFFFFFF; |
501 | 0 | stbc = (sig_a_1 >> 3) & 1; |
502 | 0 | phdr->phy_info.info_11ac.has_stbc = 1; |
503 | 0 | phdr->phy_info.info_11ac.stbc = stbc; |
504 | 0 | sgi = sig_a_2 & 1; |
505 | 0 | phdr->phy_info.info_11ac.has_short_gi = 1; |
506 | 0 | phdr->phy_info.info_11ac.short_gi = sgi; |
507 | 0 | bw = 20 << (sig_a_1 & 3); |
508 | 0 | phdr->phy_info.info_11ac.has_bandwidth = 1; |
509 | 0 | phdr->phy_info.info_11ac.bandwidth = bw_map[(sig_a_1 & 3)]; |
510 | 0 | ldpc = (sig_a_2 >> 2) & 1; |
511 | 0 | phdr->phy_info.info_11ac.has_fec = 1; |
512 | 0 | phdr->phy_info.info_11ac.fec = ldpc; |
513 | 0 | groupid = (sig_a_1 >> 4) & 0x3F; |
514 | 0 | phdr->phy_info.info_11ac.has_group_id = 1; |
515 | 0 | phdr->phy_info.info_11ac.group_id = groupid; |
516 | |
|
517 | 0 | if (groupid == 0 || groupid == 63) |
518 | 0 | su_ppdu = true; |
519 | |
|
520 | 0 | disp_rate = 0; |
521 | |
|
522 | 0 | if (su_ppdu) { |
523 | 0 | nsts_su = (sig_a_1 >> 10) & 0x7; |
524 | 0 | if (stbc) |
525 | 0 | nss = nsts_su >> 2; |
526 | 0 | else |
527 | 0 | nss = nsts_su; |
528 | 0 | ++nss; |
529 | 0 | mcs = (sig_a_2 >> 4) & 0xF; |
530 | 0 | phdr->phy_info.info_11ac.mcs[0] = mcs; |
531 | 0 | phdr->phy_info.info_11ac.nss[0] = nss; |
532 | 0 | txbf = (sig_a_2 >> 8) & 1; |
533 | 0 | phdr->phy_info.info_11ac.has_beamformed = 1; |
534 | 0 | phdr->phy_info.info_11ac.beamformed = txbf; |
535 | 0 | partial_aid = (sig_a_1 >> 13) & 0x1FF; |
536 | 0 | phdr->phy_info.info_11ac.has_partial_aid = 1; |
537 | 0 | phdr->phy_info.info_11ac.partial_aid = partial_aid; |
538 | | |
539 | | /* Check limits */ |
540 | 0 | if ((nss <= 4) && (mcs <= 9) && ((bw == 20) || (bw==40) || (bw==80) || bw==160)) { |
541 | 0 | switch (bw) { |
542 | | |
543 | 0 | case 20: |
544 | 0 | if (sgi) { |
545 | 0 | disp_rate = vht_20_tbl[mcs][(nss * 2) - 1]; |
546 | 0 | } else { |
547 | 0 | disp_rate = vht_20_tbl[mcs][(nss - 1) * 2]; |
548 | 0 | } |
549 | 0 | break; |
550 | | |
551 | 0 | case 40: |
552 | 0 | if (sgi) { |
553 | 0 | disp_rate = vht_40_tbl[mcs][(nss * 2) - 1]; |
554 | 0 | } else { |
555 | 0 | disp_rate = vht_40_tbl[mcs][(nss - 1) * 2]; |
556 | 0 | } |
557 | 0 | break; |
558 | | |
559 | 0 | case 80: |
560 | 0 | if (sgi) { |
561 | 0 | disp_rate = vht_80_tbl[mcs][(nss * 2) - 1]; |
562 | 0 | } else { |
563 | 0 | disp_rate = vht_80_tbl[mcs][(nss - 1) * 2]; |
564 | 0 | } |
565 | 0 | break; |
566 | | |
567 | 0 | case 160: |
568 | 0 | if (sgi) { |
569 | 0 | disp_rate = vht_160_tbl[mcs][(nss * 2) - 1]; |
570 | 0 | } else { |
571 | 0 | disp_rate = vht_160_tbl[mcs][(nss - 1) * 2]; |
572 | 0 | } |
573 | 0 | break; |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | 0 | result = wmem_strdup_printf(scope, |
578 | 0 | "Rate: %u.%u Mb/s VHT MCS %d NSS %d Partial AID %d BW %d MHz %s %s %s GroupID %d %s %s", |
579 | 0 | disp_rate/10, disp_rate%10, |
580 | 0 | mcs, nss, partial_aid, bw, |
581 | 0 | sgi ? "[SGI]" : "", |
582 | 0 | ldpc ? "[LDPC]" : "", |
583 | 0 | stbc ? "[STBC]" : "", |
584 | 0 | groupid, |
585 | 0 | "[SU_PPDU]", |
586 | 0 | txbf ? "[TxBF]" : ""); |
587 | 0 | } else { |
588 | 0 | nsts_u1 = (sig_a_1 >> 10) & 0x7; |
589 | 0 | nsts_u2 = (sig_a_1 >> 13) & 0x7; |
590 | 0 | nsts_u3 = (sig_a_1 >> 16) & 0x7; |
591 | 0 | nsts_u4 = (sig_a_1 >> 19) & 0x7; |
592 | |
|
593 | 0 | result = wmem_strdup_printf(scope, |
594 | 0 | "VHT NSTS %d %d %d %d BW %d MHz %s %s %s GroupID %d %s", |
595 | 0 | nsts_u1, nsts_u2, nsts_u3, nsts_u4, bw, |
596 | 0 | sgi ? "[SGI]" : "", |
597 | 0 | ldpc ? "[LDPC]" : "", |
598 | 0 | stbc ? "[STBC]" : "", |
599 | 0 | groupid, |
600 | 0 | "[MU_PPDU]"); |
601 | 0 | } |
602 | 0 | break; |
603 | 0 | } |
604 | | |
605 | 0 | return result; |
606 | 0 | } |
607 | | |
608 | | static bool |
609 | | capture_prism(const unsigned char *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_) |
610 | 0 | { |
611 | 0 | uint32_t cookie; |
612 | |
|
613 | 0 | if (!BYTES_ARE_IN_FRAME(offset, len, 4)) |
614 | 0 | return false; |
615 | | |
616 | | /* Some captures with DLT_PRISM have the AVS WLAN header */ |
617 | 0 | cookie = pntohu32(pd); |
618 | 0 | if ((cookie == WLANCAP_MAGIC_COOKIE_V1) || |
619 | 0 | (cookie == WLANCAP_MAGIC_COOKIE_V2)) { |
620 | 0 | return call_capture_dissector(wlancap_cap_handle, pd, offset, len, cpinfo, pseudo_header); |
621 | 0 | } |
622 | | |
623 | | /* Prism header */ |
624 | 0 | if (!BYTES_ARE_IN_FRAME(offset, len, PRISM_HEADER_LENGTH)) |
625 | 0 | return false; |
626 | | |
627 | 0 | offset += PRISM_HEADER_LENGTH; |
628 | | |
629 | | /* 802.11 header follows */ |
630 | 0 | return call_capture_dissector(ieee80211_cap_handle, pd, offset, len, cpinfo, pseudo_header); |
631 | 0 | } |
632 | | |
633 | | static int |
634 | | dissect_prism(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
635 | 3 | { |
636 | 3 | proto_tree *prism_tree, *prism_did_tree = NULL; |
637 | 3 | proto_item *ti = NULL, *ti_did = NULL; |
638 | 3 | tvbuff_t *next_tvb; |
639 | 3 | int offset; |
640 | 3 | uint32_t msgcode, msglen, did, rate_phy1 = 0, rate_phy2 = 0; |
641 | 3 | unsigned byte_order; |
642 | 3 | uint16_t status; |
643 | 3 | const uint8_t *devname_p; |
644 | 3 | uint32_t mactime; |
645 | 3 | uint32_t channel; |
646 | 3 | uint32_t signal_dbm; |
647 | 3 | uint32_t rate; |
648 | 3 | struct ieee_802_11_phdr phdr; |
649 | | |
650 | 3 | offset = 0; |
651 | 3 | did = 0; |
652 | | |
653 | | /* handle the AVS header */ |
654 | 3 | msgcode = tvb_get_ntohl(tvb, offset); |
655 | 3 | if ((msgcode == WLANCAP_MAGIC_COOKIE_V1) || |
656 | 2 | (msgcode == WLANCAP_MAGIC_COOKIE_V2)) { |
657 | 0 | call_dissector(wlancap_handle, tvb, pinfo, tree); |
658 | 0 | return tvb_captured_length(tvb); |
659 | 0 | } |
660 | | |
661 | | /* |
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?). |
666 | | * |
667 | | * Check for both byte orders and use that to determine |
668 | | * the byte order of the fields in the Prism header. |
669 | | */ |
670 | 3 | if ((msgcode == PRISM_TYPE1_MSGCODE) || (msgcode == PRISM_TYPE2_MSGCODE)) { |
671 | | /* big-endian fetch matched */ |
672 | 0 | byte_order = ENC_BIG_ENDIAN; |
673 | 3 | } else if (((msgcode = tvb_get_letohl(tvb, offset)) == PRISM_TYPE1_MSGCODE) || |
674 | 2 | (msgcode == PRISM_TYPE2_MSGCODE)) { |
675 | | /* little-endian fetch matched */ |
676 | 0 | byte_order = ENC_LITTLE_ENDIAN; |
677 | 3 | } else { |
678 | | /* neither matched - try it as just 802.11 with no Prism header */ |
679 | 3 | call_dissector(ieee80211_handle, tvb, pinfo, tree); |
680 | 3 | return tvb_captured_length(tvb); |
681 | 3 | } |
682 | | |
683 | | /* We don't have any 802.11 metadata yet. */ |
684 | 0 | memset(&phdr, 0, sizeof(phdr)); |
685 | 0 | phdr.fcs_len = -1; |
686 | 0 | phdr.decrypted = false; |
687 | 0 | phdr.datapad = false; |
688 | 0 | phdr.phy = PHDR_802_11_PHY_UNKNOWN; |
689 | |
|
690 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Prism"); |
691 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
692 | |
|
693 | 0 | ti = proto_tree_add_item(tree, proto_prism, tvb, 0, 144, ENC_NA); |
694 | 0 | prism_tree = proto_item_add_subtree(ti, ett_prism); |
695 | | |
696 | | /* Message Code */ |
697 | 0 | proto_tree_add_item_ret_uint(prism_tree, hf_ieee80211_prism_msgcode, tvb, offset, 4, byte_order, &msgcode); |
698 | 0 | offset += 4; |
699 | | |
700 | | /* Message Length */ |
701 | 0 | proto_tree_add_item_ret_uint(prism_tree, hf_ieee80211_prism_msglen, tvb, offset, 4, byte_order, &msglen); |
702 | 0 | offset += 4; |
703 | | |
704 | | /* Device Name */ |
705 | 0 | proto_tree_add_item_ret_string(prism_tree, hf_ieee80211_prism_devname, tvb, offset, 16, ENC_ASCII|ENC_NA, pinfo->pool, &devname_p); |
706 | 0 | offset += 16; |
707 | |
|
708 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Device: %s, Message 0x%x, Length %d", devname_p, msgcode, msglen); |
709 | |
|
710 | 0 | while (offset < PRISM_HEADER_LENGTH) |
711 | 0 | { |
712 | | /* DID */ |
713 | 0 | if (tree) { |
714 | 0 | ti_did = proto_tree_add_item(prism_tree, hf_ieee80211_prism_did, tvb, offset, 12, ENC_NA); |
715 | 0 | prism_did_tree = proto_item_add_subtree(ti_did, ett_prism_did); |
716 | |
|
717 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_type, tvb, offset, 4, byte_order); |
718 | 0 | did = tvb_get_uint32(tvb, offset, byte_order); |
719 | 0 | proto_item_append_text(ti_did, " %s", val_to_str(pinfo->pool, did, prism_did_vals, "Unknown %x") ); |
720 | 0 | } |
721 | 0 | offset += 4; |
722 | | |
723 | | |
724 | | /* Status */ |
725 | 0 | proto_tree_add_item_ret_uint16(prism_did_tree, hf_ieee80211_prism_did_status, tvb, offset, 2, byte_order, &status); |
726 | 0 | offset += 2; |
727 | | |
728 | | /* Length */ |
729 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_length, tvb, offset, 2, byte_order); |
730 | 0 | offset += 2; |
731 | | |
732 | | /* Data, if present... */ |
733 | 0 | if (status == 0) { |
734 | 0 | switch (did) { |
735 | | |
736 | 0 | case PRISM_TYPE1_HOSTTIME: |
737 | 0 | case PRISM_TYPE2_HOSTTIME: |
738 | 0 | if (tree) { |
739 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_hosttime, tvb, offset, 4, byte_order); |
740 | 0 | proto_item_append_text(ti_did, " %d", tvb_get_uint32(tvb, offset, byte_order) ); |
741 | 0 | } |
742 | 0 | break; |
743 | | |
744 | 0 | case PRISM_TYPE1_MACTIME: |
745 | 0 | case PRISM_TYPE2_MACTIME: |
746 | 0 | mactime = tvb_get_uint32(tvb, offset, byte_order); |
747 | 0 | phdr.has_tsf_timestamp = 1; |
748 | 0 | phdr.tsf_timestamp = mactime; |
749 | 0 | if (tree) { |
750 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_mactime, tvb, offset, 4, byte_order); |
751 | 0 | proto_item_append_text(ti_did, " %d", mactime ); |
752 | 0 | } |
753 | 0 | break; |
754 | | |
755 | 0 | case PRISM_TYPE1_CHANNEL: |
756 | 0 | case PRISM_TYPE2_CHANNEL: |
757 | 0 | channel = tvb_get_uint32(tvb, offset, byte_order); |
758 | 0 | phdr.has_channel = true; |
759 | 0 | phdr.channel = channel; |
760 | 0 | if (tree) { |
761 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_channel, tvb, offset, 4, byte_order); |
762 | 0 | proto_item_append_text(ti_did, " %u", channel); |
763 | 0 | } |
764 | 0 | col_add_fstr(pinfo->cinfo, COL_FREQ_CHAN, "%u", channel); |
765 | 0 | break; |
766 | | |
767 | 0 | case PRISM_TYPE1_RSSI: |
768 | 0 | case PRISM_TYPE2_RSSI: |
769 | 0 | signal_dbm = tvb_get_uint32(tvb, offset, byte_order); |
770 | 0 | phdr.has_signal_dbm = 1; |
771 | 0 | phdr.signal_dbm = signal_dbm; |
772 | 0 | if (tree) { |
773 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_rssi, tvb, offset, 4, byte_order); |
774 | 0 | proto_item_append_text(ti_did, " %d", signal_dbm ); |
775 | 0 | } |
776 | 0 | col_add_fstr(pinfo->cinfo, COL_RSSI, "%d", signal_dbm); |
777 | 0 | break; |
778 | | |
779 | 0 | case PRISM_TYPE1_SQ: |
780 | 0 | case PRISM_TYPE2_SQ: |
781 | 0 | if (tree) { |
782 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_sq, tvb, offset, 4, byte_order); |
783 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_uint32(tvb, offset, byte_order) ); |
784 | 0 | } |
785 | 0 | break; |
786 | | |
787 | 0 | case PRISM_TYPE1_SIGNAL: |
788 | 0 | case PRISM_TYPE2_SIGNAL: |
789 | 0 | if (tree) { |
790 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_signal, tvb, offset, 4, byte_order); |
791 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_uint32(tvb, offset, byte_order) ); |
792 | 0 | } |
793 | 0 | break; |
794 | | |
795 | 0 | case PRISM_TYPE1_NOISE: |
796 | 0 | case PRISM_TYPE2_NOISE: |
797 | 0 | if (tree) { |
798 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_noise, tvb, offset, 4, byte_order); |
799 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_uint32(tvb, offset, byte_order) ); |
800 | 0 | } |
801 | 0 | break; |
802 | | |
803 | 0 | case PRISM_TYPE1_RATE: |
804 | 0 | case PRISM_TYPE2_RATE: |
805 | 0 | rate = tvb_get_uint32(tvb, offset, byte_order); |
806 | 0 | phdr.has_data_rate = true; |
807 | 0 | phdr.data_rate = rate; |
808 | 0 | if (tree) { |
809 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_rate, tvb, offset, 4, byte_order); |
810 | 0 | proto_item_append_text(ti_did, " %s Mb/s", prism_rate_return(pinfo->pool, rate)); |
811 | 0 | } |
812 | 0 | col_add_str(pinfo->cinfo, COL_TX_RATE, prism_rate_return(pinfo->pool, rate)); |
813 | 0 | break; |
814 | | |
815 | 0 | case PRISM_TYPE1_RATE_SIG_A1: |
816 | 0 | case PRISM_TYPE2_RATE_SIG_A1: |
817 | | /* |
818 | | * XXX - always little-endian, or same byte order as the |
819 | | * rest of the Prism header? |
820 | | */ |
821 | 0 | rate_phy1 = tvb_get_letohl(tvb, offset); |
822 | 0 | if (tree) { |
823 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_sig_a1, tvb, offset, 4, byte_order); |
824 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset)); |
825 | 0 | } |
826 | 0 | break; |
827 | | |
828 | 0 | case PRISM_TYPE1_RATE_SIG_A2: |
829 | 0 | case PRISM_TYPE2_RATE_SIG_A2: |
830 | | /* |
831 | | * XXX - always little-endian, or same byte order as the |
832 | | * rest of the Prism header? |
833 | | */ |
834 | 0 | rate_phy2 = tvb_get_letohl(tvb, offset); |
835 | 0 | if (tree) { |
836 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_sig_a2, tvb, offset, 4, byte_order); |
837 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset)); |
838 | 0 | } |
839 | 0 | break; |
840 | | |
841 | 0 | case PRISM_TYPE1_RATE_SIG_B: |
842 | 0 | case PRISM_TYPE2_RATE_SIG_B: |
843 | 0 | if (tree && rate_phy1 && rate_phy2) { |
844 | 0 | proto_item *sig_sub_item; |
845 | |
|
846 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_sig_b, tvb, offset, 4, byte_order); |
847 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset)); |
848 | |
|
849 | 0 | sig_sub_item = proto_tree_add_item(prism_tree, hf_ieee80211_prism_did_sig_rate_field, tvb, offset, 4, byte_order); |
850 | 0 | proto_item_append_text(sig_sub_item, " %s", prism_rate_return_sig(pinfo->pool, rate_phy1, rate_phy2, &phdr)); |
851 | 0 | } |
852 | 0 | break; |
853 | | |
854 | 0 | case PRISM_TYPE1_ISTX: |
855 | 0 | case PRISM_TYPE2_ISTX: |
856 | 0 | if (tree) { |
857 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_istx, tvb, offset, 4, byte_order); |
858 | 0 | proto_item_append_text(ti_did, " 0x%x", tvb_get_uint32(tvb, offset, byte_order) ); |
859 | 0 | } |
860 | 0 | break; |
861 | | |
862 | 0 | case PRISM_TYPE1_FRMLEN: |
863 | 0 | case PRISM_TYPE2_FRMLEN: |
864 | 0 | if (tree) { |
865 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_frmlen, tvb, offset, 4, byte_order); |
866 | 0 | proto_item_append_text(ti_did, " %d", tvb_get_uint32(tvb, offset, byte_order)); |
867 | 0 | } |
868 | 0 | break; |
869 | | |
870 | 0 | default: |
871 | 0 | proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_unknown, tvb, offset, 4, byte_order); |
872 | 0 | break; |
873 | 0 | } |
874 | 0 | } |
875 | 0 | offset += 4; |
876 | 0 | } |
877 | | |
878 | | /* |
879 | | * The only DIDs that directly indicate the packet modulation |
880 | | * are the SIG_A1 and SIG_A2 DIDs; if they're not present, we |
881 | | * ned to use some other way to determine the packet modulation, |
882 | | * so, if the modulation is unknown at this point: |
883 | | * |
884 | | * if the data rate is 1 Mb/s or 2 Mb/s, the packet was |
885 | | * transmitted using the 802.11 legacy DSSS modulation |
886 | | * (we ignore the IR PHY - was it ever implemented?); |
887 | | * |
888 | | * if the data rate is 5 Mb/s or 11 Mb/s, the packet |
889 | | * was transmitted using the 802.11b DSSS/CCK modulation |
890 | | * (or the now-obsolete DSSS/PBCC modulation; *if* we can |
891 | | * rely on the channel/xchannel field's "CCK channel" and |
892 | | * "Dynamic CCK-OFDM channel" flags, the absence of either |
893 | | * flag would presumably indicate DSSS/PBCC); |
894 | | * |
895 | | * if the data rate is 22 Mb/s or 33 Mb/s, the packet was |
896 | | * transmitted using the 802.11b DSSS/PBCC modulation (as |
897 | | * those speeds aren't supported by DSSS/CCK); |
898 | | * |
899 | | * if the data rate is one of the OFDM rates for the 11a |
900 | | * OFDM PHY and the OFDM part of the 11g ERP PHY, the |
901 | | * packet was transmitted with the 11g/11a OFDM modulation - |
902 | | * we distinguish between them based on the channel, if we |
903 | | * have it. |
904 | | * |
905 | | * In addition, if they *are* present, and indicate that the |
906 | | * modulation uses OFDM and isn't HT, VHT, or HE, all we know |
907 | | * from that is that it's 11a or 11g, not which of those it |
908 | | * is. We use the channel to distinguish between them. |
909 | | */ |
910 | 0 | if (phdr.has_data_rate) { |
911 | 0 | if (phdr.phy == PHDR_802_11_PHY_UNKNOWN) { |
912 | | /* |
913 | | * We don't know they PHY, but we do have the |
914 | | * data rate; try to guess it based on the |
915 | | * data rate and center frequency. |
916 | | */ |
917 | 0 | if (RATE_IS_DSSS(phdr.data_rate)) { |
918 | | /* 11b */ |
919 | 0 | phdr.phy = PHDR_802_11_PHY_11B; |
920 | 0 | } else if (RATE_IS_OFDM(phdr.data_rate)) { |
921 | | /* 11a or 11g, depending on the band. */ |
922 | 0 | if (phdr.has_channel) { |
923 | 0 | if (CHAN_IS_BG(phdr.channel)) { |
924 | | /* 11g */ |
925 | 0 | phdr.phy = PHDR_802_11_PHY_11G; |
926 | 0 | } else { |
927 | | /* 11a */ |
928 | 0 | phdr.phy = PHDR_802_11_PHY_11A; |
929 | 0 | } |
930 | 0 | } |
931 | 0 | } |
932 | 0 | } else if (phdr.phy == PHDR_802_11_PHY_11A) { |
933 | | /* |
934 | | * All we know is that it's OFDM; we guessed |
935 | | * 11a in prism_rate_return_sig(), but if |
936 | | * the channel is 2.4 GHz channel, it's |
937 | | * 11g. |
938 | | */ |
939 | 0 | if (phdr.has_channel) { |
940 | 0 | if (CHAN_IS_BG(phdr.channel)) { |
941 | | /* 11g */ |
942 | 0 | phdr.phy = PHDR_802_11_PHY_11G; |
943 | 0 | } |
944 | 0 | } |
945 | 0 | if (RATE_IS_DSSS(phdr.data_rate)) { |
946 | | /* DSSS, so 11b. */ |
947 | 0 | phdr.phy = PHDR_802_11_PHY_11B; |
948 | 0 | } |
949 | 0 | } |
950 | 0 | } |
951 | | |
952 | | /* dissect the 802.11 header next */ |
953 | 0 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
954 | 0 | call_dissector_with_data(ieee80211_radio_handle, next_tvb, pinfo, tree, (void *)&phdr); |
955 | 0 | return tvb_captured_length(tvb); |
956 | 0 | } |
957 | | |
958 | | static hf_register_info hf_prism[] = { |
959 | | /* Prism-specific header fields |
960 | | XXX - make as many of these generic as possible. */ |
961 | | { &hf_ieee80211_prism_msgcode, |
962 | | {"Message Code", "prism.msgcode", FT_UINT32, BASE_HEX, NULL, 0x0, |
963 | | NULL, HFILL }}, |
964 | | |
965 | | { &hf_ieee80211_prism_msglen, |
966 | | {"Message Length", "prism.msglen", FT_UINT32, BASE_DEC, NULL, 0x0, |
967 | | NULL, HFILL }}, |
968 | | |
969 | | { &hf_ieee80211_prism_devname, |
970 | | {"Device Name", "prism.devname", FT_STRING, BASE_NONE, NULL, 0x0, |
971 | | NULL, HFILL }}, |
972 | | |
973 | | { &hf_ieee80211_prism_did, |
974 | | {"DID", "prism.did", FT_NONE, BASE_NONE, NULL, 0x0, |
975 | | NULL, HFILL }}, |
976 | | |
977 | | { &hf_ieee80211_prism_did_type, |
978 | | {"DID", "prism.did.type", FT_UINT32, BASE_HEX, VALS(prism_did_vals), 0x0, |
979 | | "Different ID for each parameter", HFILL }}, |
980 | | |
981 | | { &hf_ieee80211_prism_did_status, |
982 | | {"Status", "prism.did.status", FT_UINT16, BASE_DEC, VALS(prism_status_vals), 0x0, |
983 | | "Supplied by the driver or not", HFILL }}, |
984 | | |
985 | | { &hf_ieee80211_prism_did_length, |
986 | | {"Length", "prism.did.length", FT_UINT16, BASE_DEC, NULL, 0x0, |
987 | | "Length of data", HFILL }}, |
988 | | |
989 | | { &hf_ieee80211_prism_did_hosttime, |
990 | | {"Host Time", "prism.did.hosttime", FT_UINT32, BASE_DEC, NULL, 0x0, |
991 | | "In jiffies - for our system this is in 10ms units", HFILL }}, |
992 | | |
993 | | { &hf_ieee80211_prism_did_mactime, |
994 | | {"MAC timestamp (lower 32 bits)", "prism.did.mactime", FT_UINT32, BASE_DEC, NULL, 0x0, |
995 | | "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 }}, |
996 | | |
997 | | { &hf_ieee80211_prism_did_channel, |
998 | | {"Channel", "prism.did.channel", FT_UINT32, BASE_DEC, NULL, 0x0, |
999 | | NULL, HFILL }}, |
1000 | | |
1001 | | { &hf_ieee80211_prism_did_rssi, |
1002 | | {"RSSI", "prism.did.rssi", FT_INT32, BASE_DEC, NULL, 0x0, |
1003 | | NULL, HFILL }}, |
1004 | | |
1005 | | { &hf_ieee80211_prism_did_sq, |
1006 | | {"Signal Quality", "prism.did.sq", FT_UINT32, BASE_DEC, NULL, 0x0, |
1007 | | NULL, HFILL }}, |
1008 | | |
1009 | | { &hf_ieee80211_prism_did_signal, |
1010 | | {"Signal", "prism.did.signal", FT_INT32, BASE_DEC, NULL, 0x0, |
1011 | | NULL, HFILL }}, |
1012 | | |
1013 | | { &hf_ieee80211_prism_did_noise, |
1014 | | {"Noise", "prism.did.noise", FT_INT32, BASE_DEC, NULL, 0x0, |
1015 | | NULL, HFILL }}, |
1016 | | |
1017 | | { &hf_ieee80211_prism_did_rate, |
1018 | | {"Data rate (Mb/s)", "prism.did.rate", FT_UINT32, BASE_CUSTOM, CF_FUNC(prism_rate_base_custom), 0x0, |
1019 | | "Speed this frame was sent/received at", HFILL }}, |
1020 | | |
1021 | | { &hf_ieee80211_prism_did_sig_a1, |
1022 | | {"SIG_A1", "prism.did.siga1", FT_UINT32, BASE_HEX, NULL, 0x0, |
1023 | | NULL, HFILL }}, |
1024 | | |
1025 | | { &hf_ieee80211_prism_did_sig_a2, |
1026 | | {"SIG_A2", "prism.did.siga2", FT_UINT32, BASE_HEX, NULL, 0x0, |
1027 | | NULL, HFILL }}, |
1028 | | |
1029 | | { &hf_ieee80211_prism_did_sig_b, |
1030 | | {"SIG", "prism.did.sigb", FT_UINT32, BASE_HEX, NULL, 0x0, |
1031 | | NULL, HFILL}}, |
1032 | | |
1033 | | { &hf_ieee80211_prism_did_sig_rate_field, |
1034 | | {"SIG Field", "prism.did.sigab", FT_NONE, BASE_NONE, 0, 0x0, |
1035 | | NULL, HFILL}}, |
1036 | | |
1037 | | { &hf_ieee80211_prism_did_istx, |
1038 | | {"IsTX", "prism.did.istx", FT_UINT32, BASE_HEX, VALS(prism_istx_vals), 0x0, |
1039 | | "Type of packet (RX or TX?)", HFILL }}, |
1040 | | |
1041 | | { &hf_ieee80211_prism_did_frmlen, |
1042 | | {"Frame Length", "prism.did.frmlen", FT_UINT32, BASE_DEC, NULL, 0x0, |
1043 | | "Length of the following frame in bytes", HFILL }}, |
1044 | | |
1045 | | { &hf_ieee80211_prism_did_unknown, |
1046 | | {"Unknown DID Field", "prism.did.unknown", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, |
1047 | | NULL, HFILL }} |
1048 | | }; |
1049 | | |
1050 | | static int *ett_array[] = { |
1051 | | &ett_prism, |
1052 | | &ett_prism_did, |
1053 | | &ett_sig_ab |
1054 | | }; |
1055 | | |
1056 | | void proto_register_ieee80211_prism(void) |
1057 | 14 | { |
1058 | 14 | proto_prism = proto_register_protocol("Prism capture header", "Prism", |
1059 | 14 | "prism"); |
1060 | 14 | proto_register_field_array(proto_prism, hf_prism, array_length(hf_prism)); |
1061 | 14 | proto_register_subtree_array(ett_array, array_length(ett_array)); |
1062 | | |
1063 | 14 | prism_handle = register_dissector("prism", dissect_prism, proto_prism); |
1064 | 14 | } |
1065 | | |
1066 | | void proto_reg_handoff_ieee80211_prism(void) |
1067 | 14 | { |
1068 | 14 | capture_dissector_handle_t ieee80211_prism_cap_handle; |
1069 | | |
1070 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE_802_11_PRISM, prism_handle); |
1071 | 14 | ieee80211_handle = find_dissector_add_dependency("wlan", proto_prism); |
1072 | 14 | ieee80211_radio_handle = find_dissector_add_dependency("wlan_radio", proto_prism); |
1073 | 14 | wlancap_handle = find_dissector_add_dependency("wlancap", proto_prism); |
1074 | | |
1075 | 14 | ieee80211_prism_cap_handle = create_capture_dissector_handle(capture_prism, proto_prism); |
1076 | 14 | capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE_802_11_PRISM, ieee80211_prism_cap_handle); |
1077 | | |
1078 | 14 | ieee80211_cap_handle = find_capture_dissector("ieee80211"); |
1079 | 14 | wlancap_cap_handle = find_capture_dissector("wlancap"); |
1080 | 14 | } |
1081 | | |
1082 | | /* |
1083 | | * Editor modelines |
1084 | | * |
1085 | | * Local Variables: |
1086 | | * c-basic-offset: 4 |
1087 | | * tab-width: 8 |
1088 | | * indent-tabs-mode: nil |
1089 | | * End: |
1090 | | * |
1091 | | * ex: set shiftwidth=4 tabstop=8 expandtab: |
1092 | | * :indentSize=4:tabSize=8:noTabs=true: |
1093 | | */ |