blob: e901752a3774b9d5cd1d19b0ce1720cbb8459a59 [file] [log] [blame]
guy15b5a0a2001-06-12 05:17:16 +00001/*
itojun7025d462001-06-15 07:39:43 +00002 * Copyright (c) 2001
guy15b5a0a2001-06-12 05:17:16 +00003 * Fortress Technologies, Inc. All rights reserved.
4 * Charlie Lenahan (clenahan@fortresstech.com)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that: (1) source code distributions
8 * retain the above copyright notice and this paragraph in its entirety, (2)
9 * distributions including binary code include the above copyright notice and
10 * this paragraph in its entirety in the documentation or other materials
11 * provided with the distribution, and (3) all advertising materials mentioning
12 * features or use of this software display the following acknowledgement:
13 * ``This product includes software developed by the University of California,
14 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15 * the University nor the names of its contributors may be used to endorse
16 * or promote products derived from this software without specific prior
17 * written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
Francois-Xavier Le Bail11d3a012016-08-14 15:42:19 +020023/* \summary: IEEE 802.11 printer */
24
guy15b5a0a2001-06-12 05:17:16 +000025#ifdef HAVE_CONFIG_H
Guy Harrisfb2479d2018-01-21 12:27:08 -080026#include <config.h>
guy15b5a0a2001-06-12 05:17:16 +000027#endif
28
Francois-Xavier Le Bail513f7822018-01-20 15:59:49 +010029#include "netdissect-stdinc.h"
guy15b5a0a2001-06-12 05:17:16 +000030
guy15b5a0a2001-06-12 05:17:16 +000031#include <string.h>
32
Francois-Xavier Le Bailc1c3c772015-09-05 23:35:58 +020033#include "netdissect.h"
guy15b5a0a2001-06-12 05:17:16 +000034#include "addrtoname.h"
guy15b5a0a2001-06-12 05:17:16 +000035
36#include "extract.h"
37
dyoung00511ce2004-09-23 21:57:24 +000038#include "cpack.h"
guy15b5a0a2001-06-12 05:17:16 +000039
Guy Harris27d428c2013-12-30 22:52:15 -080040
41/* Lengths of 802.11 header components. */
42#define IEEE802_11_FC_LEN 2
43#define IEEE802_11_DUR_LEN 2
44#define IEEE802_11_DA_LEN 6
45#define IEEE802_11_SA_LEN 6
46#define IEEE802_11_BSSID_LEN 6
47#define IEEE802_11_RA_LEN 6
48#define IEEE802_11_TA_LEN 6
Guy Harris7b636c72015-04-15 12:51:34 -070049#define IEEE802_11_ADDR1_LEN 6
Guy Harris27d428c2013-12-30 22:52:15 -080050#define IEEE802_11_SEQ_LEN 2
51#define IEEE802_11_CTL_LEN 2
Guy Harris7b636c72015-04-15 12:51:34 -070052#define IEEE802_11_CARRIED_FC_LEN 2
53#define IEEE802_11_HT_CONTROL_LEN 4
Guy Harris27d428c2013-12-30 22:52:15 -080054#define IEEE802_11_IV_LEN 3
55#define IEEE802_11_KID_LEN 1
56
57/* Frame check sequence length. */
58#define IEEE802_11_FCS_LEN 4
59
60/* Lengths of beacon components. */
61#define IEEE802_11_TSTAMP_LEN 8
62#define IEEE802_11_BCNINT_LEN 2
63#define IEEE802_11_CAPINFO_LEN 2
64#define IEEE802_11_LISTENINT_LEN 2
65
66#define IEEE802_11_AID_LEN 2
67#define IEEE802_11_STATUS_LEN 2
68#define IEEE802_11_REASON_LEN 2
69
70/* Length of previous AP in reassocation frame */
71#define IEEE802_11_AP_LEN 6
72
73#define T_MGMT 0x0 /* management */
74#define T_CTRL 0x1 /* control */
75#define T_DATA 0x2 /* data */
76#define T_RESV 0x3 /* reserved */
77
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +010078#define ST_ASSOC_REQUEST 0x0
79#define ST_ASSOC_RESPONSE 0x1
80#define ST_REASSOC_REQUEST 0x2
81#define ST_REASSOC_RESPONSE 0x3
82#define ST_PROBE_REQUEST 0x4
83#define ST_PROBE_RESPONSE 0x5
84/* RESERVED 0x6 */
85/* RESERVED 0x7 */
86#define ST_BEACON 0x8
Guy Harris27d428c2013-12-30 22:52:15 -080087#define ST_ATIM 0x9
88#define ST_DISASSOC 0xA
89#define ST_AUTH 0xB
90#define ST_DEAUTH 0xC
91#define ST_ACTION 0xD
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +010092/* RESERVED 0xE */
93/* RESERVED 0xF */
Guy Harris27d428c2013-12-30 22:52:15 -080094
Denis Ovsienko30408b12014-04-11 12:14:47 +040095static const struct tok st_str[] = {
96 { ST_ASSOC_REQUEST, "Assoc Request" },
97 { ST_ASSOC_RESPONSE, "Assoc Response" },
98 { ST_REASSOC_REQUEST, "ReAssoc Request" },
99 { ST_REASSOC_RESPONSE, "ReAssoc Response" },
100 { ST_PROBE_REQUEST, "Probe Request" },
101 { ST_PROBE_RESPONSE, "Probe Response" },
102 { ST_BEACON, "Beacon" },
103 { ST_ATIM, "ATIM" },
104 { ST_DISASSOC, "Disassociation" },
105 { ST_AUTH, "Authentication" },
106 { ST_DEAUTH, "DeAuthentication" },
107 { ST_ACTION, "Action" },
108 { 0, NULL }
109};
Guy Harris27d428c2013-12-30 22:52:15 -0800110
111#define CTRL_CONTROL_WRAPPER 0x7
112#define CTRL_BAR 0x8
113#define CTRL_BA 0x9
114#define CTRL_PS_POLL 0xA
115#define CTRL_RTS 0xB
116#define CTRL_CTS 0xC
117#define CTRL_ACK 0xD
118#define CTRL_CF_END 0xE
119#define CTRL_END_ACK 0xF
120
Denis Ovsienko30408b12014-04-11 12:14:47 +0400121static const struct tok ctrl_str[] = {
122 { CTRL_CONTROL_WRAPPER, "Control Wrapper" },
123 { CTRL_BAR, "BAR" },
124 { CTRL_BA, "BA" },
125 { CTRL_PS_POLL, "Power Save-Poll" },
126 { CTRL_RTS, "Request-To-Send" },
127 { CTRL_CTS, "Clear-To-Send" },
128 { CTRL_ACK, "Acknowledgment" },
129 { CTRL_CF_END, "CF-End" },
130 { CTRL_END_ACK, "CF-End+CF-Ack" },
131 { 0, NULL }
132};
133
Guy Harris27d428c2013-12-30 22:52:15 -0800134#define DATA_DATA 0x0
135#define DATA_DATA_CF_ACK 0x1
136#define DATA_DATA_CF_POLL 0x2
137#define DATA_DATA_CF_ACK_POLL 0x3
138#define DATA_NODATA 0x4
139#define DATA_NODATA_CF_ACK 0x5
140#define DATA_NODATA_CF_POLL 0x6
141#define DATA_NODATA_CF_ACK_POLL 0x7
142
143#define DATA_QOS_DATA 0x8
144#define DATA_QOS_DATA_CF_ACK 0x9
145#define DATA_QOS_DATA_CF_POLL 0xA
146#define DATA_QOS_DATA_CF_ACK_POLL 0xB
147#define DATA_QOS_NODATA 0xC
148#define DATA_QOS_CF_POLL_NODATA 0xE
149#define DATA_QOS_CF_ACK_POLL_NODATA 0xF
150
151/*
152 * The subtype field of a data frame is, in effect, composed of 4 flag
153 * bits - CF-Ack, CF-Poll, Null (means the frame doesn't actually have
154 * any data), and QoS.
155 */
156#define DATA_FRAME_IS_CF_ACK(x) ((x) & 0x01)
157#define DATA_FRAME_IS_CF_POLL(x) ((x) & 0x02)
158#define DATA_FRAME_IS_NULL(x) ((x) & 0x04)
159#define DATA_FRAME_IS_QOS(x) ((x) & 0x08)
160
161/*
162 * Bits in the frame control field.
163 */
164#define FC_VERSION(fc) ((fc) & 0x3)
165#define FC_TYPE(fc) (((fc) >> 2) & 0x3)
166#define FC_SUBTYPE(fc) (((fc) >> 4) & 0xF)
167#define FC_TO_DS(fc) ((fc) & 0x0100)
168#define FC_FROM_DS(fc) ((fc) & 0x0200)
169#define FC_MORE_FLAG(fc) ((fc) & 0x0400)
170#define FC_RETRY(fc) ((fc) & 0x0800)
171#define FC_POWER_MGMT(fc) ((fc) & 0x1000)
172#define FC_MORE_DATA(fc) ((fc) & 0x2000)
Guy Harris8275fd82015-04-15 20:11:41 -0700173#define FC_PROTECTED(fc) ((fc) & 0x4000)
Guy Harris27d428c2013-12-30 22:52:15 -0800174#define FC_ORDER(fc) ((fc) & 0x8000)
175
176struct mgmt_header_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800177 nd_uint16_t fc;
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100178 nd_uint16_t duration;
Guy Harris1eae0262017-12-31 11:12:12 -0800179 nd_mac_addr da;
180 nd_mac_addr sa;
181 nd_mac_addr bssid;
182 nd_uint16_t seq_ctrl;
Guy Harris27d428c2013-12-30 22:52:15 -0800183};
184
185#define MGMT_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
186 IEEE802_11_DA_LEN+IEEE802_11_SA_LEN+\
187 IEEE802_11_BSSID_LEN+IEEE802_11_SEQ_LEN)
188
189#define CAPABILITY_ESS(cap) ((cap) & 0x0001)
190#define CAPABILITY_IBSS(cap) ((cap) & 0x0002)
191#define CAPABILITY_CFP(cap) ((cap) & 0x0004)
192#define CAPABILITY_CFP_REQ(cap) ((cap) & 0x0008)
193#define CAPABILITY_PRIVACY(cap) ((cap) & 0x0010)
194
195struct ssid_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700196 uint8_t element_id;
197 uint8_t length;
Guy Harris27d428c2013-12-30 22:52:15 -0800198 u_char ssid[33]; /* 32 + 1 for null */
199};
200
201struct rates_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700202 uint8_t element_id;
203 uint8_t length;
204 uint8_t rate[16];
Guy Harris27d428c2013-12-30 22:52:15 -0800205};
206
207struct challenge_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700208 uint8_t element_id;
209 uint8_t length;
210 uint8_t text[254]; /* 1-253 + 1 for null */
Guy Harris27d428c2013-12-30 22:52:15 -0800211};
212
213struct fh_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700214 uint8_t element_id;
215 uint8_t length;
Guy Harrised85e202014-04-23 00:20:40 -0700216 uint16_t dwell_time;
Guy Harrisa2633f22014-04-23 11:53:22 -0700217 uint8_t hop_set;
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100218 uint8_t hop_pattern;
Guy Harrisa2633f22014-04-23 11:53:22 -0700219 uint8_t hop_index;
Guy Harris27d428c2013-12-30 22:52:15 -0800220};
221
222struct ds_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700223 uint8_t element_id;
224 uint8_t length;
225 uint8_t channel;
Guy Harris27d428c2013-12-30 22:52:15 -0800226};
227
228struct cf_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700229 uint8_t element_id;
230 uint8_t length;
231 uint8_t count;
232 uint8_t period;
Guy Harrised85e202014-04-23 00:20:40 -0700233 uint16_t max_duration;
Antonin Décimo0b3880c2019-01-23 17:28:14 +0100234 uint16_t dur_remaining;
Guy Harris27d428c2013-12-30 22:52:15 -0800235};
236
237struct tim_t {
Guy Harrisa2633f22014-04-23 11:53:22 -0700238 uint8_t element_id;
239 uint8_t length;
240 uint8_t count;
241 uint8_t period;
242 uint8_t bitmap_control;
243 uint8_t bitmap[251];
Guy Harris27d428c2013-12-30 22:52:15 -0800244};
245
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100246#define E_SSID 0
247#define E_RATES 1
Francois-Xavier Le Bail46efa1b2018-09-03 14:03:25 +0200248#define E_FH 2
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100249#define E_DS 3
Francois-Xavier Le Bail46efa1b2018-09-03 14:03:25 +0200250#define E_CF 4
251#define E_TIM 5
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100252#define E_IBSS 6
253/* reserved 7 */
254/* reserved 8 */
255/* reserved 9 */
256/* reserved 10 */
257/* reserved 11 */
258/* reserved 12 */
259/* reserved 13 */
260/* reserved 14 */
261/* reserved 15 */
262/* reserved 16 */
Guy Harris27d428c2013-12-30 22:52:15 -0800263
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100264#define E_CHALLENGE 16
265/* reserved 17 */
266/* reserved 18 */
267/* reserved 19 */
268/* reserved 16 */
269/* reserved 16 */
Guy Harris27d428c2013-12-30 22:52:15 -0800270
271
272struct mgmt_body_t {
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100273 uint8_t timestamp[IEEE802_11_TSTAMP_LEN];
274 uint16_t beacon_interval;
275 uint16_t listen_interval;
276 uint16_t status_code;
277 uint16_t aid;
Guy Harris27d428c2013-12-30 22:52:15 -0800278 u_char ap[IEEE802_11_AP_LEN];
Guy Harrised85e202014-04-23 00:20:40 -0700279 uint16_t reason_code;
280 uint16_t auth_alg;
281 uint16_t auth_trans_seq_num;
Guy Harris27d428c2013-12-30 22:52:15 -0800282 int challenge_present;
283 struct challenge_t challenge;
Guy Harrised85e202014-04-23 00:20:40 -0700284 uint16_t capability_info;
Guy Harris27d428c2013-12-30 22:52:15 -0800285 int ssid_present;
286 struct ssid_t ssid;
287 int rates_present;
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +0100288 struct rates_t rates;
Guy Harris27d428c2013-12-30 22:52:15 -0800289 int ds_present;
290 struct ds_t ds;
291 int cf_present;
292 struct cf_t cf;
293 int fh_present;
294 struct fh_t fh;
295 int tim_present;
296 struct tim_t tim;
297};
298
Guy Harris7b636c72015-04-15 12:51:34 -0700299struct ctrl_control_wrapper_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800300 nd_uint16_t fc;
301 nd_uint16_t duration;
302 nd_mac_addr addr1;
303 nd_uint16_t carried_fc[IEEE802_11_CARRIED_FC_LEN];
304 nd_uint16_t ht_control[IEEE802_11_HT_CONTROL_LEN];
Guy Harris7b636c72015-04-15 12:51:34 -0700305};
306
307#define CTRL_CONTROL_WRAPPER_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
308 IEEE802_11_ADDR1_LEN+\
309 IEEE802_11_CARRIED_FC_LEN+\
310 IEEE802_11_HT_CONTROL_LEN)
311
312struct ctrl_rts_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800313 nd_uint16_t fc;
314 nd_uint16_t duration;
315 nd_mac_addr ra;
316 nd_mac_addr ta;
Guy Harris27d428c2013-12-30 22:52:15 -0800317};
318
319#define CTRL_RTS_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
320 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN)
321
Guy Harris7b636c72015-04-15 12:51:34 -0700322struct ctrl_cts_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800323 nd_uint16_t fc;
324 nd_uint16_t duration;
325 nd_mac_addr ra;
Guy Harris27d428c2013-12-30 22:52:15 -0800326};
327
328#define CTRL_CTS_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
329
Guy Harris7b636c72015-04-15 12:51:34 -0700330struct ctrl_ack_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800331 nd_uint16_t fc;
332 nd_uint16_t duration;
333 nd_mac_addr ra;
Guy Harris27d428c2013-12-30 22:52:15 -0800334};
335
336#define CTRL_ACK_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
337
Guy Harris7b636c72015-04-15 12:51:34 -0700338struct ctrl_ps_poll_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800339 nd_uint16_t fc;
340 nd_uint16_t aid;
341 nd_mac_addr bssid;
342 nd_mac_addr ta;
Guy Harris27d428c2013-12-30 22:52:15 -0800343};
344
345#define CTRL_PS_POLL_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_AID_LEN+\
346 IEEE802_11_BSSID_LEN+IEEE802_11_TA_LEN)
347
Guy Harris7b636c72015-04-15 12:51:34 -0700348struct ctrl_end_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800349 nd_uint16_t fc;
350 nd_uint16_t duration;
351 nd_mac_addr ra;
352 nd_mac_addr bssid;
Guy Harris27d428c2013-12-30 22:52:15 -0800353};
354
355#define CTRL_END_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
356 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
357
Guy Harris7b636c72015-04-15 12:51:34 -0700358struct ctrl_end_ack_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800359 nd_uint16_t fc;
360 nd_uint16_t duration;
361 nd_mac_addr ra;
362 nd_mac_addr bssid;
Guy Harris27d428c2013-12-30 22:52:15 -0800363};
364
365#define CTRL_END_ACK_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
366 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
367
Guy Harris7b636c72015-04-15 12:51:34 -0700368struct ctrl_ba_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800369 nd_uint16_t fc;
370 nd_uint16_t duration;
371 nd_mac_addr ra;
Guy Harris27d428c2013-12-30 22:52:15 -0800372};
373
374#define CTRL_BA_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
375
Guy Harris7b636c72015-04-15 12:51:34 -0700376struct ctrl_bar_hdr_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800377 nd_uint16_t fc;
378 nd_uint16_t dur;
379 nd_mac_addr ra;
380 nd_mac_addr ta;
381 nd_uint16_t ctl;
382 nd_uint16_t seq;
Guy Harris27d428c2013-12-30 22:52:15 -0800383};
384
385#define CTRL_BAR_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
386 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN+\
387 IEEE802_11_CTL_LEN+IEEE802_11_SEQ_LEN)
388
389struct meshcntl_t {
Guy Harris1eae0262017-12-31 11:12:12 -0800390 nd_uint8_t flags;
391 nd_uint8_t ttl;
392 nd_uint32_t seq;
393 nd_mac_addr addr4;
394 nd_mac_addr addr5;
395 nd_mac_addr addr6;
Guy Harris27d428c2013-12-30 22:52:15 -0800396};
397
398#define IV_IV(iv) ((iv) & 0xFFFFFF)
399#define IV_PAD(iv) (((iv) >> 24) & 0x3F)
400#define IV_KEYID(iv) (((iv) >> 30) & 0x03)
401
guy86f96f82005-11-13 12:07:25 +0000402#define PRINT_SSID(p) \
Guy Harris7923f062009-11-04 14:55:05 -0800403 if (p.ssid_present) { \
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +0100404 ND_PRINT(" ("); \
Francois-Xavier Le Bail419cc702018-05-18 22:27:34 +0200405 fn_print_str(ndo, p.ssid.ssid); \
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +0100406 ND_PRINT(")"); \
guy86f96f82005-11-13 12:07:25 +0000407 }
408
dyoung00511ce2004-09-23 21:57:24 +0000409#define PRINT_RATE(_sep, _r, _suf) \
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +0100410 ND_PRINT("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
guy6c6b1ac2002-05-13 08:30:19 +0000411#define PRINT_RATES(p) \
Guy Harris7923f062009-11-04 14:55:05 -0800412 if (p.rates_present) { \
413 int z; \
414 const char *sep = " ["; \
415 for (z = 0; z < p.rates.length ; z++) { \
416 PRINT_RATE(sep, p.rates.rate[z], \
417 (p.rates.rate[z] & 0x80 ? "*" : "")); \
418 sep = " "; \
419 } \
420 if (p.rates.length != 0) \
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +0100421 ND_PRINT(" Mbit]"); \
guy86f96f82005-11-13 12:07:25 +0000422 }
423
424#define PRINT_DS_CHANNEL(p) \
Guy Harris7923f062009-11-04 14:55:05 -0800425 if (p.ds_present) \
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +0100426 ND_PRINT(" CH: %u", p.ds.channel); \
427 ND_PRINT("%s", \
428 CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "");
guy15b5a0a2001-06-12 05:17:16 +0000429
Guy Harris54db1222011-04-27 12:08:27 -0700430#define MAX_MCS_INDEX 76
431
432/*
433 * Indices are:
434 *
435 * the MCS index (0-76);
436 *
437 * 0 for 20 MHz, 1 for 40 MHz;
438 *
439 * 0 for a long guard interval, 1 for a short guard interval.
440 */
441static const float ieee80211_float_htrates[MAX_MCS_INDEX+1][2][2] = {
442 /* MCS 0 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800443 { /* 20 Mhz */ { 6.5f, /* SGI */ 7.2f, },
444 /* 40 Mhz */ { 13.5f, /* SGI */ 15.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700445 },
446
447 /* MCS 1 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800448 { /* 20 Mhz */ { 13.0f, /* SGI */ 14.4f, },
449 /* 40 Mhz */ { 27.0f, /* SGI */ 30.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700450 },
451
452 /* MCS 2 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800453 { /* 20 Mhz */ { 19.5f, /* SGI */ 21.7f, },
454 /* 40 Mhz */ { 40.5f, /* SGI */ 45.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700455 },
456
457 /* MCS 3 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800458 { /* 20 Mhz */ { 26.0f, /* SGI */ 28.9f, },
459 /* 40 Mhz */ { 54.0f, /* SGI */ 60.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700460 },
461
462 /* MCS 4 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800463 { /* 20 Mhz */ { 39.0f, /* SGI */ 43.3f, },
464 /* 40 Mhz */ { 81.0f, /* SGI */ 90.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700465 },
466
467 /* MCS 5 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800468 { /* 20 Mhz */ { 52.0f, /* SGI */ 57.8f, },
469 /* 40 Mhz */ { 108.0f, /* SGI */ 120.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700470 },
471
472 /* MCS 6 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800473 { /* 20 Mhz */ { 58.5f, /* SGI */ 65.0f, },
474 /* 40 Mhz */ { 121.5f, /* SGI */ 135.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700475 },
476
477 /* MCS 7 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800478 { /* 20 Mhz */ { 65.0f, /* SGI */ 72.2f, },
479 /* 40 Mhz */ { 135.0f, /* SGI */ 150.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700480 },
481
482 /* MCS 8 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800483 { /* 20 Mhz */ { 13.0f, /* SGI */ 14.4f, },
484 /* 40 Mhz */ { 27.0f, /* SGI */ 30.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700485 },
486
487 /* MCS 9 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800488 { /* 20 Mhz */ { 26.0f, /* SGI */ 28.9f, },
489 /* 40 Mhz */ { 54.0f, /* SGI */ 60.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700490 },
491
492 /* MCS 10 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800493 { /* 20 Mhz */ { 39.0f, /* SGI */ 43.3f, },
494 /* 40 Mhz */ { 81.0f, /* SGI */ 90.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700495 },
496
497 /* MCS 11 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800498 { /* 20 Mhz */ { 52.0f, /* SGI */ 57.8f, },
499 /* 40 Mhz */ { 108.0f, /* SGI */ 120.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700500 },
501
502 /* MCS 12 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800503 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
504 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700505 },
506
507 /* MCS 13 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800508 { /* 20 Mhz */ { 104.0f, /* SGI */ 115.6f, },
509 /* 40 Mhz */ { 216.0f, /* SGI */ 240.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700510 },
511
512 /* MCS 14 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800513 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
514 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700515 },
516
517 /* MCS 15 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800518 { /* 20 Mhz */ { 130.0f, /* SGI */ 144.4f, },
519 /* 40 Mhz */ { 270.0f, /* SGI */ 300.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700520 },
521
522 /* MCS 16 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800523 { /* 20 Mhz */ { 19.5f, /* SGI */ 21.7f, },
524 /* 40 Mhz */ { 40.5f, /* SGI */ 45.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700525 },
526
527 /* MCS 17 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800528 { /* 20 Mhz */ { 39.0f, /* SGI */ 43.3f, },
529 /* 40 Mhz */ { 81.0f, /* SGI */ 90.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700530 },
531
532 /* MCS 18 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800533 { /* 20 Mhz */ { 58.5f, /* SGI */ 65.0f, },
534 /* 40 Mhz */ { 121.5f, /* SGI */ 135.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700535 },
536
537 /* MCS 19 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800538 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
539 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700540 },
541
542 /* MCS 20 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800543 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
544 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700545 },
546
547 /* MCS 21 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800548 { /* 20 Mhz */ { 156.0f, /* SGI */ 173.3f, },
549 /* 40 Mhz */ { 324.0f, /* SGI */ 360.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700550 },
551
552 /* MCS 22 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800553 { /* 20 Mhz */ { 175.5f, /* SGI */ 195.0f, },
554 /* 40 Mhz */ { 364.5f, /* SGI */ 405.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700555 },
556
557 /* MCS 23 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800558 { /* 20 Mhz */ { 195.0f, /* SGI */ 216.7f, },
559 /* 40 Mhz */ { 405.0f, /* SGI */ 450.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700560 },
561
562 /* MCS 24 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800563 { /* 20 Mhz */ { 26.0f, /* SGI */ 28.9f, },
564 /* 40 Mhz */ { 54.0f, /* SGI */ 60.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700565 },
566
567 /* MCS 25 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800568 { /* 20 Mhz */ { 52.0f, /* SGI */ 57.8f, },
569 /* 40 Mhz */ { 108.0f, /* SGI */ 120.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700570 },
571
572 /* MCS 26 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800573 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
574 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700575 },
576
577 /* MCS 27 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800578 { /* 20 Mhz */ { 104.0f, /* SGI */ 115.6f, },
579 /* 40 Mhz */ { 216.0f, /* SGI */ 240.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700580 },
581
582 /* MCS 28 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800583 { /* 20 Mhz */ { 156.0f, /* SGI */ 173.3f, },
584 /* 40 Mhz */ { 324.0f, /* SGI */ 360.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700585 },
586
587 /* MCS 29 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800588 { /* 20 Mhz */ { 208.0f, /* SGI */ 231.1f, },
589 /* 40 Mhz */ { 432.0f, /* SGI */ 480.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700590 },
591
592 /* MCS 30 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800593 { /* 20 Mhz */ { 234.0f, /* SGI */ 260.0f, },
594 /* 40 Mhz */ { 486.0f, /* SGI */ 540.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700595 },
596
597 /* MCS 31 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800598 { /* 20 Mhz */ { 260.0f, /* SGI */ 288.9f, },
599 /* 40 Mhz */ { 540.0f, /* SGI */ 600.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700600 },
601
602 /* MCS 32 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800603 { /* 20 Mhz */ { 0.0f, /* SGI */ 0.0f, }, /* not valid */
604 /* 40 Mhz */ { 6.0f, /* SGI */ 6.7f, },
Guy Harris54db1222011-04-27 12:08:27 -0700605 },
606
607 /* MCS 33 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800608 { /* 20 Mhz */ { 39.0f, /* SGI */ 43.3f, },
609 /* 40 Mhz */ { 81.0f, /* SGI */ 90.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700610 },
611
612 /* MCS 34 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800613 { /* 20 Mhz */ { 52.0f, /* SGI */ 57.8f, },
614 /* 40 Mhz */ { 108.0f, /* SGI */ 120.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700615 },
616
617 /* MCS 35 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800618 { /* 20 Mhz */ { 65.0f, /* SGI */ 72.2f, },
619 /* 40 Mhz */ { 135.0f, /* SGI */ 150.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700620 },
621
622 /* MCS 36 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800623 { /* 20 Mhz */ { 58.5f, /* SGI */ 65.0f, },
624 /* 40 Mhz */ { 121.5f, /* SGI */ 135.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700625 },
626
627 /* MCS 37 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800628 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
629 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700630 },
631
632 /* MCS 38 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800633 { /* 20 Mhz */ { 97.5f, /* SGI */ 108.3f, },
634 /* 40 Mhz */ { 202.5f, /* SGI */ 225.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700635 },
636
637 /* MCS 39 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800638 { /* 20 Mhz */ { 52.0f, /* SGI */ 57.8f, },
639 /* 40 Mhz */ { 108.0f, /* SGI */ 120.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700640 },
641
642 /* MCS 40 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800643 { /* 20 Mhz */ { 65.0f, /* SGI */ 72.2f, },
644 /* 40 Mhz */ { 135.0f, /* SGI */ 150.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700645 },
646
647 /* MCS 41 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800648 { /* 20 Mhz */ { 65.0f, /* SGI */ 72.2f, },
649 /* 40 Mhz */ { 135.0f, /* SGI */ 150.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700650 },
651
652 /* MCS 42 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800653 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
654 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700655 },
656
657 /* MCS 43 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800658 { /* 20 Mhz */ { 91.0f, /* SGI */ 101.1f, },
659 /* 40 Mhz */ { 189.0f, /* SGI */ 210.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700660 },
661
662 /* MCS 44 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800663 { /* 20 Mhz */ { 91.0f, /* SGI */ 101.1f, },
664 /* 40 Mhz */ { 189.0f, /* SGI */ 210.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700665 },
666
667 /* MCS 45 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800668 { /* 20 Mhz */ { 104.0f, /* SGI */ 115.6f, },
669 /* 40 Mhz */ { 216.0f, /* SGI */ 240.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700670 },
671
672 /* MCS 46 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800673 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
674 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700675 },
676
677 /* MCS 47 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800678 { /* 20 Mhz */ { 97.5f, /* SGI */ 108.3f, },
679 /* 40 Mhz */ { 202.5f, /* SGI */ 225.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700680 },
681
682 /* MCS 48 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800683 { /* 20 Mhz */ { 97.5f, /* SGI */ 108.3f, },
684 /* 40 Mhz */ { 202.5f, /* SGI */ 225.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700685 },
686
687 /* MCS 49 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800688 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
689 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700690 },
691
692 /* MCS 50 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800693 { /* 20 Mhz */ { 136.5f, /* SGI */ 151.7f, },
694 /* 40 Mhz */ { 283.5f, /* SGI */ 315.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700695 },
696
697 /* MCS 51 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800698 { /* 20 Mhz */ { 136.5f, /* SGI */ 151.7f, },
699 /* 40 Mhz */ { 283.5f, /* SGI */ 315.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700700 },
701
702 /* MCS 52 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800703 { /* 20 Mhz */ { 156.0f, /* SGI */ 173.3f, },
704 /* 40 Mhz */ { 324.0f, /* SGI */ 360.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700705 },
706
707 /* MCS 53 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800708 { /* 20 Mhz */ { 65.0f, /* SGI */ 72.2f, },
709 /* 40 Mhz */ { 135.0f, /* SGI */ 150.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700710 },
711
712 /* MCS 54 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800713 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
714 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700715 },
716
717 /* MCS 55 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800718 { /* 20 Mhz */ { 91.0f, /* SGI */ 101.1f, },
719 /* 40 Mhz */ { 189.0f, /* SGI */ 210.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700720 },
721
722 /* MCS 56 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800723 { /* 20 Mhz */ { 78.0f, /* SGI */ 86.7f, },
724 /* 40 Mhz */ { 162.0f, /* SGI */ 180.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700725 },
726
727 /* MCS 57 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800728 { /* 20 Mhz */ { 91.0f, /* SGI */ 101.1f, },
729 /* 40 Mhz */ { 189.0f, /* SGI */ 210.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700730 },
731
732 /* MCS 58 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800733 { /* 20 Mhz */ { 104.0f, /* SGI */ 115.6f, },
734 /* 40 Mhz */ { 216.0f, /* SGI */ 240.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700735 },
736
737 /* MCS 59 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800738 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
739 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700740 },
741
742 /* MCS 60 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800743 { /* 20 Mhz */ { 104.0f, /* SGI */ 115.6f, },
744 /* 40 Mhz */ { 216.0f, /* SGI */ 240.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700745 },
746
747 /* MCS 61 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800748 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
749 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700750 },
751
752 /* MCS 62 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800753 { /* 20 Mhz */ { 130.0f, /* SGI */ 144.4f, },
754 /* 40 Mhz */ { 270.0f, /* SGI */ 300.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700755 },
756
757 /* MCS 63 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800758 { /* 20 Mhz */ { 130.0f, /* SGI */ 144.4f, },
759 /* 40 Mhz */ { 270.0f, /* SGI */ 300.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700760 },
761
762 /* MCS 64 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800763 { /* 20 Mhz */ { 143.0f, /* SGI */ 158.9f, },
764 /* 40 Mhz */ { 297.0f, /* SGI */ 330.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700765 },
766
767 /* MCS 65 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800768 { /* 20 Mhz */ { 97.5f, /* SGI */ 108.3f, },
769 /* 40 Mhz */ { 202.5f, /* SGI */ 225.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700770 },
771
772 /* MCS 66 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800773 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
774 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700775 },
776
777 /* MCS 67 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800778 { /* 20 Mhz */ { 136.5f, /* SGI */ 151.7f, },
779 /* 40 Mhz */ { 283.5f, /* SGI */ 315.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700780 },
781
782 /* MCS 68 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800783 { /* 20 Mhz */ { 117.0f, /* SGI */ 130.0f, },
784 /* 40 Mhz */ { 243.0f, /* SGI */ 270.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700785 },
786
787 /* MCS 69 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800788 { /* 20 Mhz */ { 136.5f, /* SGI */ 151.7f, },
789 /* 40 Mhz */ { 283.5f, /* SGI */ 315.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700790 },
791
792 /* MCS 70 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800793 { /* 20 Mhz */ { 156.0f, /* SGI */ 173.3f, },
794 /* 40 Mhz */ { 324.0f, /* SGI */ 360.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700795 },
796
797 /* MCS 71 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800798 { /* 20 Mhz */ { 175.5f, /* SGI */ 195.0f, },
799 /* 40 Mhz */ { 364.5f, /* SGI */ 405.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700800 },
801
802 /* MCS 72 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800803 { /* 20 Mhz */ { 156.0f, /* SGI */ 173.3f, },
804 /* 40 Mhz */ { 324.0f, /* SGI */ 360.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700805 },
806
807 /* MCS 73 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800808 { /* 20 Mhz */ { 175.5f, /* SGI */ 195.0f, },
809 /* 40 Mhz */ { 364.5f, /* SGI */ 405.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700810 },
811
812 /* MCS 74 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800813 { /* 20 Mhz */ { 195.0f, /* SGI */ 216.7f, },
814 /* 40 Mhz */ { 405.0f, /* SGI */ 450.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700815 },
816
817 /* MCS 75 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800818 { /* 20 Mhz */ { 195.0f, /* SGI */ 216.7f, },
819 /* 40 Mhz */ { 405.0f, /* SGI */ 450.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700820 },
821
822 /* MCS 76 */
Guy Harris7b909ab2018-01-29 02:25:56 -0800823 { /* 20 Mhz */ { 214.5f, /* SGI */ 238.3f, },
824 /* 40 Mhz */ { 445.5f, /* SGI */ 495.0f, },
Guy Harris54db1222011-04-27 12:08:27 -0700825 },
Guy Harrisaae14f92009-07-14 18:23:06 -0700826};
Guy Harrisaae14f92009-07-14 18:23:06 -0700827
guy15b5a0a2001-06-12 05:17:16 +0000828static const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
Francois-Xavier Le Bail46f52032018-02-06 19:15:45 +0100829#define NUM_AUTH_ALGS (sizeof(auth_alg_text) / sizeof(auth_alg_text[0]))
guyd9441bb2005-07-30 00:05:32 +0000830
itojun7025d462001-06-15 07:39:43 +0000831static const char *status_text[] = {
Romain Francoise5eb37a52012-05-28 14:33:07 -0400832 "Successful", /* 0 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700833 "Unspecified failure", /* 1 */
Mister Xd20791d2019-06-08 02:20:27 +0000834 "TDLS wakeup schedule rejected but alternative schedule "
835 "provided", /* 2 */
836 "TDLS wakeup schedule rejected",/* 3 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700837 "Reserved", /* 4 */
Mister Xd20791d2019-06-08 02:20:27 +0000838 "Security disabled", /* 5 */
839 "Unacceptable lifetime", /* 6 */
840 "Not in same BSS", /* 7 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700841 "Reserved", /* 8 */
842 "Reserved", /* 9 */
843 "Cannot Support all requested capabilities in the Capability "
Francois-Xavier Le Bail46efa1b2018-09-03 14:03:25 +0200844 "Information field", /* 10 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700845 "Reassociation denied due to inability to confirm that association "
846 "exists", /* 11 */
Mister Xd20791d2019-06-08 02:20:27 +0000847 "Association denied due to reason outside the scope of this "
Guy Harrisaae14f92009-07-14 18:23:06 -0700848 "standard", /* 12 */
Mister Xd20791d2019-06-08 02:20:27 +0000849 "Responding STA does not support the specified authentication "
850 "algorithm", /* 13 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700851 "Received an Authentication frame with authentication transaction "
852 "sequence number out of expected sequence", /* 14 */
853 "Authentication rejected because of challenge failure", /* 15 */
854 "Authentication rejected due to timeout waiting for next frame in "
Francois-Xavier Le Bail46efa1b2018-09-03 14:03:25 +0200855 "sequence", /* 16 */
Mister Xd20791d2019-06-08 02:20:27 +0000856 "Association denied because AP is unable to handle "
857 "additional associated STAs", /* 17 */
858 "Association denied due to requesting STA not supporting "
859 "all of the data rates in the BSSBasicRateSet parameter, "
860 "the Basic HT-MCS Set field of the HT Operation "
861 "parameter, or the Basic VHT-MCS and NSS Set field in "
862 "the VHT Operation parameter", /* 18 */
863 "Association denied due to requesting STA not supporting "
864 "the short preamble option", /* 19 */
865 "Reserved", /* 20 */
866 "Reserved", /* 21 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700867 "Association request rejected because Spectrum Management "
868 "capability is required", /* 22 */
869 "Association request rejected because the information in the "
870 "Power Capability element is unacceptable", /* 23 */
871 "Association request rejected because the information in the "
872 "Supported Channels element is unacceptable", /* 24 */
Mister Xd20791d2019-06-08 02:20:27 +0000873 "Association denied due to requesting STA not supporting "
874 "the Short Slot Time option", /* 25 */
875 "Reserved", /* 26 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700876 "Association denied because the requested STA does not support HT "
877 "features", /* 27 */
Mister Xd20791d2019-06-08 02:20:27 +0000878 "R0KH unreachable", /* 28 */
879 "Association denied because the requesting STA does not "
880 "support the phased coexistence operation (PCO) "
881 "transition time required by the AP", /* 29 */
882 "Association request rejected temporarily; try again "
883 "later", /* 30 */
884 "Robust management frame policy violation", /* 31 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700885 "Unspecified, QoS-related failure", /* 32 */
Mister Xd20791d2019-06-08 02:20:27 +0000886 "Association denied because QoS AP or PCP has "
887 "insufficient bandwidth to handle another QoS "
888 "STA", /* 33 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700889 "Association denied due to excessive frame loss rates and/or "
890 "poor conditions on current operating channel", /* 34 */
Mister Xd20791d2019-06-08 02:20:27 +0000891 "Association (with QoS BSS) denied because the requesting STA "
892 "does not support the QoS facility", /* 35 */
893 "Reserved", /* 36 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700894 "The request has been declined", /* 37 */
895 "The request has not been successful as one or more parameters "
896 "have invalid values", /* 38 */
Mister Xd20791d2019-06-08 02:20:27 +0000897 "The allocation or TS has not been created because the request "
898 "cannot be honored; however, a suggested TSPEC/DMG TSPEC is "
899 "provided so that the initiating STA can attempt to set "
900 "another allocation or TS with the suggested changes to the "
901 "TSPEC/DMG TSPEC", /* 39 */
902 "Invalid element, i.e., an element defined in this standard "
903 "for which the content does not meet the specifications in "
904 "Clause 9", /* 40 */
905 "Invalid group cipher", /* 41 */
906 "Invalid pairwise cipher", /* 42 */
907 "Invalid AKMP", /* 43 */
908 "Unsupported RSNE version", /* 44 */
909 "Invalid RSNE capabilities", /* 45 */
910 "Cipher suite rejected because of security policy", /* 46 */
911 "The TS or allocation has not been created; however, the "
912 "HC or PCP might be capable of creating a TS or "
913 "allocation, in response to a request, after the time "
914 "indicated in the TS Delay element", /* 47 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700915 "Direct Link is not allowed in the BSS by policy", /* 48 */
Mister Xd20791d2019-06-08 02:20:27 +0000916 "The Destination STA is not present within this BSS", /* 49 */
917 "The Destination STA is not a QoS STA", /* 50 */
Guy Harrisaae14f92009-07-14 18:23:06 -0700918
Mister Xd20791d2019-06-08 02:20:27 +0000919 "Association denied because the listen interval is "
920 "too large", /* 51 */
921 "Invalid FT Action frame count", /* 52 */
922 "Invalid pairwise master key identifier (PMKID)", /* 53 */
923 "Invalid MDE", /* 54 */
924 "Invalid FTE", /* 55 */
925 "Requested TCLAS processing is not supported by the AP "
926 "or PCP", /* 56 */
927 "The AP or PCP has insufficient TCLAS processing "
928 "resources to satisfy the request", /* 57 */
929 "The TS has not been created because the request "
930 "cannot be honored; however, the HC or PCP suggests "
931 "that the STA transition to a different BSS to set up "
932 "the TS", /* 58 */
933 "GAS Advertisement Protocol not supported", /* 59 */
934 "No outstanding GAS request", /* 60 */
935 "GAS Response not received from the Advertisement "
936 "Server", /* 61 */
937 "STA timed out waiting for GAS Query Response", /* 62 */
938 "LARGE GAS Response is larger than query response "
939 "length limit", /* 63 */
940 "Request refused because home network does not support "
941 "request", /* 64 */
942 "Advertisement Server in the network is not currently "
943 "reachable", /* 65 */
944 "Reserved", /* 66 */
945 "Request refused due to permissions received via SSPN "
946 "interface", /* 67 */
947 "Request refused because the AP or PCP does not "
948 "support unauthenticated access", /* 68 */
949 "Reserved", /* 69 */
950 "Reserved", /* 70 */
951 "Reserved", /* 71 */
952 "Invalid contents of RSNE", /* 72 */
953 "U-APSD coexistence is not supported", /* 73 */
954 "Requested U-APSD coexistence mode is not supported", /* 74 */
955 "Requested Interval/Duration value cannot be "
956 "supported with U-APSD coexistence", /* 75 */
957 "Authentication is rejected because an Anti-Clogging "
958 "Token is required", /* 76 */
959 "Authentication is rejected because the offered "
960 "finite cyclic group is not supported", /* 77 */
961 "The TBTT adjustment request has not been successful "
962 "because the STA could not find an alternative TBTT", /* 78 */
963 "Transmission failure", /* 79 */
964 "Requested TCLAS Not Supported", /* 80 */
965 "TCLAS Resources Exhausted", /* 81 */
966 "Rejected with Suggested BSS transition", /* 82 */
967 "Reject with recommended schedule", /* 83 */
968 "Reject because no wakeup schedule specified", /* 84 */
969 "Success, the destination STA is in power save mode", /* 85 */
970 "FST pending, in process of admitting FST session", /* 86 */
971 "Performing FST now", /* 87 */
972 "FST pending, gap(s) in block ack window", /* 88 */
973 "Reject because of U-PID setting", /* 89 */
974 "Reserved", /* 90 */
975 "Reserved", /* 91 */
976 "(Re)Association refused for some external reason", /* 92 */
977 "(Re)Association refused because of memory limits "
978 "at the AP", /* 93 */
979 "(Re)Association refused because emergency services "
980 "are not supported at the AP", /* 94 */
981 "GAS query response not yet received", /* 95 */
982 "Reject since the request is for transition to a "
983 "frequency band subject to DSE procedures and "
984 "FST Initiator is a dependent STA", /* 96 */
985 "Requested TCLAS processing has been terminated by "
986 "the AP", /* 97 */
987 "The TS schedule conflicts with an existing "
988 "schedule; an alternative schedule is provided", /* 98 */
989 "The association has been denied; however, one or "
990 "more Multi-band elements are included that can "
991 "be used by the receiving STA to join the BSS", /* 99 */
992 "The request failed due to a reservation conflict", /* 100 */
993 "The request failed due to exceeded MAF limit", /* 101 */
994 "The request failed due to exceeded MCCA track "
995 "limit", /* 102 */
996 "Association denied because the information in the"
997 "Spectrum Management field is unacceptable", /* 103 */
998 "Association denied because the requesting STA "
999 "does not support VHT features", /* 104 */
1000 "Enablement denied", /* 105 */
1001 "Enablement denied due to restriction from an "
1002 "authorized GDB", /* 106 */
1003 "Authorization deenabled", /* 107 */
itojun7025d462001-06-15 07:39:43 +00001004};
Francois-Xavier Le Bail46f52032018-02-06 19:15:45 +01001005#define NUM_STATUSES (sizeof(status_text) / sizeof(status_text[0]))
guy15b5a0a2001-06-12 05:17:16 +00001006
itojun7025d462001-06-15 07:39:43 +00001007static const char *reason_text[] = {
Guy Harrisaae14f92009-07-14 18:23:06 -07001008 "Reserved", /* 0 */
1009 "Unspecified reason", /* 1 */
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001010 "Previous authentication no longer valid", /* 2 */
Mister Xee5abf52019-06-20 21:59:34 +00001011 "Deauthenticated because sending STA is leaving (or has left) "
Guy Harrisaae14f92009-07-14 18:23:06 -07001012 "IBSS or ESS", /* 3 */
1013 "Disassociated due to inactivity", /* 4 */
1014 "Disassociated because AP is unable to handle all currently "
Mister Xddbf2c42019-06-08 02:19:27 +00001015 " associated STAs", /* 5 */
1016 "Class 2 frame received from nonauthenticated STA", /* 6 */
1017 "Class 3 frame received from nonassociated STA", /* 7 */
1018 "Disassociated because sending STA is leaving "
Guy Harrisaae14f92009-07-14 18:23:06 -07001019 "(or has left) BSS", /* 8 */
Mister Xddbf2c42019-06-08 02:19:27 +00001020 "STA requesting (re)association is not authenticated with "
1021 "responding STA", /* 9 */
Guy Harrisaae14f92009-07-14 18:23:06 -07001022 "Disassociated because the information in the Power Capability "
1023 "element is unacceptable", /* 10 */
Mister Xddbf2c42019-06-08 02:19:27 +00001024 "Disassociated because the information in the Supported Channels "
Guy Harrisaae14f92009-07-14 18:23:06 -07001025 "element is unacceptable", /* 11 */
Mister Xddbf2c42019-06-08 02:19:27 +00001026 "Disassociated due to BSS transition management", /* 12 */
1027 "Invalid element, i.e., an element defined in this standard for "
1028 "which the content does not meet the specifications "
1029 "in Clause 9", /* 13 */
1030 "Message integrity code (MIC) failure", /* 14 */
Guy Harrisaae14f92009-07-14 18:23:06 -07001031 "4-Way Handshake timeout", /* 15 */
Mister Xddbf2c42019-06-08 02:19:27 +00001032 "Group key handshake timeout", /* 16 */
Guy Harrisaae14f92009-07-14 18:23:06 -07001033 "Information element in 4-Way Handshake different from (Re)Association"
Mister Xddbf2c42019-06-08 02:19:27 +00001034 "Request/Probe Response/Beacon frame", /* 17 */
1035 "Invalid group cipher", /* 18 */
1036 "Invalid pairwise cipher", /* 19 */
1037 "Invalid AKMP", /* 20 */
1038 "Unsupported RSNE version", /* 21 */
1039 "Invalid RSNE capabilities", /* 22 */
1040 "IEEE 802.1X authentication failed", /* 23 */
1041 "Cipher suite rejected because of the security policy", /* 24 */
1042 "TDLS direct-link teardown due to TDLS peer STA "
1043 "unreachable via the TDLS direct link", /* 25 */
1044 "TDLS direct-link teardown for unspecified reason", /* 26 */
1045 "Disassociated because session terminated by SSP request",/* 27 */
1046 "Disassociated because of lack of SSP roaming agreement",/* 28 */
1047 "Requested service rejected because of SSP cipher suite or "
1048 "AKM requirement", /* 29 */
1049 "Requested service not authorized in this location", /* 30 */
Guy Harrisaae14f92009-07-14 18:23:06 -07001050 "TS deleted because QoS AP lacks sufficient bandwidth for this "
1051 "QoS STA due to a change in BSS service characteristics or "
1052 "operational mode (e.g. an HT BSS change from 40 MHz channel "
1053 "to 20 MHz channel)", /* 31 */
1054 "Disassociated for unspecified, QoS-related reason", /* 32 */
1055 "Disassociated because QoS AP lacks sufficient bandwidth for this "
1056 "QoS STA", /* 33 */
1057 "Disassociated because of excessive number of frames that need to be "
Mister Xddbf2c42019-06-08 02:19:27 +00001058 "acknowledged, but are not acknowledged due to AP transmissions "
Guy Harrisaae14f92009-07-14 18:23:06 -07001059 "and/or poor channel conditions", /* 34 */
1060 "Disassociated because STA is transmitting outside the limits "
1061 "of its TXOPs", /* 35 */
1062 "Requested from peer STA as the STA is leaving the BSS "
1063 "(or resetting)", /* 36 */
1064 "Requested from peer STA as it does not want to use the "
1065 "mechanism", /* 37 */
1066 "Requested from peer STA as the STA received frames using the "
1067 "mechanism for which a set up is required", /* 38 */
1068 "Requested from peer STA due to time out", /* 39 */
1069 "Reserved", /* 40 */
1070 "Reserved", /* 41 */
1071 "Reserved", /* 42 */
1072 "Reserved", /* 43 */
1073 "Reserved", /* 44 */
1074 "Peer STA does not support the requested cipher suite", /* 45 */
Mister Xddbf2c42019-06-08 02:19:27 +00001075 "In a DLS Teardown frame: The teardown was initiated by the "
1076 "DLS peer. In a Disassociation frame: Disassociated because "
1077 "authorized access limit reached", /* 46 */
1078 "In a DLS Teardown frame: The teardown was initiated by the "
1079 "AP. In a Disassociation frame: Disassociated due to external "
1080 "service requirements", /* 47 */
1081 "Invalid FT Action frame count", /* 48 */
1082 "Invalid pairwise master key identifier (PMKID)", /* 49 */
1083 "Invalid MDE", /* 50 */
1084 "Invalid FTE", /* 51 */
1085 "Mesh peering canceled for unknown reasons", /* 52 */
1086 "The mesh STA has reached the supported maximum number of "
1087 "peer mesh STAs", /* 53 */
1088 "The received information violates the Mesh Configuration "
1089 "policy configured in the mesh STA profile", /* 54 */
1090 "The mesh STA has received a Mesh Peering Close frame "
1091 "requesting to close the mesh peering", /* 55 */
1092 "The mesh STA has resent dot11MeshMaxRetries Mesh "
1093 "Peering Open frames, without receiving a Mesh Peering "
Francois-Xavier Le Bail815e0332020-05-25 20:21:57 +02001094 "Confirm frame", /* 56 */
Mister Xddbf2c42019-06-08 02:19:27 +00001095 "The confirmTimer for the mesh peering instance times out", /* 57 */
1096 "The mesh STA fails to unwrap the GTK or the values in the "
1097 "wrapped contents do not match", /* 58 */
1098 "The mesh STA receives inconsistent information about the "
1099 "mesh parameters between mesh peering Management frames", /* 59 */
1100 "The mesh STA fails the authenticated mesh peering exchange "
1101 "because due to failure in selecting either the pairwise "
1102 "ciphersuite or group ciphersuite", /* 60 */
1103 "The mesh STA does not have proxy information for this "
1104 "external destination", /* 61 */
1105 "The mesh STA does not have forwarding information for this "
1106 "destination", /* 62 */
1107 "The mesh STA determines that the link to the next hop of an "
1108 "active path in its forwarding information is no longer "
1109 "usable", /* 63 */
1110 "The Deauthentication frame was sent because the MAC "
1111 "address of the STA already exists in the mesh BSS", /* 64 */
1112 "The mesh STA performs channel switch to meet regulatory "
1113 "requirements", /* 65 */
1114 "The mesh STA performs channel switching with unspecified "
1115 "reason", /* 66 */
itojun7025d462001-06-15 07:39:43 +00001116};
Francois-Xavier Le Bail46f52032018-02-06 19:15:45 +01001117#define NUM_REASONS (sizeof(reason_text) / sizeof(reason_text[0]))
itojun7025d462001-06-15 07:39:43 +00001118
guyd8add7c2003-07-22 17:35:04 +00001119static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001120wep_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001121 const u_char *p)
guy15b5a0a2001-06-12 05:17:16 +00001122{
Guy Harrised85e202014-04-23 00:20:40 -07001123 uint32_t iv;
guy15b5a0a2001-06-12 05:17:16 +00001124
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001125 ND_TCHECK_LEN(p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN);
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001126 iv = GET_LE_U_4(p);
guy15b5a0a2001-06-12 05:17:16 +00001127
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001128 ND_PRINT(" IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
1129 IV_KEYID(iv));
guy15b5a0a2001-06-12 05:17:16 +00001130
guy884ae4d2001-06-13 07:25:57 +00001131 return 1;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001132trunc:
1133 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001134}
1135
Guy Harris7923f062009-11-04 14:55:05 -08001136static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001137parse_elements(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001138 struct mgmt_body_t *pbody, const u_char *p, int offset,
1139 u_int length)
itojun7025d462001-06-15 07:39:43 +00001140{
Guy Harris5b665ba2011-04-05 09:53:57 -07001141 u_int elementlen;
Guy Harris7923f062009-11-04 14:55:05 -08001142 struct ssid_t ssid;
1143 struct challenge_t challenge;
1144 struct rates_t rates;
1145 struct ds_t ds;
1146 struct cf_t cf;
1147 struct tim_t tim;
1148
guy86f96f82005-11-13 12:07:25 +00001149 /*
1150 * We haven't seen any elements yet.
1151 */
Guy Harris7923f062009-11-04 14:55:05 -08001152 pbody->challenge_present = 0;
1153 pbody->ssid_present = 0;
1154 pbody->rates_present = 0;
1155 pbody->ds_present = 0;
1156 pbody->cf_present = 0;
1157 pbody->tim_present = 0;
guy86f96f82005-11-13 12:07:25 +00001158
Guy Harris7923f062009-11-04 14:55:05 -08001159 while (length != 0) {
Guy Harris9f033012014-04-18 19:09:49 -07001160 /* Make sure we at least have the element ID and length. */
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001161 ND_TCHECK_2(p + offset);
Guy Harris9f033012014-04-18 19:09:49 -07001162 if (length < 2)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001163 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001164 elementlen = GET_U_1(p + offset + 1);
Guy Harris9f033012014-04-18 19:09:49 -07001165
1166 /* Make sure we have the entire element. */
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001167 ND_TCHECK_LEN(p + offset + 2, elementlen);
Guy Harris9f033012014-04-18 19:09:49 -07001168 if (length < elementlen + 2)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001169 goto trunc;
Guy Harris9f033012014-04-18 19:09:49 -07001170
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001171 switch (GET_U_1(p + offset)) {
itojun7025d462001-06-15 07:39:43 +00001172 case E_SSID:
Guy Harris7923f062009-11-04 14:55:05 -08001173 memcpy(&ssid, p + offset, 2);
guyd8add7c2003-07-22 17:35:04 +00001174 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001175 length -= 2;
1176 if (ssid.length != 0) {
1177 if (ssid.length > sizeof(ssid.ssid) - 1)
1178 return 0;
Guy Harris7923f062009-11-04 14:55:05 -08001179 memcpy(&ssid.ssid, p + offset, ssid.length);
1180 offset += ssid.length;
1181 length -= ssid.length;
guy86f96f82005-11-13 12:07:25 +00001182 }
Guy Harris7923f062009-11-04 14:55:05 -08001183 ssid.ssid[ssid.length] = '\0';
1184 /*
1185 * Present and not truncated.
1186 *
1187 * If we haven't already seen an SSID IE,
1188 * copy this one, otherwise ignore this one,
1189 * so we later report the first one we saw.
1190 */
1191 if (!pbody->ssid_present) {
1192 pbody->ssid = ssid;
1193 pbody->ssid_present = 1;
1194 }
itojun7025d462001-06-15 07:39:43 +00001195 break;
1196 case E_CHALLENGE:
Guy Harris7923f062009-11-04 14:55:05 -08001197 memcpy(&challenge, p + offset, 2);
guyd8add7c2003-07-22 17:35:04 +00001198 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001199 length -= 2;
1200 if (challenge.length != 0) {
1201 if (challenge.length >
1202 sizeof(challenge.text) - 1)
1203 return 0;
Guy Harris7923f062009-11-04 14:55:05 -08001204 memcpy(&challenge.text, p + offset,
1205 challenge.length);
1206 offset += challenge.length;
1207 length -= challenge.length;
guy86f96f82005-11-13 12:07:25 +00001208 }
Guy Harris7923f062009-11-04 14:55:05 -08001209 challenge.text[challenge.length] = '\0';
1210 /*
1211 * Present and not truncated.
1212 *
1213 * If we haven't already seen a challenge IE,
1214 * copy this one, otherwise ignore this one,
1215 * so we later report the first one we saw.
1216 */
1217 if (!pbody->challenge_present) {
1218 pbody->challenge = challenge;
1219 pbody->challenge_present = 1;
1220 }
itojun7025d462001-06-15 07:39:43 +00001221 break;
1222 case E_RATES:
Guy Harris7923f062009-11-04 14:55:05 -08001223 memcpy(&rates, p + offset, 2);
guyd8add7c2003-07-22 17:35:04 +00001224 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001225 length -= 2;
1226 if (rates.length != 0) {
Francois-Xavier Le Bail46f52032018-02-06 19:15:45 +01001227 if (rates.length > sizeof(rates.rate))
Guy Harris7923f062009-11-04 14:55:05 -08001228 return 0;
Guy Harris7923f062009-11-04 14:55:05 -08001229 memcpy(&rates.rate, p + offset, rates.length);
1230 offset += rates.length;
1231 length -= rates.length;
guy86f96f82005-11-13 12:07:25 +00001232 }
Guy Harris7923f062009-11-04 14:55:05 -08001233 /*
1234 * Present and not truncated.
1235 *
1236 * If we haven't already seen a rates IE,
1237 * copy this one if it's not zero-length,
1238 * otherwise ignore this one, so we later
1239 * report the first one we saw.
1240 *
1241 * We ignore zero-length rates IEs as some
1242 * devices seem to put a zero-length rates
1243 * IE, followed by an SSID IE, followed by
1244 * a non-zero-length rates IE into frames,
1245 * even though IEEE Std 802.11-2007 doesn't
1246 * seem to indicate that a zero-length rates
1247 * IE is valid.
1248 */
1249 if (!pbody->rates_present && rates.length != 0) {
1250 pbody->rates = rates;
1251 pbody->rates_present = 1;
1252 }
itojun7025d462001-06-15 07:39:43 +00001253 break;
1254 case E_DS:
Guy Harris9f033012014-04-18 19:09:49 -07001255 memcpy(&ds, p + offset, 2);
1256 offset += 2;
1257 length -= 2;
1258 if (ds.length != 1) {
1259 offset += ds.length;
1260 length -= ds.length;
1261 break;
1262 }
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001263 ds.channel = GET_U_1(p + offset);
Guy Harris9f033012014-04-18 19:09:49 -07001264 offset += 1;
1265 length -= 1;
Guy Harris7923f062009-11-04 14:55:05 -08001266 /*
1267 * Present and not truncated.
1268 *
1269 * If we haven't already seen a DS IE,
1270 * copy this one, otherwise ignore this one,
1271 * so we later report the first one we saw.
1272 */
1273 if (!pbody->ds_present) {
1274 pbody->ds = ds;
1275 pbody->ds_present = 1;
1276 }
itojun7025d462001-06-15 07:39:43 +00001277 break;
1278 case E_CF:
Guy Harris9f033012014-04-18 19:09:49 -07001279 memcpy(&cf, p + offset, 2);
1280 offset += 2;
1281 length -= 2;
1282 if (cf.length != 6) {
1283 offset += cf.length;
1284 length -= cf.length;
1285 break;
1286 }
1287 memcpy(&cf.count, p + offset, 6);
1288 offset += 6;
1289 length -= 6;
Guy Harris7923f062009-11-04 14:55:05 -08001290 /*
1291 * Present and not truncated.
1292 *
1293 * If we haven't already seen a CF IE,
1294 * copy this one, otherwise ignore this one,
1295 * so we later report the first one we saw.
1296 */
1297 if (!pbody->cf_present) {
1298 pbody->cf = cf;
1299 pbody->cf_present = 1;
1300 }
itojun7025d462001-06-15 07:39:43 +00001301 break;
1302 case E_TIM:
Guy Harris7923f062009-11-04 14:55:05 -08001303 memcpy(&tim, p + offset, 2);
guyd8add7c2003-07-22 17:35:04 +00001304 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001305 length -= 2;
Guy Harris317abbf2017-11-23 13:11:44 -08001306 if (tim.length <= 3U) {
Guy Harris9f033012014-04-18 19:09:49 -07001307 offset += tim.length;
1308 length -= tim.length;
1309 break;
1310 }
Francois-Xavier Le Bail46f52032018-02-06 19:15:45 +01001311 if (tim.length - 3U > sizeof(tim.bitmap))
Guy Harris7923f062009-11-04 14:55:05 -08001312 return 0;
1313 memcpy(&tim.count, p + offset, 3);
guyd8add7c2003-07-22 17:35:04 +00001314 offset += 3;
Guy Harris7923f062009-11-04 14:55:05 -08001315 length -= 3;
guy15b5a0a2001-06-12 05:17:16 +00001316
Guy Harris5edf4052017-03-06 09:42:49 -08001317 memcpy(tim.bitmap, p + offset, tim.length - 3);
Guy Harris7923f062009-11-04 14:55:05 -08001318 offset += tim.length - 3;
1319 length -= tim.length - 3;
1320 /*
1321 * Present and not truncated.
1322 *
1323 * If we haven't already seen a TIM IE,
1324 * copy this one, otherwise ignore this one,
1325 * so we later report the first one we saw.
1326 */
1327 if (!pbody->tim_present) {
1328 pbody->tim = tim;
1329 pbody->tim_present = 1;
1330 }
itojun7025d462001-06-15 07:39:43 +00001331 break;
1332 default:
guy15b5a0a2001-06-12 05:17:16 +00001333#if 0
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001334 ND_PRINT("(1) unhandled element_id (%u) ",
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001335 GET_U_1(p + offset));
guy15b5a0a2001-06-12 05:17:16 +00001336#endif
Guy Harris9f033012014-04-18 19:09:49 -07001337 offset += 2 + elementlen;
1338 length -= 2 + elementlen;
itojun7025d462001-06-15 07:39:43 +00001339 break;
guy15b5a0a2001-06-12 05:17:16 +00001340 }
1341 }
Guy Harris7923f062009-11-04 14:55:05 -08001342
1343 /* No problems found. */
1344 return 1;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001345trunc:
1346 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001347}
1348
1349/*********************************************************************************
1350 * Print Handle functions for the management frame types
1351 *********************************************************************************/
1352
guyd8add7c2003-07-22 17:35:04 +00001353static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001354handle_beacon(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001355 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001356{
1357 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001358 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001359 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001360
itojun7025d462001-06-15 07:39:43 +00001361 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001362
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001363 ND_TCHECK_LEN(p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1364 IEEE802_11_CAPINFO_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001365 if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1366 IEEE802_11_CAPINFO_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001367 goto trunc;
guyc5897772005-10-17 07:58:56 +00001368 memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
guyd8add7c2003-07-22 17:35:04 +00001369 offset += IEEE802_11_TSTAMP_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001370 length -= IEEE802_11_TSTAMP_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001371 pbody.beacon_interval = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001372 offset += IEEE802_11_BCNINT_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001373 length -= IEEE802_11_BCNINT_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001374 pbody.capability_info = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001375 offset += IEEE802_11_CAPINFO_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001376 length -= IEEE802_11_CAPINFO_LEN;
guy15b5a0a2001-06-12 05:17:16 +00001377
Denis Ovsienko26498832014-03-31 16:46:12 +04001378 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001379
guy86f96f82005-11-13 12:07:25 +00001380 PRINT_SSID(pbody);
guy6c6b1ac2002-05-13 08:30:19 +00001381 PRINT_RATES(pbody);
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001382 ND_PRINT(" %s",
1383 CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
guy86f96f82005-11-13 12:07:25 +00001384 PRINT_DS_CHANNEL(pbody);
itojun7025d462001-06-15 07:39:43 +00001385
Guy Harris7923f062009-11-04 14:55:05 -08001386 return ret;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001387trunc:
1388 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001389}
1390
guyd8add7c2003-07-22 17:35:04 +00001391static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001392handle_assoc_request(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001393 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001394{
1395 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001396 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001397 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001398
itojun7025d462001-06-15 07:39:43 +00001399 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001400
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001401 ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001402 if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001403 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001404 pbody.capability_info = GET_LE_U_2(p);
guyd8add7c2003-07-22 17:35:04 +00001405 offset += IEEE802_11_CAPINFO_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001406 length -= IEEE802_11_CAPINFO_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001407 pbody.listen_interval = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001408 offset += IEEE802_11_LISTENINT_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001409 length -= IEEE802_11_LISTENINT_LEN;
itojun7025d462001-06-15 07:39:43 +00001410
Denis Ovsienko26498832014-03-31 16:46:12 +04001411 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001412
guy86f96f82005-11-13 12:07:25 +00001413 PRINT_SSID(pbody);
guy6c6b1ac2002-05-13 08:30:19 +00001414 PRINT_RATES(pbody);
Guy Harris7923f062009-11-04 14:55:05 -08001415 return ret;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001416trunc:
1417 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001418}
1419
guyd8add7c2003-07-22 17:35:04 +00001420static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001421handle_assoc_response(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001422 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001423{
1424 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001425 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001426 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001427
itojun7025d462001-06-15 07:39:43 +00001428 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001429
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001430 ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1431 IEEE802_11_AID_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001432 if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1433 IEEE802_11_AID_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001434 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001435 pbody.capability_info = GET_LE_U_2(p);
guyd8add7c2003-07-22 17:35:04 +00001436 offset += IEEE802_11_CAPINFO_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001437 length -= IEEE802_11_CAPINFO_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001438 pbody.status_code = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001439 offset += IEEE802_11_STATUS_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001440 length -= IEEE802_11_STATUS_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001441 pbody.aid = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001442 offset += IEEE802_11_AID_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001443 length -= IEEE802_11_AID_LEN;
guy15b5a0a2001-06-12 05:17:16 +00001444
Denis Ovsienko26498832014-03-31 16:46:12 +04001445 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001446
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001447 ND_PRINT(" AID(%x) :%s: %s", ((uint16_t)(pbody.aid << 2 )) >> 2 ,
itojun7025d462001-06-15 07:39:43 +00001448 CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
guyd9441bb2005-07-30 00:05:32 +00001449 (pbody.status_code < NUM_STATUSES
1450 ? status_text[pbody.status_code]
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001451 : "n/a"));
guy15b5a0a2001-06-12 05:17:16 +00001452
Guy Harris7923f062009-11-04 14:55:05 -08001453 return ret;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001454trunc:
1455 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001456}
1457
guyd8add7c2003-07-22 17:35:04 +00001458static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001459handle_reassoc_request(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001460 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001461{
1462 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001463 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001464 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001465
itojun7025d462001-06-15 07:39:43 +00001466 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001467
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001468 ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1469 IEEE802_11_AP_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001470 if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1471 IEEE802_11_AP_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001472 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001473 pbody.capability_info = GET_LE_U_2(p);
guyd8add7c2003-07-22 17:35:04 +00001474 offset += IEEE802_11_CAPINFO_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001475 length -= IEEE802_11_CAPINFO_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001476 pbody.listen_interval = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001477 offset += IEEE802_11_LISTENINT_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001478 length -= IEEE802_11_LISTENINT_LEN;
guyd8add7c2003-07-22 17:35:04 +00001479 memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
1480 offset += IEEE802_11_AP_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001481 length -= IEEE802_11_AP_LEN;
guy15b5a0a2001-06-12 05:17:16 +00001482
Denis Ovsienko26498832014-03-31 16:46:12 +04001483 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001484
guy86f96f82005-11-13 12:07:25 +00001485 PRINT_SSID(pbody);
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001486 ND_PRINT(" AP : %s", etheraddr_string(ndo, pbody.ap ));
itojun7025d462001-06-15 07:39:43 +00001487
Guy Harris7923f062009-11-04 14:55:05 -08001488 return ret;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001489trunc:
1490 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001491}
1492
guyd8add7c2003-07-22 17:35:04 +00001493static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001494handle_reassoc_response(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001495 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001496{
Antonin Décimo0b3880c2019-01-23 17:28:14 +01001497 /* Same as a Association Response */
Denis Ovsienko26498832014-03-31 16:46:12 +04001498 return handle_assoc_response(ndo, p, length);
guy15b5a0a2001-06-12 05:17:16 +00001499}
1500
guyd8add7c2003-07-22 17:35:04 +00001501static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001502handle_probe_request(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001503 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001504{
1505 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001506 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001507 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001508
itojun7025d462001-06-15 07:39:43 +00001509 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001510
Denis Ovsienko26498832014-03-31 16:46:12 +04001511 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001512
guy86f96f82005-11-13 12:07:25 +00001513 PRINT_SSID(pbody);
guy6c6b1ac2002-05-13 08:30:19 +00001514 PRINT_RATES(pbody);
guy15b5a0a2001-06-12 05:17:16 +00001515
Guy Harris7923f062009-11-04 14:55:05 -08001516 return ret;
guy15b5a0a2001-06-12 05:17:16 +00001517}
1518
guyd8add7c2003-07-22 17:35:04 +00001519static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001520handle_probe_response(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001521 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001522{
1523 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001524 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001525 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001526
itojun7025d462001-06-15 07:39:43 +00001527 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001528
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001529 ND_TCHECK_LEN(p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1530 IEEE802_11_CAPINFO_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001531 if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1532 IEEE802_11_CAPINFO_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001533 goto trunc;
guyd8add7c2003-07-22 17:35:04 +00001534 memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
1535 offset += IEEE802_11_TSTAMP_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001536 length -= IEEE802_11_TSTAMP_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001537 pbody.beacon_interval = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001538 offset += IEEE802_11_BCNINT_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001539 length -= IEEE802_11_BCNINT_LEN;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001540 pbody.capability_info = GET_LE_U_2(p + offset);
guyd8add7c2003-07-22 17:35:04 +00001541 offset += IEEE802_11_CAPINFO_LEN;
Guy Harris7923f062009-11-04 14:55:05 -08001542 length -= IEEE802_11_CAPINFO_LEN;
itojun7025d462001-06-15 07:39:43 +00001543
Denis Ovsienko26498832014-03-31 16:46:12 +04001544 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001545
guy86f96f82005-11-13 12:07:25 +00001546 PRINT_SSID(pbody);
guy6c6b1ac2002-05-13 08:30:19 +00001547 PRINT_RATES(pbody);
guy86f96f82005-11-13 12:07:25 +00001548 PRINT_DS_CHANNEL(pbody);
guy15b5a0a2001-06-12 05:17:16 +00001549
Guy Harris7923f062009-11-04 14:55:05 -08001550 return ret;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001551trunc:
1552 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001553}
1554
guyd8add7c2003-07-22 17:35:04 +00001555static int
1556handle_atim(void)
guy15b5a0a2001-06-12 05:17:16 +00001557{
1558 /* the frame body for ATIM is null. */
guy884ae4d2001-06-13 07:25:57 +00001559 return 1;
guy15b5a0a2001-06-12 05:17:16 +00001560}
1561
guyd8add7c2003-07-22 17:35:04 +00001562static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001563handle_disassoc(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001564 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001565{
1566 struct mgmt_body_t pbody;
guy15b5a0a2001-06-12 05:17:16 +00001567
itojun7025d462001-06-15 07:39:43 +00001568 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001569
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001570 ND_TCHECK_LEN(p, IEEE802_11_REASON_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001571 if (length < IEEE802_11_REASON_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001572 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001573 pbody.reason_code = GET_LE_U_2(p);
guy15b5a0a2001-06-12 05:17:16 +00001574
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001575 ND_PRINT(": %s",
guyd9441bb2005-07-30 00:05:32 +00001576 (pbody.reason_code < NUM_REASONS)
1577 ? reason_text[pbody.reason_code]
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001578 : "Reserved");
guy15b5a0a2001-06-12 05:17:16 +00001579
guy884ae4d2001-06-13 07:25:57 +00001580 return 1;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001581trunc:
1582 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001583}
1584
guyd8add7c2003-07-22 17:35:04 +00001585static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001586handle_auth(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001587 const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001588{
1589 struct mgmt_body_t pbody;
itojun7025d462001-06-15 07:39:43 +00001590 int offset = 0;
Guy Harris7923f062009-11-04 14:55:05 -08001591 int ret;
guy15b5a0a2001-06-12 05:17:16 +00001592
itojun7025d462001-06-15 07:39:43 +00001593 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001594
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001595 ND_TCHECK_6(p);
Guy Harris7923f062009-11-04 14:55:05 -08001596 if (length < 6)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001597 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001598 pbody.auth_alg = GET_LE_U_2(p);
guy15b5a0a2001-06-12 05:17:16 +00001599 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001600 length -= 2;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001601 pbody.auth_trans_seq_num = GET_LE_U_2(p + offset);
guy15b5a0a2001-06-12 05:17:16 +00001602 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001603 length -= 2;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001604 pbody.status_code = GET_LE_U_2(p + offset);
guy15b5a0a2001-06-12 05:17:16 +00001605 offset += 2;
Guy Harris7923f062009-11-04 14:55:05 -08001606 length -= 2;
guy15b5a0a2001-06-12 05:17:16 +00001607
Denis Ovsienko26498832014-03-31 16:46:12 +04001608 ret = parse_elements(ndo, &pbody, p, offset, length);
guy15b5a0a2001-06-12 05:17:16 +00001609
itojun7025d462001-06-15 07:39:43 +00001610 if ((pbody.auth_alg == 1) &&
guyd8add7c2003-07-22 17:35:04 +00001611 ((pbody.auth_trans_seq_num == 2) ||
1612 (pbody.auth_trans_seq_num == 3))) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001613 ND_PRINT(" (%s)-%x [Challenge Text] %s",
guyd9441bb2005-07-30 00:05:32 +00001614 (pbody.auth_alg < NUM_AUTH_ALGS)
1615 ? auth_alg_text[pbody.auth_alg]
1616 : "Reserved",
itojun7025d462001-06-15 07:39:43 +00001617 pbody.auth_trans_seq_num,
guyd8add7c2003-07-22 17:35:04 +00001618 ((pbody.auth_trans_seq_num % 2)
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001619 ? ((pbody.status_code < NUM_STATUSES)
guyd8add7c2003-07-22 17:35:04 +00001620 ? status_text[pbody.status_code]
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001621 : "n/a") : ""));
Guy Harris7923f062009-11-04 14:55:05 -08001622 return ret;
guy15b5a0a2001-06-12 05:17:16 +00001623 }
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001624 ND_PRINT(" (%s)-%x: %s",
guyd9441bb2005-07-30 00:05:32 +00001625 (pbody.auth_alg < NUM_AUTH_ALGS)
1626 ? auth_alg_text[pbody.auth_alg]
1627 : "Reserved",
guyd8add7c2003-07-22 17:35:04 +00001628 pbody.auth_trans_seq_num,
1629 (pbody.auth_trans_seq_num % 2)
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001630 ? ((pbody.status_code < NUM_STATUSES)
guyd9441bb2005-07-30 00:05:32 +00001631 ? status_text[pbody.status_code]
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001632 : "n/a")
1633 : "");
guy15b5a0a2001-06-12 05:17:16 +00001634
Guy Harris7923f062009-11-04 14:55:05 -08001635 return ret;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001636trunc:
1637 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001638}
1639
guyd8add7c2003-07-22 17:35:04 +00001640static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001641handle_deauth(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001642 const uint8_t *src, const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001643{
1644 struct mgmt_body_t pbody;
guyd8add7c2003-07-22 17:35:04 +00001645 const char *reason = NULL;
guy15b5a0a2001-06-12 05:17:16 +00001646
itojun7025d462001-06-15 07:39:43 +00001647 memset(&pbody, 0, sizeof(pbody));
guy15b5a0a2001-06-12 05:17:16 +00001648
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001649 ND_TCHECK_LEN(p, IEEE802_11_REASON_LEN);
Guy Harris7923f062009-11-04 14:55:05 -08001650 if (length < IEEE802_11_REASON_LEN)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001651 goto trunc;
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001652 pbody.reason_code = GET_LE_U_2(p);
guyd8add7c2003-07-22 17:35:04 +00001653
guyd9441bb2005-07-30 00:05:32 +00001654 reason = (pbody.reason_code < NUM_REASONS)
1655 ? reason_text[pbody.reason_code]
1656 : "Reserved";
itojun7025d462001-06-15 07:39:43 +00001657
Denis Ovsienko26498832014-03-31 16:46:12 +04001658 if (ndo->ndo_eflag) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001659 ND_PRINT(": %s", reason);
itojun7025d462001-06-15 07:39:43 +00001660 } else {
Guy Harris306c2a02020-01-19 19:55:38 -08001661 ND_PRINT(" (%s): %s", GET_ETHERADDR_STRING(src), reason);
guy15b5a0a2001-06-12 05:17:16 +00001662 }
guy884ae4d2001-06-13 07:25:57 +00001663 return 1;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001664trunc:
1665 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001666}
1667
Guy Harrisaae14f92009-07-14 18:23:06 -07001668#define PRINT_HT_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001669 (v) == 0 ? ND_PRINT("TxChWidth"): \
1670 (v) == 1 ? ND_PRINT("MIMOPwrSave"): \
1671 ND_PRINT("Act#%u", (v)))
Guy Harrisaae14f92009-07-14 18:23:06 -07001672#define PRINT_BA_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001673 (v) == 0 ? ND_PRINT("ADDBA Request"): \
1674 (v) == 1 ? ND_PRINT("ADDBA Response"): \
1675 (v) == 2 ? ND_PRINT("DELBA"): \
1676 ND_PRINT("Act#%u", (v)))
Guy Harrisaae14f92009-07-14 18:23:06 -07001677#define PRINT_MESHLINK_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001678 (v) == 0 ? ND_PRINT("Request"): \
1679 (v) == 1 ? ND_PRINT("Report"): \
1680 ND_PRINT("Act#%u", (v)))
Guy Harrisaae14f92009-07-14 18:23:06 -07001681#define PRINT_MESHPEERING_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001682 (v) == 0 ? ND_PRINT("Open"): \
1683 (v) == 1 ? ND_PRINT("Confirm"): \
1684 (v) == 2 ? ND_PRINT("Close"): \
1685 ND_PRINT("Act#%u", (v)))
Guy Harrisaae14f92009-07-14 18:23:06 -07001686#define PRINT_MESHPATH_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001687 (v) == 0 ? ND_PRINT("Request"): \
1688 (v) == 1 ? ND_PRINT("Report"): \
1689 (v) == 2 ? ND_PRINT("Error"): \
1690 (v) == 3 ? ND_PRINT("RootAnnouncement"): \
1691 ND_PRINT("Act#%u", (v)))
Guy Harrisaae14f92009-07-14 18:23:06 -07001692
Monthadar Al Jaberif1c05532012-03-27 19:22:51 +02001693#define PRINT_MESH_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001694 (v) == 0 ? ND_PRINT("MeshLink"): \
1695 (v) == 1 ? ND_PRINT("HWMP"): \
1696 (v) == 2 ? ND_PRINT("Gate Announcement"): \
1697 (v) == 3 ? ND_PRINT("Congestion Control"): \
1698 (v) == 4 ? ND_PRINT("MCCA Setup Request"): \
1699 (v) == 5 ? ND_PRINT("MCCA Setup Reply"): \
1700 (v) == 6 ? ND_PRINT("MCCA Advertisement Request"): \
1701 (v) == 7 ? ND_PRINT("MCCA Advertisement"): \
1702 (v) == 8 ? ND_PRINT("MCCA Teardown"): \
1703 (v) == 9 ? ND_PRINT("TBTT Adjustment Request"): \
1704 (v) == 10 ? ND_PRINT("TBTT Adjustment Response"): \
1705 ND_PRINT("Act#%u", (v)))
Monthadar Al Jaberif1c05532012-03-27 19:22:51 +02001706#define PRINT_MULTIHOP_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001707 (v) == 0 ? ND_PRINT("Proxy Update"): \
1708 (v) == 1 ? ND_PRINT("Proxy Update Confirmation"): \
1709 ND_PRINT("Act#%u", (v)))
Monthadar Al Jaberif1c05532012-03-27 19:22:51 +02001710#define PRINT_SELFPROT_ACTION(v) (\
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001711 (v) == 1 ? ND_PRINT("Peering Open"): \
1712 (v) == 2 ? ND_PRINT("Peering Confirm"): \
1713 (v) == 3 ? ND_PRINT("Peering Close"): \
1714 (v) == 4 ? ND_PRINT("Group Key Inform"): \
1715 (v) == 5 ? ND_PRINT("Group Key Acknowledge"): \
1716 ND_PRINT("Act#%u", (v)))
Monthadar Al Jaberif1c05532012-03-27 19:22:51 +02001717
Guy Harrisaae14f92009-07-14 18:23:06 -07001718static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001719handle_action(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001720 const uint8_t *src, const u_char *p, u_int length)
Guy Harrisaae14f92009-07-14 18:23:06 -07001721{
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001722 ND_TCHECK_2(p);
Guy Harris7923f062009-11-04 14:55:05 -08001723 if (length < 2)
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001724 goto trunc;
Denis Ovsienko26498832014-03-31 16:46:12 +04001725 if (ndo->ndo_eflag) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001726 ND_PRINT(": ");
Guy Harrisaae14f92009-07-14 18:23:06 -07001727 } else {
Guy Harris306c2a02020-01-19 19:55:38 -08001728 ND_PRINT(" (%s): ", GET_ETHERADDR_STRING(src));
Guy Harrisaae14f92009-07-14 18:23:06 -07001729 }
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001730 switch (GET_U_1(p)) {
1731 case 0: ND_PRINT("Spectrum Management Act#%u", GET_U_1(p + 1)); break;
1732 case 1: ND_PRINT("QoS Act#%u", GET_U_1(p + 1)); break;
1733 case 2: ND_PRINT("DLS Act#%u", GET_U_1(p + 1)); break;
1734 case 3: ND_PRINT("BA "); PRINT_BA_ACTION(GET_U_1(p + 1)); break;
1735 case 7: ND_PRINT("HT "); PRINT_HT_ACTION(GET_U_1(p + 1)); break;
1736 case 13: ND_PRINT("MeshAction "); PRINT_MESH_ACTION(GET_U_1(p + 1)); break;
Monthadar Al Jaberif1c05532012-03-27 19:22:51 +02001737 case 14:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001738 ND_PRINT("MultiohopAction ");
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001739 PRINT_MULTIHOP_ACTION(GET_U_1(p + 1)); break;
Monthadar Al Jaberif1c05532012-03-27 19:22:51 +02001740 case 15:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001741 ND_PRINT("SelfprotectAction ");
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001742 PRINT_SELFPROT_ACTION(GET_U_1(p + 1)); break;
1743 case 127: ND_PRINT("Vendor Act#%u", GET_U_1(p + 1)); break;
Guy Harrisaae14f92009-07-14 18:23:06 -07001744 default:
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001745 ND_PRINT("Reserved(%u) Act#%u", GET_U_1(p), GET_U_1(p + 1));
Guy Harrisaae14f92009-07-14 18:23:06 -07001746 break;
1747 }
1748 return 1;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001749trunc:
1750 return 0;
Guy Harrisaae14f92009-07-14 18:23:06 -07001751}
1752
guy15b5a0a2001-06-12 05:17:16 +00001753
1754/*********************************************************************************
1755 * Print Body funcs
1756 *********************************************************************************/
1757
1758
guyd8add7c2003-07-22 17:35:04 +00001759static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001760mgmt_body_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001761 uint16_t fc, const uint8_t *src, const u_char *p, u_int length)
guy15b5a0a2001-06-12 05:17:16 +00001762{
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001763 ND_PRINT("%s", tok2str(st_str, "Unhandled Management subtype(%x)", FC_SUBTYPE(fc)));
Guy Harris698e6582015-04-17 13:22:16 -07001764
1765 /* There may be a problem w/ AP not having this bit set */
1766 if (FC_PROTECTED(fc))
1767 return wep_print(ndo, p);
itojun7025d462001-06-15 07:39:43 +00001768 switch (FC_SUBTYPE(fc)) {
1769 case ST_ASSOC_REQUEST:
Denis Ovsienko26498832014-03-31 16:46:12 +04001770 return handle_assoc_request(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001771 case ST_ASSOC_RESPONSE:
Denis Ovsienko26498832014-03-31 16:46:12 +04001772 return handle_assoc_response(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001773 case ST_REASSOC_REQUEST:
Denis Ovsienko26498832014-03-31 16:46:12 +04001774 return handle_reassoc_request(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001775 case ST_REASSOC_RESPONSE:
Denis Ovsienko26498832014-03-31 16:46:12 +04001776 return handle_reassoc_response(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001777 case ST_PROBE_REQUEST:
Denis Ovsienko26498832014-03-31 16:46:12 +04001778 return handle_probe_request(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001779 case ST_PROBE_RESPONSE:
Denis Ovsienko26498832014-03-31 16:46:12 +04001780 return handle_probe_response(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001781 case ST_BEACON:
Denis Ovsienko26498832014-03-31 16:46:12 +04001782 return handle_beacon(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001783 case ST_ATIM:
guyd8add7c2003-07-22 17:35:04 +00001784 return handle_atim();
itojun7025d462001-06-15 07:39:43 +00001785 case ST_DISASSOC:
Denis Ovsienko26498832014-03-31 16:46:12 +04001786 return handle_disassoc(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001787 case ST_AUTH:
Denis Ovsienko26498832014-03-31 16:46:12 +04001788 return handle_auth(ndo, p, length);
itojun7025d462001-06-15 07:39:43 +00001789 case ST_DEAUTH:
Guy Harrisce0f6c92015-04-17 13:49:12 -07001790 return handle_deauth(ndo, src, p, length);
Guy Harrisaae14f92009-07-14 18:23:06 -07001791 case ST_ACTION:
Guy Harrisce0f6c92015-04-17 13:49:12 -07001792 return handle_action(ndo, src, p, length);
itojun7025d462001-06-15 07:39:43 +00001793 default:
itojun7025d462001-06-15 07:39:43 +00001794 return 1;
guy15b5a0a2001-06-12 05:17:16 +00001795 }
1796}
1797
1798
1799/*********************************************************************************
1800 * Handles printing all the control frame types
1801 *********************************************************************************/
1802
guyd8add7c2003-07-22 17:35:04 +00001803static int
Denis Ovsienko26498832014-03-31 16:46:12 +04001804ctrl_body_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001805 uint16_t fc, const u_char *p)
guy15b5a0a2001-06-12 05:17:16 +00001806{
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001807 ND_PRINT("%s", tok2str(ctrl_str, "Unknown Ctrl Subtype", FC_SUBTYPE(fc)));
itojun7025d462001-06-15 07:39:43 +00001808 switch (FC_SUBTYPE(fc)) {
Guy Harrisf2aee3e2009-01-15 02:35:19 -08001809 case CTRL_CONTROL_WRAPPER:
Guy Harrisf2aee3e2009-01-15 02:35:19 -08001810 /* XXX - requires special handling */
1811 break;
Guy Harrisaae14f92009-07-14 18:23:06 -07001812 case CTRL_BAR:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001813 ND_TCHECK_LEN(p, CTRL_BAR_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001814 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001815 ND_PRINT(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
Guy Harris306c2a02020-01-19 19:55:38 -08001816 GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ra),
1817 GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ta),
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001818 GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->ctl),
1819 GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->seq));
Guy Harrisf2aee3e2009-01-15 02:35:19 -08001820 break;
Guy Harrisaae14f92009-07-14 18:23:06 -07001821 case CTRL_BA:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001822 ND_TCHECK_LEN(p, CTRL_BA_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001823 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001824 ND_PRINT(" RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001825 GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ra));
Guy Harrisf2aee3e2009-01-15 02:35:19 -08001826 break;
itojun7025d462001-06-15 07:39:43 +00001827 case CTRL_PS_POLL:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001828 ND_TCHECK_LEN(p, CTRL_PS_POLL_HDRLEN);
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001829 ND_PRINT(" AID(%x)",
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02001830 GET_LE_U_2(((const struct ctrl_ps_poll_hdr_t *)p)->aid));
itojun7025d462001-06-15 07:39:43 +00001831 break;
1832 case CTRL_RTS:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001833 ND_TCHECK_LEN(p, CTRL_RTS_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001834 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001835 ND_PRINT(" TA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001836 GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ta));
itojun7025d462001-06-15 07:39:43 +00001837 break;
1838 case CTRL_CTS:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001839 ND_TCHECK_LEN(p, CTRL_CTS_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001840 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001841 ND_PRINT(" RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001842 GET_ETHERADDR_STRING(((const struct ctrl_cts_hdr_t *)p)->ra));
itojun7025d462001-06-15 07:39:43 +00001843 break;
1844 case CTRL_ACK:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001845 ND_TCHECK_LEN(p, CTRL_ACK_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001846 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001847 ND_PRINT(" RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001848 GET_ETHERADDR_STRING(((const struct ctrl_ack_hdr_t *)p)->ra));
itojun7025d462001-06-15 07:39:43 +00001849 break;
1850 case CTRL_CF_END:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001851 ND_TCHECK_LEN(p, CTRL_END_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001852 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001853 ND_PRINT(" RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001854 GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->ra));
itojun7025d462001-06-15 07:39:43 +00001855 break;
1856 case CTRL_END_ACK:
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001857 ND_TCHECK_LEN(p, CTRL_END_ACK_HDRLEN);
Denis Ovsienko26498832014-03-31 16:46:12 +04001858 if (!ndo->ndo_eflag)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001859 ND_PRINT(" RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001860 GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->ra));
itojun7025d462001-06-15 07:39:43 +00001861 break;
guy15b5a0a2001-06-12 05:17:16 +00001862 }
guy884ae4d2001-06-13 07:25:57 +00001863 return 1;
Francois-Xavier Le Bail91b0ee02019-02-24 10:47:24 +01001864trunc:
1865 return 0;
guy15b5a0a2001-06-12 05:17:16 +00001866}
1867
itojun7025d462001-06-15 07:39:43 +00001868/*
guy15b5a0a2001-06-12 05:17:16 +00001869 * Data Frame - Address field contents
1870 *
1871 * To Ds | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
1872 * 0 | 0 | DA | SA | BSSID | n/a
1873 * 0 | 1 | DA | BSSID | SA | n/a
1874 * 1 | 0 | BSSID | SA | DA | n/a
1875 * 1 | 1 | RA | TA | DA | SA
itojun7025d462001-06-15 07:39:43 +00001876 */
guy15b5a0a2001-06-12 05:17:16 +00001877
Guy Harris1ac906f2015-04-15 19:44:34 -07001878/*
1879 * Function to get source and destination MAC addresses for a data frame.
1880 */
guye070cf22002-12-18 08:53:18 +00001881static void
Guy Harris1ac906f2015-04-15 19:44:34 -07001882get_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01001883 const uint8_t **dstp)
Guy Harris1ac906f2015-04-15 19:44:34 -07001884{
1885#define ADDR1 (p + 4)
1886#define ADDR2 (p + 10)
1887#define ADDR3 (p + 16)
1888#define ADDR4 (p + 24)
1889
Guy Harris599b0312015-04-27 00:02:31 -07001890 if (!FC_TO_DS(fc)) {
1891 if (!FC_FROM_DS(fc)) {
1892 /* not To DS and not From DS */
1893 *srcp = ADDR2;
1894 *dstp = ADDR1;
1895 } else {
1896 /* not To DS and From DS */
1897 *srcp = ADDR3;
1898 *dstp = ADDR1;
1899 }
1900 } else {
1901 if (!FC_FROM_DS(fc)) {
1902 /* From DS and not To DS */
1903 *srcp = ADDR2;
1904 *dstp = ADDR3;
1905 } else {
1906 /* To DS and From DS */
1907 *srcp = ADDR4;
1908 *dstp = ADDR3;
1909 }
Guy Harris1ac906f2015-04-15 19:44:34 -07001910 }
1911
1912#undef ADDR1
1913#undef ADDR2
1914#undef ADDR3
1915#undef ADDR4
1916}
1917
Guy Harrisce0f6c92015-04-17 13:49:12 -07001918static void
1919get_mgmt_src_dst_mac(const u_char *p, const uint8_t **srcp, const uint8_t **dstp)
1920{
1921 const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
1922
1923 if (srcp != NULL)
1924 *srcp = hp->sa;
1925 if (dstp != NULL)
1926 *dstp = hp->da;
1927}
1928
Guy Harris1ac906f2015-04-15 19:44:34 -07001929/*
1930 * Print Header funcs
1931 */
1932
1933static void
1934data_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
guy15b5a0a2001-06-12 05:17:16 +00001935{
guy45b4f192007-07-22 22:00:40 +00001936 u_int subtype = FC_SUBTYPE(fc);
1937
1938 if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) ||
1939 DATA_FRAME_IS_QOS(subtype)) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001940 ND_PRINT("CF ");
guy45b4f192007-07-22 22:00:40 +00001941 if (DATA_FRAME_IS_CF_ACK(subtype)) {
1942 if (DATA_FRAME_IS_CF_POLL(subtype))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001943 ND_PRINT("Ack/Poll");
guy45b4f192007-07-22 22:00:40 +00001944 else
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001945 ND_PRINT("Ack");
guy45b4f192007-07-22 22:00:40 +00001946 } else {
1947 if (DATA_FRAME_IS_CF_POLL(subtype))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001948 ND_PRINT("Poll");
guy45b4f192007-07-22 22:00:40 +00001949 }
1950 if (DATA_FRAME_IS_QOS(subtype))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001951 ND_PRINT("+QoS");
1952 ND_PRINT(" ");
guyf72f67a2003-02-04 05:53:21 +00001953 }
1954
itojun7025d462001-06-15 07:39:43 +00001955#define ADDR1 (p + 4)
1956#define ADDR2 (p + 10)
1957#define ADDR3 (p + 16)
1958#define ADDR4 (p + 24)
1959
guyd8add7c2003-07-22 17:35:04 +00001960 if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001961 ND_PRINT("DA:%s SA:%s BSSID:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001962 GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1963 GET_ETHERADDR_STRING(ADDR3));
guyd8add7c2003-07-22 17:35:04 +00001964 } else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001965 ND_PRINT("DA:%s BSSID:%s SA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001966 GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1967 GET_ETHERADDR_STRING(ADDR3));
guyd8add7c2003-07-22 17:35:04 +00001968 } else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001969 ND_PRINT("BSSID:%s SA:%s DA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001970 GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1971 GET_ETHERADDR_STRING(ADDR3));
guyd8add7c2003-07-22 17:35:04 +00001972 } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001973 ND_PRINT("RA:%s TA:%s DA:%s SA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001974 GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1975 GET_ETHERADDR_STRING(ADDR3), GET_ETHERADDR_STRING(ADDR4));
guy15b5a0a2001-06-12 05:17:16 +00001976 }
itojun7025d462001-06-15 07:39:43 +00001977
1978#undef ADDR1
1979#undef ADDR2
1980#undef ADDR3
1981#undef ADDR4
guy15b5a0a2001-06-12 05:17:16 +00001982}
1983
guye070cf22002-12-18 08:53:18 +00001984static void
Guy Harris1ac906f2015-04-15 19:44:34 -07001985mgmt_header_print(netdissect_options *ndo, const u_char *p)
guy15b5a0a2001-06-12 05:17:16 +00001986{
itojun7025d462001-06-15 07:39:43 +00001987 const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
guy15b5a0a2001-06-12 05:17:16 +00001988
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001989 ND_PRINT("BSSID:%s DA:%s SA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08001990 GET_ETHERADDR_STRING((hp)->bssid), GET_ETHERADDR_STRING((hp)->da),
1991 GET_ETHERADDR_STRING((hp)->sa));
guy15b5a0a2001-06-12 05:17:16 +00001992}
1993
guye070cf22002-12-18 08:53:18 +00001994static void
Guy Harris1ac906f2015-04-15 19:44:34 -07001995ctrl_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
guy15b5a0a2001-06-12 05:17:16 +00001996{
itojun7025d462001-06-15 07:39:43 +00001997 switch (FC_SUBTYPE(fc)) {
Guy Harrisaae14f92009-07-14 18:23:06 -07001998 case CTRL_BAR:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01001999 ND_PRINT(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
Guy Harris306c2a02020-01-19 19:55:38 -08002000 GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ra),
2001 GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ta),
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02002002 GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->ctl),
2003 GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->seq));
Guy Harrisaae14f92009-07-14 18:23:06 -07002004 break;
2005 case CTRL_BA:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002006 ND_PRINT("RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002007 GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ra));
Guy Harrisaae14f92009-07-14 18:23:06 -07002008 break;
itojun7025d462001-06-15 07:39:43 +00002009 case CTRL_PS_POLL:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002010 ND_PRINT("BSSID:%s TA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002011 GET_ETHERADDR_STRING(((const struct ctrl_ps_poll_hdr_t *)p)->bssid),
2012 GET_ETHERADDR_STRING(((const struct ctrl_ps_poll_hdr_t *)p)->ta));
itojun7025d462001-06-15 07:39:43 +00002013 break;
2014 case CTRL_RTS:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002015 ND_PRINT("RA:%s TA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002016 GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ra),
2017 GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ta));
itojun7025d462001-06-15 07:39:43 +00002018 break;
2019 case CTRL_CTS:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002020 ND_PRINT("RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002021 GET_ETHERADDR_STRING(((const struct ctrl_cts_hdr_t *)p)->ra));
itojun7025d462001-06-15 07:39:43 +00002022 break;
2023 case CTRL_ACK:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002024 ND_PRINT("RA:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002025 GET_ETHERADDR_STRING(((const struct ctrl_ack_hdr_t *)p)->ra));
itojun7025d462001-06-15 07:39:43 +00002026 break;
2027 case CTRL_CF_END:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002028 ND_PRINT("RA:%s BSSID:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002029 GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->ra),
2030 GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->bssid));
itojun7025d462001-06-15 07:39:43 +00002031 break;
2032 case CTRL_END_ACK:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002033 ND_PRINT("RA:%s BSSID:%s ",
Guy Harris306c2a02020-01-19 19:55:38 -08002034 GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->ra),
2035 GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->bssid));
itojun7025d462001-06-15 07:39:43 +00002036 break;
2037 default:
Guy Harrise4c749f2015-04-15 18:13:53 -07002038 /* We shouldn't get here - we should already have quit */
guye070cf22002-12-18 08:53:18 +00002039 break;
guy15b5a0a2001-06-12 05:17:16 +00002040 }
2041}
2042
guyd8add7c2003-07-22 17:35:04 +00002043static int
Denis Ovsienko26498832014-03-31 16:46:12 +04002044extract_header_length(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002045 uint16_t fc)
guy15b5a0a2001-06-12 05:17:16 +00002046{
guy45b4f192007-07-22 22:00:40 +00002047 int len;
2048
itojun7025d462001-06-15 07:39:43 +00002049 switch (FC_TYPE(fc)) {
2050 case T_MGMT:
guy91f7cb22003-07-22 17:36:57 +00002051 return MGMT_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002052 case T_CTRL:
2053 switch (FC_SUBTYPE(fc)) {
Guy Harris7b636c72015-04-15 12:51:34 -07002054 case CTRL_CONTROL_WRAPPER:
2055 return CTRL_CONTROL_WRAPPER_HDRLEN;
Guy Harrisaae14f92009-07-14 18:23:06 -07002056 case CTRL_BAR:
2057 return CTRL_BAR_HDRLEN;
Guy Harris7b636c72015-04-15 12:51:34 -07002058 case CTRL_BA:
2059 return CTRL_BA_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002060 case CTRL_PS_POLL:
guy91f7cb22003-07-22 17:36:57 +00002061 return CTRL_PS_POLL_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002062 case CTRL_RTS:
guy91f7cb22003-07-22 17:36:57 +00002063 return CTRL_RTS_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002064 case CTRL_CTS:
guy91f7cb22003-07-22 17:36:57 +00002065 return CTRL_CTS_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002066 case CTRL_ACK:
guy91f7cb22003-07-22 17:36:57 +00002067 return CTRL_ACK_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002068 case CTRL_CF_END:
guy91f7cb22003-07-22 17:36:57 +00002069 return CTRL_END_HDRLEN;
itojun7025d462001-06-15 07:39:43 +00002070 case CTRL_END_ACK:
guy91f7cb22003-07-22 17:36:57 +00002071 return CTRL_END_ACK_HDRLEN;
guy15b5a0a2001-06-12 05:17:16 +00002072 default:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002073 ND_PRINT("unknown 802.11 ctrl frame subtype (%u)", FC_SUBTYPE(fc));
guyd8add7c2003-07-22 17:35:04 +00002074 return 0;
itojun7025d462001-06-15 07:39:43 +00002075 }
itojun7025d462001-06-15 07:39:43 +00002076 case T_DATA:
guy45b4f192007-07-22 22:00:40 +00002077 len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
2078 if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
2079 len += 2;
2080 return len;
itojun7025d462001-06-15 07:39:43 +00002081 default:
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002082 ND_PRINT("unknown 802.11 frame type (%u)", FC_TYPE(fc));
guyd8add7c2003-07-22 17:35:04 +00002083 return 0;
guy15b5a0a2001-06-12 05:17:16 +00002084 }
guy15b5a0a2001-06-12 05:17:16 +00002085}
2086
Guy Harrisaae14f92009-07-14 18:23:06 -07002087static int
Francois-Xavier Le Bail1af20c32018-06-15 15:44:51 +02002088extract_mesh_header_length(netdissect_options *ndo, const u_char *p)
Guy Harrisaae14f92009-07-14 18:23:06 -07002089{
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02002090 return (GET_U_1(p) &~ 3) ? 0 : 6*(1 + (GET_U_1(p) & 3));
Guy Harrisaae14f92009-07-14 18:23:06 -07002091}
2092
guy15b5a0a2001-06-12 05:17:16 +00002093/*
Guy Harris1ac906f2015-04-15 19:44:34 -07002094 * Print the 802.11 MAC header.
guy15b5a0a2001-06-12 05:17:16 +00002095 */
Guy Harrisaae14f92009-07-14 18:23:06 -07002096static void
Denis Ovsienko26498832014-03-31 16:46:12 +04002097ieee_802_11_hdr_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002098 uint16_t fc, const u_char *p, u_int hdrlen,
2099 u_int meshdrlen)
guy15b5a0a2001-06-12 05:17:16 +00002100{
Denis Ovsienko26498832014-03-31 16:46:12 +04002101 if (ndo->ndo_vflag) {
guyf72f67a2003-02-04 05:53:21 +00002102 if (FC_MORE_DATA(fc))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002103 ND_PRINT("More Data ");
guyf72f67a2003-02-04 05:53:21 +00002104 if (FC_MORE_FLAG(fc))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002105 ND_PRINT("More Fragments ");
guyf72f67a2003-02-04 05:53:21 +00002106 if (FC_POWER_MGMT(fc))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002107 ND_PRINT("Pwr Mgmt ");
guyf72f67a2003-02-04 05:53:21 +00002108 if (FC_RETRY(fc))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002109 ND_PRINT("Retry ");
guyf72f67a2003-02-04 05:53:21 +00002110 if (FC_ORDER(fc))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002111 ND_PRINT("Strictly Ordered ");
Guy Harris8275fd82015-04-15 20:11:41 -07002112 if (FC_PROTECTED(fc))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002113 ND_PRINT("Protected ");
guy91f7cb22003-07-22 17:36:57 +00002114 if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002115 ND_PRINT("%uus ",
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02002116 GET_LE_U_2(((const struct mgmt_header_t *)p)->duration));
guyf72f67a2003-02-04 05:53:21 +00002117 }
Guy Harrisaae14f92009-07-14 18:23:06 -07002118 if (meshdrlen != 0) {
2119 const struct meshcntl_t *mc =
Francois-Xavier Le Baile44bc942017-12-10 15:17:06 +01002120 (const struct meshcntl_t *)(p + hdrlen - meshdrlen);
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02002121 u_int ae = GET_U_1(mc->flags) & 3;
Guy Harrisaae14f92009-07-14 18:23:06 -07002122
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002123 ND_PRINT("MeshData (AE %u TTL %u seq %u", ae,
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02002124 GET_U_1(mc->ttl), GET_LE_U_4(mc->seq));
Guy Harrisaae14f92009-07-14 18:23:06 -07002125 if (ae > 0)
Guy Harris306c2a02020-01-19 19:55:38 -08002126 ND_PRINT(" A4:%s", GET_ETHERADDR_STRING(mc->addr4));
Guy Harrisaae14f92009-07-14 18:23:06 -07002127 if (ae > 1)
Guy Harris306c2a02020-01-19 19:55:38 -08002128 ND_PRINT(" A5:%s", GET_ETHERADDR_STRING(mc->addr5));
Guy Harrisaae14f92009-07-14 18:23:06 -07002129 if (ae > 2)
Guy Harris306c2a02020-01-19 19:55:38 -08002130 ND_PRINT(" A6:%s", GET_ETHERADDR_STRING(mc->addr6));
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002131 ND_PRINT(") ");
Guy Harrisaae14f92009-07-14 18:23:06 -07002132 }
guyf72f67a2003-02-04 05:53:21 +00002133
guy15b5a0a2001-06-12 05:17:16 +00002134 switch (FC_TYPE(fc)) {
guy15b5a0a2001-06-12 05:17:16 +00002135 case T_MGMT:
Guy Harris1ac906f2015-04-15 19:44:34 -07002136 mgmt_header_print(ndo, p);
guy15b5a0a2001-06-12 05:17:16 +00002137 break;
guy15b5a0a2001-06-12 05:17:16 +00002138 case T_CTRL:
Guy Harris1ac906f2015-04-15 19:44:34 -07002139 ctrl_header_print(ndo, fc, p);
guy15b5a0a2001-06-12 05:17:16 +00002140 break;
guy15b5a0a2001-06-12 05:17:16 +00002141 case T_DATA:
Guy Harris1ac906f2015-04-15 19:44:34 -07002142 data_header_print(ndo, fc, p);
guy15b5a0a2001-06-12 05:17:16 +00002143 break;
guy15b5a0a2001-06-12 05:17:16 +00002144 default:
guy15b5a0a2001-06-12 05:17:16 +00002145 break;
2146 }
2147}
2148
guy4bec97f2002-12-19 09:39:10 +00002149static u_int
Denis Ovsienko26498832014-03-31 16:46:12 +04002150ieee802_11_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002151 const u_char *p, u_int length, u_int orig_caplen, int pad,
2152 u_int fcslen)
guy15b5a0a2001-06-12 05:17:16 +00002153{
Guy Harrised85e202014-04-23 00:20:40 -07002154 uint16_t fc;
Guy Harrisaae14f92009-07-14 18:23:06 -07002155 u_int caplen, hdrlen, meshdrlen;
Guy Harris6bc44292015-07-03 15:54:14 -07002156 struct lladdr_info src, dst;
Guy Harrisbd001162015-04-17 23:42:22 -07002157 int llc_hdrlen;
guy15b5a0a2001-06-12 05:17:16 +00002158
Francois-Xavier Le Bail546558e2018-03-14 16:54:17 +01002159 ndo->ndo_protocol = "802.11";
Guy Harrisf2aee3e2009-01-15 02:35:19 -08002160 caplen = orig_caplen;
2161 /* Remove FCS, if present */
2162 if (length < fcslen) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02002163 nd_print_trunc(ndo);
guy4bec97f2002-12-19 09:39:10 +00002164 return caplen;
guy5585ad82002-12-12 07:39:19 +00002165 }
Guy Harrisf2aee3e2009-01-15 02:35:19 -08002166 length -= fcslen;
2167 if (caplen > length) {
2168 /* Amount of FCS in actual packet data, if any */
2169 fcslen = caplen - length;
2170 caplen -= fcslen;
Denis Ovsienko26498832014-03-31 16:46:12 +04002171 ndo->ndo_snapend -= fcslen;
Guy Harrisf2aee3e2009-01-15 02:35:19 -08002172 }
2173
2174 if (caplen < IEEE802_11_FC_LEN) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02002175 nd_print_trunc(ndo);
Guy Harrisf2aee3e2009-01-15 02:35:19 -08002176 return orig_caplen;
2177 }
guy5585ad82002-12-12 07:39:19 +00002178
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02002179 fc = GET_LE_U_2(p);
Denis Ovsienko26498832014-03-31 16:46:12 +04002180 hdrlen = extract_header_length(ndo, fc);
Guy Harrise4c749f2015-04-15 18:13:53 -07002181 if (hdrlen == 0) {
2182 /* Unknown frame type or control frame subtype; quit. */
2183 return (0);
2184 }
guy4bef1ce2007-07-22 23:13:41 +00002185 if (pad)
2186 hdrlen = roundup2(hdrlen, 4);
Denis Ovsienko26498832014-03-31 16:46:12 +04002187 if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA &&
Guy Harrisfe209f32010-05-27 23:58:01 -07002188 DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
Francois-Xavier Le Bail3f1c4af2018-06-18 21:47:43 +02002189 if(!ND_TTEST_1(p + hdrlen)) {
2190 nd_print_trunc(ndo);
2191 return hdrlen;
2192 }
Francois-Xavier Le Bail1af20c32018-06-15 15:44:51 +02002193 meshdrlen = extract_mesh_header_length(ndo, p + hdrlen);
Guy Harrisaae14f92009-07-14 18:23:06 -07002194 hdrlen += meshdrlen;
2195 } else
2196 meshdrlen = 0;
2197
guyd8add7c2003-07-22 17:35:04 +00002198 if (caplen < hdrlen) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02002199 nd_print_trunc(ndo);
guyd8add7c2003-07-22 17:35:04 +00002200 return hdrlen;
guyc422d3a2002-09-05 21:25:34 +00002201 }
guy15b5a0a2001-06-12 05:17:16 +00002202
Guy Harris1ac906f2015-04-15 19:44:34 -07002203 if (ndo->ndo_eflag)
2204 ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen);
guy15b5a0a2001-06-12 05:17:16 +00002205
2206 /*
guycfabfb02002-12-18 09:41:13 +00002207 * Go past the 802.11 header.
2208 */
guyd8add7c2003-07-22 17:35:04 +00002209 length -= hdrlen;
2210 caplen -= hdrlen;
2211 p += hdrlen;
guy15b5a0a2001-06-12 05:17:16 +00002212
Guy Harris6bc44292015-07-03 15:54:14 -07002213 src.addr_string = etheraddr_string;
2214 dst.addr_string = etheraddr_string;
guy15b5a0a2001-06-12 05:17:16 +00002215 switch (FC_TYPE(fc)) {
guy15b5a0a2001-06-12 05:17:16 +00002216 case T_MGMT:
Guy Harris6bc44292015-07-03 15:54:14 -07002217 get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr);
2218 if (!mgmt_body_print(ndo, fc, src.addr, p, length)) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02002219 nd_print_trunc(ndo);
guyd8add7c2003-07-22 17:35:04 +00002220 return hdrlen;
guy884ae4d2001-06-13 07:25:57 +00002221 }
guy15b5a0a2001-06-12 05:17:16 +00002222 break;
guy15b5a0a2001-06-12 05:17:16 +00002223 case T_CTRL:
Denis Ovsienko26498832014-03-31 16:46:12 +04002224 if (!ctrl_body_print(ndo, fc, p - hdrlen)) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02002225 nd_print_trunc(ndo);
guyd8add7c2003-07-22 17:35:04 +00002226 return hdrlen;
guy884ae4d2001-06-13 07:25:57 +00002227 }
guy15b5a0a2001-06-12 05:17:16 +00002228 break;
guy15b5a0a2001-06-12 05:17:16 +00002229 case T_DATA:
guy7bfcc5e2007-07-22 19:59:06 +00002230 if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
2231 return hdrlen; /* no-data frame */
guy15b5a0a2001-06-12 05:17:16 +00002232 /* There may be a problem w/ AP not having this bit set */
Guy Harris8275fd82015-04-15 20:11:41 -07002233 if (FC_PROTECTED(fc)) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002234 ND_PRINT("Data");
Denis Ovsienko26498832014-03-31 16:46:12 +04002235 if (!wep_print(ndo, p)) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02002236 nd_print_trunc(ndo);
guyd8add7c2003-07-22 17:35:04 +00002237 return hdrlen;
guy884ae4d2001-06-13 07:25:57 +00002238 }
Guy Harris1ac906f2015-04-15 19:44:34 -07002239 } else {
Guy Harris6bc44292015-07-03 15:54:14 -07002240 get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr);
2241 llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
Guy Harrisbd001162015-04-17 23:42:22 -07002242 if (llc_hdrlen < 0) {
Guy Harris1ac906f2015-04-15 19:44:34 -07002243 /*
2244 * Some kinds of LLC packet we cannot
2245 * handle intelligently
2246 */
Guy Harris1ac906f2015-04-15 19:44:34 -07002247 if (!ndo->ndo_suppress_default_print)
2248 ND_DEFAULTPRINT(p, caplen);
Guy Harrisbd001162015-04-17 23:42:22 -07002249 llc_hdrlen = -llc_hdrlen;
Guy Harris1ac906f2015-04-15 19:44:34 -07002250 }
Guy Harrisbd001162015-04-17 23:42:22 -07002251 hdrlen += llc_hdrlen;
guy15b5a0a2001-06-12 05:17:16 +00002252 }
2253 break;
guy15b5a0a2001-06-12 05:17:16 +00002254 default:
Guy Harrise4c749f2015-04-15 18:13:53 -07002255 /* We shouldn't get here - we should already have quit */
guy15b5a0a2001-06-12 05:17:16 +00002256 break;
2257 }
2258
guyd8add7c2003-07-22 17:35:04 +00002259 return hdrlen;
guyc52bf5a2002-12-12 07:28:35 +00002260}
2261
2262/*
2263 * This is the top level routine of the printer. 'p' points
2264 * to the 802.11 header of the packet, 'h->ts' is the timestamp,
guyfb1b6d82004-03-17 23:24:35 +00002265 * 'h->len' is the length of the packet off the wire, and 'h->caplen'
guyc52bf5a2002-12-12 07:28:35 +00002266 * is the number of bytes actually captured.
2267 */
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02002268void
Denis Ovsienko26498832014-03-31 16:46:12 +04002269ieee802_11_if_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002270 const struct pcap_pkthdr *h, const u_char *p)
guyc52bf5a2002-12-12 07:28:35 +00002271{
Francois-Xavier Le Bail4eb7a802020-08-02 11:36:05 +02002272 ndo->ndo_protocol = "802.11";
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02002273 ndo->ndo_ll_hdr_len += ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0);
guyc52bf5a2002-12-12 07:28:35 +00002274}
2275
Guy Harris1d595052015-09-28 16:01:16 -07002276
2277/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
2278/* NetBSD: ieee802_11_radio.h,v 1.2 2006/02/26 03:04:03 dyoung Exp */
2279
2280/*-
2281 * Copyright (c) 2003, 2004 David Young. All rights reserved.
2282 *
2283 * Redistribution and use in source and binary forms, with or without
2284 * modification, are permitted provided that the following conditions
2285 * are met:
2286 * 1. Redistributions of source code must retain the above copyright
2287 * notice, this list of conditions and the following disclaimer.
2288 * 2. Redistributions in binary form must reproduce the above copyright
2289 * notice, this list of conditions and the following disclaimer in the
2290 * documentation and/or other materials provided with the distribution.
2291 * 3. The name of David Young may not be used to endorse or promote
2292 * products derived from this software without specific prior
2293 * written permission.
2294 *
2295 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
2296 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2297 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2298 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
2299 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2300 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2301 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2302 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2303 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2304 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2305 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
2306 * OF SUCH DAMAGE.
2307 */
2308
2309/* A generic radio capture format is desirable. It must be
2310 * rigidly defined (e.g., units for fields should be given),
2311 * and easily extensible.
2312 *
2313 * The following is an extensible radio capture format. It is
2314 * based on a bitmap indicating which fields are present.
2315 *
2316 * I am trying to describe precisely what the application programmer
2317 * should expect in the following, and for that reason I tell the
2318 * units and origin of each measurement (where it applies), or else I
2319 * use sufficiently weaselly language ("is a monotonically nondecreasing
2320 * function of...") that I cannot set false expectations for lawyerly
2321 * readers.
2322 */
2323
2324/*
2325 * The radio capture header precedes the 802.11 header.
2326 *
2327 * Note well: all radiotap fields are little-endian.
2328 */
2329struct ieee80211_radiotap_header {
Guy Harris1eae0262017-12-31 11:12:12 -08002330 nd_uint8_t it_version; /* Version 0. Only increases
Guy Harris1d595052015-09-28 16:01:16 -07002331 * for drastic changes,
2332 * introduction of compatible
2333 * new fields does not count.
2334 */
Guy Harris1eae0262017-12-31 11:12:12 -08002335 nd_uint8_t it_pad;
2336 nd_uint16_t it_len; /* length of the whole
Guy Harris1d595052015-09-28 16:01:16 -07002337 * header in bytes, including
2338 * it_version, it_pad,
2339 * it_len, and data fields.
2340 */
Guy Harris1eae0262017-12-31 11:12:12 -08002341 nd_uint32_t it_present; /* A bitmap telling which
Guy Harris1d595052015-09-28 16:01:16 -07002342 * fields are present. Set bit 31
2343 * (0x80000000) to extend the
2344 * bitmap by another 32 bits.
2345 * Additional extensions are made
2346 * by setting bit 31.
2347 */
2348};
2349
2350/* Name Data type Units
2351 * ---- --------- -----
2352 *
2353 * IEEE80211_RADIOTAP_TSFT uint64_t microseconds
2354 *
2355 * Value in microseconds of the MAC's 64-bit 802.11 Time
2356 * Synchronization Function timer when the first bit of the
2357 * MPDU arrived at the MAC. For received frames, only.
2358 *
2359 * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
2360 *
2361 * Tx/Rx frequency in MHz, followed by flags (see below).
2362 * Note that IEEE80211_RADIOTAP_XCHANNEL must be used to
2363 * represent an HT channel as there is not enough room in
2364 * the flags word.
2365 *
2366 * IEEE80211_RADIOTAP_FHSS uint16_t see below
2367 *
2368 * For frequency-hopping radios, the hop set (first byte)
2369 * and pattern (second byte).
2370 *
2371 * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s or index
2372 *
2373 * Tx/Rx data rate. If bit 0x80 is set then it represents an
2374 * an MCS index and not an IEEE rate.
2375 *
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002376 * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from
2377 * one milliwatt (dBm)
Guy Harris1d595052015-09-28 16:01:16 -07002378 *
2379 * RF signal power at the antenna, decibel difference from
2380 * one milliwatt.
2381 *
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002382 * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from
2383 * one milliwatt (dBm)
Guy Harris1d595052015-09-28 16:01:16 -07002384 *
2385 * RF noise power at the antenna, decibel difference from one
2386 * milliwatt.
2387 *
2388 * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB)
2389 *
2390 * RF signal power at the antenna, decibel difference from an
2391 * arbitrary, fixed reference.
2392 *
2393 * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB)
2394 *
2395 * RF noise power at the antenna, decibel difference from an
2396 * arbitrary, fixed reference point.
2397 *
2398 * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
2399 *
2400 * Quality of Barker code lock. Unitless. Monotonically
2401 * nondecreasing with "better" lock strength. Called "Signal
2402 * Quality" in datasheets. (Is there a standard way to measure
2403 * this?)
2404 *
2405 * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
2406 *
2407 * Transmit power expressed as unitless distance from max
2408 * power set at factory calibration. 0 is max power.
2409 * Monotonically nondecreasing with lower power levels.
2410 *
2411 * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
2412 *
2413 * Transmit power expressed as decibel distance from max power
2414 * set at factory calibration. 0 is max power. Monotonically
2415 * nondecreasing with lower power levels.
2416 *
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002417 * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from
2418 * one milliwatt (dBm)
Guy Harris1d595052015-09-28 16:01:16 -07002419 *
2420 * Transmit power expressed as dBm (decibels from a 1 milliwatt
2421 * reference). This is the absolute power level measured at
2422 * the antenna port.
2423 *
2424 * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap
2425 *
2426 * Properties of transmitted and received frames. See flags
2427 * defined below.
2428 *
2429 * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index
2430 *
2431 * Unitless indication of the Rx/Tx antenna for this packet.
2432 * The first antenna is antenna 0.
2433 *
2434 * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
2435 *
2436 * Properties of received frames. See flags defined below.
2437 *
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002438 * IEEE80211_RADIOTAP_XCHANNEL uint32_t bitmap
2439 * uint16_t MHz
2440 * uint8_t channel number
2441 * uint8_t .5 dBm
Guy Harris1d595052015-09-28 16:01:16 -07002442 *
2443 * Extended channel specification: flags (see below) followed by
2444 * frequency in MHz, the corresponding IEEE channel number, and
2445 * finally the maximum regulatory transmit power cap in .5 dBm
2446 * units. This property supersedes IEEE80211_RADIOTAP_CHANNEL
2447 * and only one of the two should be present.
2448 *
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002449 * IEEE80211_RADIOTAP_MCS uint8_t known
2450 * uint8_t flags
2451 * uint8_t mcs
Guy Harris1d595052015-09-28 16:01:16 -07002452 *
2453 * Bitset indicating which fields have known values, followed
2454 * by bitset of flag values, followed by the MCS rate index as
2455 * in IEEE 802.11n.
2456 *
Guy Harris6e8dc382015-11-01 11:41:26 -08002457 *
2458 * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitless
2459 *
2460 * Contains the AMPDU information for the subframe.
2461 *
2462 * IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16
2463 *
2464 * Contains VHT information about this frame.
2465 *
Guy Harris1d595052015-09-28 16:01:16 -07002466 * IEEE80211_RADIOTAP_VENDOR_NAMESPACE
2467 * uint8_t OUI[3]
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002468 * uint8_t subspace
2469 * uint16_t length
Guy Harris1d595052015-09-28 16:01:16 -07002470 *
2471 * The Vendor Namespace Field contains three sub-fields. The first
2472 * sub-field is 3 bytes long. It contains the vendor's IEEE 802
2473 * Organizationally Unique Identifier (OUI). The fourth byte is a
2474 * vendor-specific "namespace selector."
2475 *
2476 */
2477enum ieee80211_radiotap_type {
2478 IEEE80211_RADIOTAP_TSFT = 0,
2479 IEEE80211_RADIOTAP_FLAGS = 1,
2480 IEEE80211_RADIOTAP_RATE = 2,
2481 IEEE80211_RADIOTAP_CHANNEL = 3,
2482 IEEE80211_RADIOTAP_FHSS = 4,
2483 IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
2484 IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
2485 IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
2486 IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
2487 IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
2488 IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
2489 IEEE80211_RADIOTAP_ANTENNA = 11,
2490 IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
2491 IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
2492 IEEE80211_RADIOTAP_RX_FLAGS = 14,
2493 /* NB: gap for netbsd definitions */
2494 IEEE80211_RADIOTAP_XCHANNEL = 18,
2495 IEEE80211_RADIOTAP_MCS = 19,
Guy Harris6e8dc382015-11-01 11:41:26 -08002496 IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
2497 IEEE80211_RADIOTAP_VHT = 21,
Guy Harris1d595052015-09-28 16:01:16 -07002498 IEEE80211_RADIOTAP_NAMESPACE = 29,
2499 IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
2500 IEEE80211_RADIOTAP_EXT = 31
2501};
2502
2503/* channel attributes */
2504#define IEEE80211_CHAN_TURBO 0x00010 /* Turbo channel */
2505#define IEEE80211_CHAN_CCK 0x00020 /* CCK channel */
2506#define IEEE80211_CHAN_OFDM 0x00040 /* OFDM channel */
2507#define IEEE80211_CHAN_2GHZ 0x00080 /* 2 GHz spectrum channel. */
2508#define IEEE80211_CHAN_5GHZ 0x00100 /* 5 GHz spectrum channel */
2509#define IEEE80211_CHAN_PASSIVE 0x00200 /* Only passive scan allowed */
2510#define IEEE80211_CHAN_DYN 0x00400 /* Dynamic CCK-OFDM channel */
2511#define IEEE80211_CHAN_GFSK 0x00800 /* GFSK channel (FHSS PHY) */
2512#define IEEE80211_CHAN_GSM 0x01000 /* 900 MHz spectrum channel */
2513#define IEEE80211_CHAN_STURBO 0x02000 /* 11a static turbo channel only */
2514#define IEEE80211_CHAN_HALF 0x04000 /* Half rate channel */
2515#define IEEE80211_CHAN_QUARTER 0x08000 /* Quarter rate channel */
2516#define IEEE80211_CHAN_HT20 0x10000 /* HT 20 channel */
2517#define IEEE80211_CHAN_HT40U 0x20000 /* HT 40 channel w/ ext above */
2518#define IEEE80211_CHAN_HT40D 0x40000 /* HT 40 channel w/ ext below */
2519
2520/* Useful combinations of channel characteristics, borrowed from Ethereal */
2521#define IEEE80211_CHAN_A \
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002522 (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
Guy Harris1d595052015-09-28 16:01:16 -07002523#define IEEE80211_CHAN_B \
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002524 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
Guy Harris1d595052015-09-28 16:01:16 -07002525#define IEEE80211_CHAN_G \
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002526 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
Guy Harris1d595052015-09-28 16:01:16 -07002527#define IEEE80211_CHAN_TA \
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002528 (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
Guy Harris1d595052015-09-28 16:01:16 -07002529#define IEEE80211_CHAN_TG \
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002530 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN | IEEE80211_CHAN_TURBO)
Guy Harris1d595052015-09-28 16:01:16 -07002531
2532
2533/* For IEEE80211_RADIOTAP_FLAGS */
2534#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
2535 * during CFP
2536 */
2537#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
2538 * with short
2539 * preamble
2540 */
2541#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
2542 * with WEP encryption
2543 */
2544#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
2545 * with fragmentation
2546 */
2547#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
2548#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
2549 * 802.11 header and payload
2550 * (to 32-bit boundary)
2551 */
2552#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* does not pass FCS check */
2553
2554/* For IEEE80211_RADIOTAP_RX_FLAGS */
2555#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
2556#define IEEE80211_RADIOTAP_F_RX_PLCP_CRC 0x0002 /* frame failed PLCP CRC check */
2557
2558/* For IEEE80211_RADIOTAP_MCS known */
2559#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN 0x01
2560#define IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN 0x02 /* MCS index field */
2561#define IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN 0x04
2562#define IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN 0x08
2563#define IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN 0x10
2564#define IEEE80211_RADIOTAP_MCS_STBC_KNOWN 0x20
Guy Harris6e8dc382015-11-01 11:41:26 -08002565#define IEEE80211_RADIOTAP_MCS_NESS_KNOWN 0x40
2566#define IEEE80211_RADIOTAP_MCS_NESS_BIT_1 0x80
Guy Harris1d595052015-09-28 16:01:16 -07002567
2568/* For IEEE80211_RADIOTAP_MCS flags */
2569#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK 0x03
2570#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20 0
2571#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 1
2572#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20L 2
2573#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20U 3
2574#define IEEE80211_RADIOTAP_MCS_SHORT_GI 0x04 /* short guard interval */
2575#define IEEE80211_RADIOTAP_MCS_HT_GREENFIELD 0x08
2576#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
2577#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60
2578#define IEEE80211_RADIOTAP_MCS_STBC_1 1
2579#define IEEE80211_RADIOTAP_MCS_STBC_2 2
2580#define IEEE80211_RADIOTAP_MCS_STBC_3 3
2581#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
Guy Harris6e8dc382015-11-01 11:41:26 -08002582#define IEEE80211_RADIOTAP_MCS_NESS_BIT_0 0x80
2583
2584/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
2585#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
2586#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
2587#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
2588#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
2589#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
2590#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
2591
2592/* For IEEE80211_RADIOTAP_VHT known */
2593#define IEEE80211_RADIOTAP_VHT_STBC_KNOWN 0x0001
2594#define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA_KNOWN 0x0002
2595#define IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN 0x0004
2596#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_DIS_KNOWN 0x0008
2597#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM_KNOWN 0x0010
2598#define IEEE80211_RADIOTAP_VHT_BEAMFORMED_KNOWN 0x0020
2599#define IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN 0x0040
2600#define IEEE80211_RADIOTAP_VHT_GROUP_ID_KNOWN 0x0080
2601#define IEEE80211_RADIOTAP_VHT_PARTIAL_AID_KNOWN 0x0100
2602
2603/* For IEEE80211_RADIOTAP_VHT flags */
2604#define IEEE80211_RADIOTAP_VHT_STBC 0x01
2605#define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA 0x02
2606#define IEEE80211_RADIOTAP_VHT_SHORT_GI 0x04
2607#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_M10_9 0x08
2608#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM 0x10
2609#define IEEE80211_RADIOTAP_VHT_BEAMFORMED 0x20
2610
2611#define IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK 0x1f
2612
2613#define IEEE80211_RADIOTAP_VHT_NSS_MASK 0x0f
2614#define IEEE80211_RADIOTAP_VHT_MCS_MASK 0xf0
2615#define IEEE80211_RADIOTAP_VHT_MCS_SHIFT 4
2616
2617#define IEEE80211_RADIOTAP_CODING_LDPC_USERn 0x01
2618
Guy Harrisaae14f92009-07-14 18:23:06 -07002619#define IEEE80211_CHAN_FHSS \
2620 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
2621#define IEEE80211_CHAN_A \
2622 (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
2623#define IEEE80211_CHAN_B \
2624 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
2625#define IEEE80211_CHAN_PUREG \
2626 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
2627#define IEEE80211_CHAN_G \
2628 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2629
2630#define IS_CHAN_FHSS(flags) \
2631 ((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
2632#define IS_CHAN_A(flags) \
2633 ((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
2634#define IS_CHAN_B(flags) \
2635 ((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
2636#define IS_CHAN_PUREG(flags) \
2637 ((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
2638#define IS_CHAN_G(flags) \
2639 ((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
2640#define IS_CHAN_ANYG(flags) \
2641 (IS_CHAN_PUREG(flags) || IS_CHAN_G(flags))
2642
2643static void
Denis Ovsienko26498832014-03-31 16:46:12 +04002644print_chaninfo(netdissect_options *ndo,
Francois-Xavier Le Bail52ad9e12020-07-01 10:15:39 +02002645 uint16_t freq, uint32_t flags, uint32_t presentflags)
Guy Harrisaae14f92009-07-14 18:23:06 -07002646{
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002647 ND_PRINT("%u MHz", freq);
Guy Harrisc632b5f2015-09-28 20:09:53 -07002648 if (presentflags & (1 << IEEE80211_RADIOTAP_MCS)) {
Guy Harris1daa1862015-09-28 18:19:31 -07002649 /*
2650 * We have the MCS field, so this is 11n, regardless
2651 * of what the channel flags say.
2652 */
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002653 ND_PRINT(" 11n");
Guy Harris1daa1862015-09-28 18:19:31 -07002654 } else {
2655 if (IS_CHAN_FHSS(flags))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002656 ND_PRINT(" FHSS");
Guy Harris1daa1862015-09-28 18:19:31 -07002657 if (IS_CHAN_A(flags)) {
2658 if (flags & IEEE80211_CHAN_HALF)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002659 ND_PRINT(" 11a/10Mhz");
Guy Harris1daa1862015-09-28 18:19:31 -07002660 else if (flags & IEEE80211_CHAN_QUARTER)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002661 ND_PRINT(" 11a/5Mhz");
Guy Harris1daa1862015-09-28 18:19:31 -07002662 else
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002663 ND_PRINT(" 11a");
Guy Harris1daa1862015-09-28 18:19:31 -07002664 }
2665 if (IS_CHAN_ANYG(flags)) {
2666 if (flags & IEEE80211_CHAN_HALF)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002667 ND_PRINT(" 11g/10Mhz");
Guy Harris1daa1862015-09-28 18:19:31 -07002668 else if (flags & IEEE80211_CHAN_QUARTER)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002669 ND_PRINT(" 11g/5Mhz");
Guy Harris1daa1862015-09-28 18:19:31 -07002670 else
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002671 ND_PRINT(" 11g");
Guy Harris1daa1862015-09-28 18:19:31 -07002672 } else if (IS_CHAN_B(flags))
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002673 ND_PRINT(" 11b");
Guy Harris1daa1862015-09-28 18:19:31 -07002674 if (flags & IEEE80211_CHAN_TURBO)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002675 ND_PRINT(" Turbo");
Guy Harrisaae14f92009-07-14 18:23:06 -07002676 }
Guy Harris1daa1862015-09-28 18:19:31 -07002677 /*
2678 * These apply to 11n.
2679 */
Guy Harrisaae14f92009-07-14 18:23:06 -07002680 if (flags & IEEE80211_CHAN_HT20)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002681 ND_PRINT(" ht/20");
Guy Harrisaae14f92009-07-14 18:23:06 -07002682 else if (flags & IEEE80211_CHAN_HT40D)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002683 ND_PRINT(" ht/40-");
Guy Harrisaae14f92009-07-14 18:23:06 -07002684 else if (flags & IEEE80211_CHAN_HT40U)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002685 ND_PRINT(" ht/40+");
2686 ND_PRINT(" ");
Guy Harrisaae14f92009-07-14 18:23:06 -07002687}
2688
dyoung00511ce2004-09-23 21:57:24 +00002689static int
Denis Ovsienko26498832014-03-31 16:46:12 +04002690print_radiotap_field(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01002691 struct cpack_state *s, uint32_t bit, uint8_t *flagsp,
2692 uint32_t presentflags)
dyoung00511ce2004-09-23 21:57:24 +00002693{
Guy Harris6e8dc382015-11-01 11:41:26 -08002694 u_int i;
dyoung00511ce2004-09-23 21:57:24 +00002695 int rc;
2696
2697 switch (bit) {
Guy Harris91983fa2016-02-12 22:39:24 -08002698
2699 case IEEE80211_RADIOTAP_TSFT: {
2700 uint64_t tsft;
2701
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002702 rc = nd_cpack_uint64(ndo, s, &tsft);
Guy Harris5b08a202011-04-04 21:30:22 -07002703 if (rc != 0)
Guy Harris91983fa2016-02-12 22:39:24 -08002704 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002705 ND_PRINT("%" PRIu64 "us tsft ", tsft);
guy4bef1ce2007-07-22 23:13:41 +00002706 break;
Guy Harris6e8dc382015-11-01 11:41:26 -08002707 }
dyoung00511ce2004-09-23 21:57:24 +00002708
Guy Harris91983fa2016-02-12 22:39:24 -08002709 case IEEE80211_RADIOTAP_FLAGS: {
2710 uint8_t flagsval;
dyoung00511ce2004-09-23 21:57:24 +00002711
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002712 rc = nd_cpack_uint8(ndo, s, &flagsval);
Guy Harris91983fa2016-02-12 22:39:24 -08002713 if (rc != 0)
2714 goto trunc;
2715 *flagsp = flagsval;
2716 if (flagsval & IEEE80211_RADIOTAP_F_CFP)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002717 ND_PRINT("cfp ");
Guy Harris91983fa2016-02-12 22:39:24 -08002718 if (flagsval & IEEE80211_RADIOTAP_F_SHORTPRE)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002719 ND_PRINT("short preamble ");
Guy Harris91983fa2016-02-12 22:39:24 -08002720 if (flagsval & IEEE80211_RADIOTAP_F_WEP)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002721 ND_PRINT("wep ");
Guy Harris91983fa2016-02-12 22:39:24 -08002722 if (flagsval & IEEE80211_RADIOTAP_F_FRAG)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002723 ND_PRINT("fragmented ");
Guy Harris91983fa2016-02-12 22:39:24 -08002724 if (flagsval & IEEE80211_RADIOTAP_F_BADFCS)
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002725 ND_PRINT("bad-fcs ");
dyoung00511ce2004-09-23 21:57:24 +00002726 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002727 }
2728
2729 case IEEE80211_RADIOTAP_RATE: {
2730 uint8_t rate;
2731
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002732 rc = nd_cpack_uint8(ndo, s, &rate);
Guy Harris91983fa2016-02-12 22:39:24 -08002733 if (rc != 0)
2734 goto trunc;
Guy Harris54db1222011-04-27 12:08:27 -07002735 /*
Guy Harris6bfcf8d2011-04-27 15:15:09 -07002736 * XXX On FreeBSD rate & 0x80 means we have an MCS. On
2737 * Linux and AirPcap it does not. (What about
Guy Harris3bc62cd2018-01-08 18:49:50 -08002738 * macOS, NetBSD, OpenBSD, and DragonFly BSD?)
Guy Harris54db1222011-04-27 12:08:27 -07002739 *
Guy Harris6bfcf8d2011-04-27 15:15:09 -07002740 * This is an issue either for proprietary extensions
2741 * to 11a or 11g, which do exist, or for 11n
2742 * implementations that stuff a rate value into
2743 * this field, which also appear to exist.
2744 *
2745 * We currently handle that by assuming that
2746 * if the 0x80 bit is set *and* the remaining
2747 * bits have a value between 0 and 15 it's
2748 * an MCS value, otherwise it's a rate. If
2749 * there are cases where systems that use
2750 * "0x80 + MCS index" for MCS indices > 15,
2751 * or stuff a rate value here between 64 and
2752 * 71.5 Mb/s in here, we'll need a preference
2753 * setting. Such rates do exist, e.g. 11n
2754 * MCS 7 at 20 MHz with a long guard interval.
Guy Harris54db1222011-04-27 12:08:27 -07002755 */
Guy Harris91983fa2016-02-12 22:39:24 -08002756 if (rate >= 0x80 && rate <= 0x8f) {
Guy Harris6bfcf8d2011-04-27 15:15:09 -07002757 /*
2758 * XXX - we don't know the channel width
2759 * or guard interval length, so we can't
2760 * convert this to a data rate.
2761 *
2762 * If you want us to show a data rate,
2763 * use the MCS field, not the Rate field;
2764 * the MCS field includes not only the
2765 * MCS index, it also includes bandwidth
2766 * and guard interval information.
2767 *
2768 * XXX - can we get the channel width
2769 * from XChannel and the guard interval
2770 * information from Flags, at least on
2771 * FreeBSD?
2772 */
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002773 ND_PRINT("MCS %u ", rate & 0x7f);
Guy Harris6bfcf8d2011-04-27 15:15:09 -07002774 } else
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002775 ND_PRINT("%2.1f Mb/s ", .5 * rate);
dyoung00511ce2004-09-23 21:57:24 +00002776 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002777 }
2778
2779 case IEEE80211_RADIOTAP_CHANNEL: {
2780 uint16_t frequency;
2781 uint16_t flags;
2782
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002783 rc = nd_cpack_uint16(ndo, s, &frequency);
Guy Harris91983fa2016-02-12 22:39:24 -08002784 if (rc != 0)
2785 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002786 rc = nd_cpack_uint16(ndo, s, &flags);
Guy Harris91983fa2016-02-12 22:39:24 -08002787 if (rc != 0)
2788 goto trunc;
2789 /*
2790 * If CHANNEL and XCHANNEL are both present, skip
2791 * CHANNEL.
2792 */
2793 if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL))
2794 break;
2795 print_chaninfo(ndo, frequency, flags, presentflags);
dyoung00511ce2004-09-23 21:57:24 +00002796 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002797 }
2798
2799 case IEEE80211_RADIOTAP_FHSS: {
2800 uint8_t hopset;
2801 uint8_t hoppat;
2802
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002803 rc = nd_cpack_uint8(ndo, s, &hopset);
Guy Harris91983fa2016-02-12 22:39:24 -08002804 if (rc != 0)
2805 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002806 rc = nd_cpack_uint8(ndo, s, &hoppat);
Guy Harris91983fa2016-02-12 22:39:24 -08002807 if (rc != 0)
2808 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002809 ND_PRINT("fhset %u fhpat %u ", hopset, hoppat);
dyoung00511ce2004-09-23 21:57:24 +00002810 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002811 }
2812
2813 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: {
2814 int8_t dbm_antsignal;
2815
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002816 rc = nd_cpack_int8(ndo, s, &dbm_antsignal);
Guy Harris91983fa2016-02-12 22:39:24 -08002817 if (rc != 0)
2818 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002819 ND_PRINT("%ddBm signal ", dbm_antsignal);
dyoung00511ce2004-09-23 21:57:24 +00002820 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002821 }
2822
2823 case IEEE80211_RADIOTAP_DBM_ANTNOISE: {
2824 int8_t dbm_antnoise;
2825
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002826 rc = nd_cpack_int8(ndo, s, &dbm_antnoise);
Guy Harris91983fa2016-02-12 22:39:24 -08002827 if (rc != 0)
2828 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002829 ND_PRINT("%ddBm noise ", dbm_antnoise);
dyoung00511ce2004-09-23 21:57:24 +00002830 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002831 }
2832
2833 case IEEE80211_RADIOTAP_LOCK_QUALITY: {
2834 uint16_t lock_quality;
2835
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002836 rc = nd_cpack_uint16(ndo, s, &lock_quality);
Guy Harris91983fa2016-02-12 22:39:24 -08002837 if (rc != 0)
2838 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002839 ND_PRINT("%u sq ", lock_quality);
dyoung00511ce2004-09-23 21:57:24 +00002840 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002841 }
2842
2843 case IEEE80211_RADIOTAP_TX_ATTENUATION: {
Guy Harrisc45bfbe2017-11-23 11:19:38 -08002844 int16_t tx_attenuation;
Guy Harris91983fa2016-02-12 22:39:24 -08002845
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002846 rc = nd_cpack_int16(ndo, s, &tx_attenuation);
Guy Harris91983fa2016-02-12 22:39:24 -08002847 if (rc != 0)
2848 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002849 ND_PRINT("%d tx power ", -tx_attenuation);
dyoung00511ce2004-09-23 21:57:24 +00002850 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002851 }
2852
2853 case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: {
Guy Harrisc45bfbe2017-11-23 11:19:38 -08002854 int8_t db_tx_attenuation;
Guy Harris91983fa2016-02-12 22:39:24 -08002855
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002856 rc = nd_cpack_int8(ndo, s, &db_tx_attenuation);
Guy Harris91983fa2016-02-12 22:39:24 -08002857 if (rc != 0)
2858 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002859 ND_PRINT("%ddB tx attenuation ", -db_tx_attenuation);
dyoung00511ce2004-09-23 21:57:24 +00002860 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002861 }
2862
2863 case IEEE80211_RADIOTAP_DBM_TX_POWER: {
2864 int8_t dbm_tx_power;
2865
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002866 rc = nd_cpack_int8(ndo, s, &dbm_tx_power);
Guy Harris91983fa2016-02-12 22:39:24 -08002867 if (rc != 0)
2868 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002869 ND_PRINT("%ddBm tx power ", dbm_tx_power);
dyoung00511ce2004-09-23 21:57:24 +00002870 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002871 }
2872
2873 case IEEE80211_RADIOTAP_ANTENNA: {
2874 uint8_t antenna;
2875
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002876 rc = nd_cpack_uint8(ndo, s, &antenna);
Guy Harris91983fa2016-02-12 22:39:24 -08002877 if (rc != 0)
2878 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002879 ND_PRINT("antenna %u ", antenna);
dyoung00511ce2004-09-23 21:57:24 +00002880 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002881 }
2882
2883 case IEEE80211_RADIOTAP_DB_ANTSIGNAL: {
2884 uint8_t db_antsignal;
2885
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002886 rc = nd_cpack_uint8(ndo, s, &db_antsignal);
Guy Harris91983fa2016-02-12 22:39:24 -08002887 if (rc != 0)
2888 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002889 ND_PRINT("%udB signal ", db_antsignal);
dyoung00511ce2004-09-23 21:57:24 +00002890 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002891 }
2892
2893 case IEEE80211_RADIOTAP_DB_ANTNOISE: {
2894 uint8_t db_antnoise;
2895
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002896 rc = nd_cpack_uint8(ndo, s, &db_antnoise);
Guy Harris91983fa2016-02-12 22:39:24 -08002897 if (rc != 0)
2898 goto trunc;
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002899 ND_PRINT("%udB noise ", db_antnoise);
dyoung00511ce2004-09-23 21:57:24 +00002900 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002901 }
2902
2903 case IEEE80211_RADIOTAP_RX_FLAGS: {
2904 uint16_t rx_flags;
2905
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002906 rc = nd_cpack_uint16(ndo, s, &rx_flags);
Guy Harris91983fa2016-02-12 22:39:24 -08002907 if (rc != 0)
2908 goto trunc;
Guy Harris54db1222011-04-27 12:08:27 -07002909 /* Do nothing for now */
2910 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002911 }
2912
2913 case IEEE80211_RADIOTAP_XCHANNEL: {
2914 uint32_t flags;
2915 uint16_t frequency;
2916 uint8_t channel;
2917 uint8_t maxpower;
2918
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002919 rc = nd_cpack_uint32(ndo, s, &flags);
Guy Harris91983fa2016-02-12 22:39:24 -08002920 if (rc != 0)
2921 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002922 rc = nd_cpack_uint16(ndo, s, &frequency);
Guy Harris91983fa2016-02-12 22:39:24 -08002923 if (rc != 0)
2924 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002925 rc = nd_cpack_uint8(ndo, s, &channel);
Guy Harris91983fa2016-02-12 22:39:24 -08002926 if (rc != 0)
2927 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002928 rc = nd_cpack_uint8(ndo, s, &maxpower);
Guy Harris91983fa2016-02-12 22:39:24 -08002929 if (rc != 0)
2930 goto trunc;
2931 print_chaninfo(ndo, frequency, flags, presentflags);
Guy Harrisaae14f92009-07-14 18:23:06 -07002932 break;
Guy Harris91983fa2016-02-12 22:39:24 -08002933 }
2934
Guy Harris54db1222011-04-27 12:08:27 -07002935 case IEEE80211_RADIOTAP_MCS: {
Guy Harris91983fa2016-02-12 22:39:24 -08002936 uint8_t known;
2937 uint8_t flags;
2938 uint8_t mcs_index;
Guy Harris6e8dc382015-11-01 11:41:26 -08002939 static const char *ht_bandwidth[4] = {
Guy Harris54db1222011-04-27 12:08:27 -07002940 "20 MHz",
2941 "40 MHz",
2942 "20 MHz (L)",
2943 "20 MHz (U)"
2944 };
2945 float htrate;
2946
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002947 rc = nd_cpack_uint8(ndo, s, &known);
Guy Harris91983fa2016-02-12 22:39:24 -08002948 if (rc != 0)
2949 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002950 rc = nd_cpack_uint8(ndo, s, &flags);
Guy Harris91983fa2016-02-12 22:39:24 -08002951 if (rc != 0)
2952 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01002953 rc = nd_cpack_uint8(ndo, s, &mcs_index);
Guy Harris91983fa2016-02-12 22:39:24 -08002954 if (rc != 0)
2955 goto trunc;
2956 if (known & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) {
Guy Harris54db1222011-04-27 12:08:27 -07002957 /*
2958 * We know the MCS index.
2959 */
Guy Harris91983fa2016-02-12 22:39:24 -08002960 if (mcs_index <= MAX_MCS_INDEX) {
Guy Harris54db1222011-04-27 12:08:27 -07002961 /*
2962 * And it's in-range.
2963 */
Guy Harris91983fa2016-02-12 22:39:24 -08002964 if (known & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) {
Guy Harris54db1222011-04-27 12:08:27 -07002965 /*
2966 * And we know both the bandwidth and
2967 * the guard interval, so we can look
2968 * up the rate.
2969 */
Michael Richardsona97fb2f2014-01-01 21:27:54 -05002970 htrate =
Francois-Xavier Le Bailff1c2092018-01-04 13:26:39 +01002971 ieee80211_float_htrates
2972 [mcs_index]
2973 [((flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)]
Guy Harris91983fa2016-02-12 22:39:24 -08002974 [((flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)];
Guy Harris54db1222011-04-27 12:08:27 -07002975 } else {
2976 /*
2977 * We don't know both the bandwidth
2978 * and the guard interval, so we can
2979 * only report the MCS index.
2980 */
2981 htrate = 0.0;
2982 }
2983 } else {
2984 /*
2985 * The MCS value is out of range.
2986 */
2987 htrate = 0.0;
2988 }
2989 if (htrate != 0.0) {
2990 /*
2991 * We have the rate.
2992 * Print it.
2993 */
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01002994 ND_PRINT("%.1f Mb/s MCS %u ", htrate, mcs_index);
Guy Harris54db1222011-04-27 12:08:27 -07002995 } else {
2996 /*
2997 * We at least have the MCS index.
2998 * Print it.
2999 */
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003000 ND_PRINT("MCS %u ", mcs_index);
Guy Harris54db1222011-04-27 12:08:27 -07003001 }
3002 }
Guy Harris91983fa2016-02-12 22:39:24 -08003003 if (known & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003004 ND_PRINT("%s ",
3005 ht_bandwidth[flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK]);
Guy Harris54db1222011-04-27 12:08:27 -07003006 }
Guy Harris91983fa2016-02-12 22:39:24 -08003007 if (known & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003008 ND_PRINT("%s GI ",
Guy Harris91983fa2016-02-12 22:39:24 -08003009 (flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ?
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003010 "short" : "long");
Guy Harris54db1222011-04-27 12:08:27 -07003011 }
Guy Harris91983fa2016-02-12 22:39:24 -08003012 if (known & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003013 ND_PRINT("%s ",
Guy Harris91983fa2016-02-12 22:39:24 -08003014 (flags & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ?
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003015 "greenfield" : "mixed");
Guy Harris54db1222011-04-27 12:08:27 -07003016 }
Guy Harris91983fa2016-02-12 22:39:24 -08003017 if (known & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003018 ND_PRINT("%s FEC ",
Guy Harris91983fa2016-02-12 22:39:24 -08003019 (flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ?
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003020 "LDPC" : "BCC");
Guy Harris54db1222011-04-27 12:08:27 -07003021 }
Guy Harris91983fa2016-02-12 22:39:24 -08003022 if (known & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003023 ND_PRINT("RX-STBC%u ",
3024 (flags & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT);
Guy Harris91983fa2016-02-12 22:39:24 -08003025 }
3026 break;
Oleksij Rempel35cafed2013-05-03 21:53:56 +02003027 }
3028
Guy Harris91983fa2016-02-12 22:39:24 -08003029 case IEEE80211_RADIOTAP_AMPDU_STATUS: {
3030 uint32_t reference_num;
3031 uint16_t flags;
3032 uint8_t delim_crc;
3033 uint8_t reserved;
3034
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003035 rc = nd_cpack_uint32(ndo, s, &reference_num);
Guy Harris91983fa2016-02-12 22:39:24 -08003036 if (rc != 0)
3037 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003038 rc = nd_cpack_uint16(ndo, s, &flags);
Guy Harris91983fa2016-02-12 22:39:24 -08003039 if (rc != 0)
3040 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003041 rc = nd_cpack_uint8(ndo, s, &delim_crc);
Guy Harris91983fa2016-02-12 22:39:24 -08003042 if (rc != 0)
3043 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003044 rc = nd_cpack_uint8(ndo, s, &reserved);
Guy Harris91983fa2016-02-12 22:39:24 -08003045 if (rc != 0)
3046 goto trunc;
3047 /* Do nothing for now */
Guy Harris54db1222011-04-27 12:08:27 -07003048 break;
3049 }
Guy Harris91983fa2016-02-12 22:39:24 -08003050
Guy Harris6e8dc382015-11-01 11:41:26 -08003051 case IEEE80211_RADIOTAP_VHT: {
Guy Harris91983fa2016-02-12 22:39:24 -08003052 uint16_t known;
3053 uint8_t flags;
3054 uint8_t bandwidth;
3055 uint8_t mcs_nss[4];
3056 uint8_t coding;
3057 uint8_t group_id;
3058 uint16_t partial_aid;
Guy Harris6e8dc382015-11-01 11:41:26 -08003059 static const char *vht_bandwidth[32] = {
3060 "20 MHz",
3061 "40 MHz",
3062 "20 MHz (L)",
3063 "20 MHz (U)",
3064 "80 MHz",
3065 "80 MHz (L)",
3066 "80 MHz (U)",
3067 "80 MHz (LL)",
3068 "80 MHz (LU)",
3069 "80 MHz (UL)",
3070 "80 MHz (UU)",
3071 "160 MHz",
3072 "160 MHz (L)",
3073 "160 MHz (U)",
3074 "160 MHz (LL)",
3075 "160 MHz (LU)",
3076 "160 MHz (UL)",
3077 "160 MHz (UU)",
3078 "160 MHz (LLL)",
3079 "160 MHz (LLU)",
3080 "160 MHz (LUL)",
3081 "160 MHz (UUU)",
3082 "160 MHz (ULL)",
3083 "160 MHz (ULU)",
3084 "160 MHz (UUL)",
Guy Harris23d1a762015-11-01 13:27:32 -08003085 "160 MHz (UUU)",
Guy Harris6e8dc382015-11-01 11:41:26 -08003086 "unknown (26)",
3087 "unknown (27)",
3088 "unknown (28)",
3089 "unknown (29)",
3090 "unknown (30)",
3091 "unknown (31)"
3092 };
3093
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003094 rc = nd_cpack_uint16(ndo, s, &known);
Guy Harris91983fa2016-02-12 22:39:24 -08003095 if (rc != 0)
3096 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003097 rc = nd_cpack_uint8(ndo, s, &flags);
Guy Harris91983fa2016-02-12 22:39:24 -08003098 if (rc != 0)
3099 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003100 rc = nd_cpack_uint8(ndo, s, &bandwidth);
Guy Harris91983fa2016-02-12 22:39:24 -08003101 if (rc != 0)
3102 goto trunc;
3103 for (i = 0; i < 4; i++) {
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003104 rc = nd_cpack_uint8(ndo, s, &mcs_nss[i]);
Guy Harris91983fa2016-02-12 22:39:24 -08003105 if (rc != 0)
3106 goto trunc;
3107 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003108 rc = nd_cpack_uint8(ndo, s, &coding);
Guy Harris91983fa2016-02-12 22:39:24 -08003109 if (rc != 0)
3110 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003111 rc = nd_cpack_uint8(ndo, s, &group_id);
Guy Harris91983fa2016-02-12 22:39:24 -08003112 if (rc != 0)
3113 goto trunc;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003114 rc = nd_cpack_uint16(ndo, s, &partial_aid);
Guy Harris91983fa2016-02-12 22:39:24 -08003115 if (rc != 0)
3116 goto trunc;
Guy Harris6e8dc382015-11-01 11:41:26 -08003117 for (i = 0; i < 4; i++) {
3118 u_int nss, mcs;
3119 nss = mcs_nss[i] & IEEE80211_RADIOTAP_VHT_NSS_MASK;
3120 mcs = (mcs_nss[i] & IEEE80211_RADIOTAP_VHT_MCS_MASK) >> IEEE80211_RADIOTAP_VHT_MCS_SHIFT;
3121
3122 if (nss == 0)
3123 continue;
3124
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003125 ND_PRINT("User %u MCS %u ", i, mcs);
3126 ND_PRINT("%s FEC ",
Guy Harris91983fa2016-02-12 22:39:24 -08003127 (coding & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ?
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003128 "LDPC" : "BCC");
Guy Harris6e8dc382015-11-01 11:41:26 -08003129 }
Guy Harris91983fa2016-02-12 22:39:24 -08003130 if (known & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003131 ND_PRINT("%s ",
3132 vht_bandwidth[bandwidth & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK]);
Guy Harris6e8dc382015-11-01 11:41:26 -08003133 }
Guy Harris91983fa2016-02-12 22:39:24 -08003134 if (known & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) {
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003135 ND_PRINT("%s GI ",
Guy Harris91983fa2016-02-12 22:39:24 -08003136 (flags & IEEE80211_RADIOTAP_VHT_SHORT_GI) ?
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003137 "short" : "long");
Guy Harris6e8dc382015-11-01 11:41:26 -08003138 }
3139 break;
3140 }
Guy Harris91983fa2016-02-12 22:39:24 -08003141
3142 default:
3143 /* this bit indicates a field whose
3144 * size we do not know, so we cannot
3145 * proceed. Just print the bit number.
3146 */
Francois-Xavier Le Baile2982e72018-01-07 11:47:30 +01003147 ND_PRINT("[bit %u] ", bit);
Guy Harris91983fa2016-02-12 22:39:24 -08003148 return -1;
dyoung00511ce2004-09-23 21:57:24 +00003149 }
Guy Harris91983fa2016-02-12 22:39:24 -08003150
dyoung00511ce2004-09-23 21:57:24 +00003151 return 0;
Guy Harris91983fa2016-02-12 22:39:24 -08003152
3153trunc:
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003154 nd_print_trunc(ndo);
Guy Harris91983fa2016-02-12 22:39:24 -08003155 return rc;
dyoung00511ce2004-09-23 21:57:24 +00003156}
3157
Guy Harrisea1182b2016-01-11 15:47:31 -08003158
3159static int
3160print_in_radiotap_namespace(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01003161 struct cpack_state *s, uint8_t *flags,
3162 uint32_t presentflags, int bit0)
guy46c77e72002-12-17 09:13:45 +00003163{
dyoung00511ce2004-09-23 21:57:24 +00003164#define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
3165#define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
3166#define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
3167#define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
3168#define BITNO_2(x) (((x) & 2) ? 1 : 0)
Guy Harrisea1182b2016-01-11 15:47:31 -08003169 uint32_t present, next_present;
3170 int bitno;
3171 enum ieee80211_radiotap_type bit;
3172 int rc;
3173
3174 for (present = presentflags; present; present = next_present) {
3175 /*
3176 * Clear the least significant bit that is set.
3177 */
3178 next_present = present & (present - 1);
3179
3180 /*
3181 * Get the bit number, within this presence word,
3182 * of the remaining least significant bit that
3183 * is set.
3184 */
3185 bitno = BITNO_32(present ^ next_present);
3186
3187 /*
3188 * Stop if this is one of the "same meaning
3189 * in all presence flags" bits.
3190 */
3191 if (bitno >= IEEE80211_RADIOTAP_NAMESPACE)
3192 break;
3193
3194 /*
3195 * Get the radiotap bit number of that bit.
3196 */
3197 bit = (enum ieee80211_radiotap_type)(bit0 + bitno);
3198
3199 rc = print_radiotap_field(ndo, s, bit, flags, presentflags);
3200 if (rc != 0)
3201 return rc;
3202 }
3203
3204 return 0;
3205}
3206
Guy Harris83e419c2018-11-12 22:03:49 -08003207u_int
Guy Harrisea1182b2016-01-11 15:47:31 -08003208ieee802_11_radio_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01003209 const u_char *p, u_int length, u_int caplen)
Guy Harrisea1182b2016-01-11 15:47:31 -08003210{
Guy Harrisab73c1d2009-06-28 10:58:16 -07003211#define BIT(n) (1U << n)
dyoung00511ce2004-09-23 21:57:24 +00003212#define IS_EXTENDED(__p) \
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02003213 (GET_LE_U_4(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
dyoung00511ce2004-09-23 21:57:24 +00003214
3215 struct cpack_state cpacker;
Guy Harris69cb46a2015-04-26 17:24:42 -07003216 const struct ieee80211_radiotap_header *hdr;
Guy Harrisea1182b2016-01-11 15:47:31 -08003217 uint32_t presentflags;
Guy Harris1eae0262017-12-31 11:12:12 -08003218 const nd_uint32_t *presentp, *last_presentp;
Guy Harrisea1182b2016-01-11 15:47:31 -08003219 int vendor_namespace;
3220 uint8_t vendor_oui[3];
3221 uint8_t vendor_subnamespace;
3222 uint16_t skip_length;
dyoung00511ce2004-09-23 21:57:24 +00003223 int bit0;
dyoung00511ce2004-09-23 21:57:24 +00003224 u_int len;
Guy Harrised85e202014-04-23 00:20:40 -07003225 uint8_t flags;
Guy Harris68fcda92009-05-21 10:50:08 -07003226 int pad;
3227 u_int fcslen;
dyoung00511ce2004-09-23 21:57:24 +00003228
Francois-Xavier Le Bail546558e2018-03-14 16:54:17 +01003229 ndo->ndo_protocol = "802.11_radio";
dyoung00511ce2004-09-23 21:57:24 +00003230 if (caplen < sizeof(*hdr)) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003231 nd_print_trunc(ndo);
dyoung00511ce2004-09-23 21:57:24 +00003232 return caplen;
3233 }
3234
Guy Harris69cb46a2015-04-26 17:24:42 -07003235 hdr = (const struct ieee80211_radiotap_header *)p;
dyoung00511ce2004-09-23 21:57:24 +00003236
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02003237 len = GET_LE_U_2(hdr->it_len);
Guy Harriscf99f0b2018-08-08 13:41:44 -07003238 if (len < sizeof(*hdr)) {
3239 /*
3240 * The length is the length of the entire header, so
3241 * it must be as large as the fixed-length part of
3242 * the header.
3243 */
3244 nd_print_trunc(ndo);
3245 return caplen;
3246 }
dyoung00511ce2004-09-23 21:57:24 +00003247
Guy Harrisda946bd2015-07-03 16:01:36 -07003248 /*
3249 * If we don't have the entire radiotap header, just give up.
3250 */
dyoung00511ce2004-09-23 21:57:24 +00003251 if (caplen < len) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003252 nd_print_trunc(ndo);
dyoung00511ce2004-09-23 21:57:24 +00003253 return caplen;
3254 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003255 nd_cpack_init(&cpacker, (const uint8_t *)hdr, len); /* align against header start */
3256 nd_cpack_advance(&cpacker, sizeof(*hdr)); /* includes the 1st bitmap */
dyoung00511ce2004-09-23 21:57:24 +00003257 for (last_presentp = &hdr->it_present;
Guy Harrisda946bd2015-07-03 16:01:36 -07003258 (const u_char*)(last_presentp + 1) <= p + len &&
3259 IS_EXTENDED(last_presentp);
Denis Ovsienkob766ec92013-04-28 17:20:28 +04003260 last_presentp++)
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003261 nd_cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */
dyoung00511ce2004-09-23 21:57:24 +00003262
3263 /* are there more bitmap extensions than bytes in header? */
Guy Harrisda946bd2015-07-03 16:01:36 -07003264 if ((const u_char*)(last_presentp + 1) > p + len) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003265 nd_print_trunc(ndo);
dyoung00511ce2004-09-23 21:57:24 +00003266 return caplen;
3267 }
3268
Guy Harrisea1182b2016-01-11 15:47:31 -08003269 /*
3270 * Start out at the beginning of the default radiotap namespace.
3271 */
3272 bit0 = 0;
3273 vendor_namespace = 0;
3274 memset(vendor_oui, 0, 3);
3275 vendor_subnamespace = 0;
3276 skip_length = 0;
Guy Harrisf2aee3e2009-01-15 02:35:19 -08003277 /* Assume no flags */
3278 flags = 0;
guy4bef1ce2007-07-22 23:13:41 +00003279 /* Assume no Atheros padding between 802.11 header and body */
3280 pad = 0;
Guy Harrisf2aee3e2009-01-15 02:35:19 -08003281 /* Assume no FCS at end of frame */
3282 fcslen = 0;
Guy Harrisea1182b2016-01-11 15:47:31 -08003283 for (presentp = &hdr->it_present; presentp <= last_presentp;
3284 presentp++) {
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02003285 presentflags = GET_LE_U_4(presentp);
Guy Harris54db1222011-04-27 12:08:27 -07003286
Guy Harrisea1182b2016-01-11 15:47:31 -08003287 /*
3288 * If this is a vendor namespace, we don't handle it.
3289 */
3290 if (vendor_namespace) {
3291 /*
3292 * Skip past the stuff we don't understand.
3293 * If we add support for any vendor namespaces,
3294 * it'd be added here; use vendor_oui and
3295 * vendor_subnamespace to interpret the fields.
3296 */
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003297 if (nd_cpack_advance(&cpacker, skip_length) != 0) {
Guy Harrisea1182b2016-01-11 15:47:31 -08003298 /*
3299 * Ran out of space in the packet.
3300 */
3301 break;
3302 }
Guy Harris54db1222011-04-27 12:08:27 -07003303
Guy Harrisea1182b2016-01-11 15:47:31 -08003304 /*
3305 * We've skipped it all; nothing more to
3306 * skip.
3307 */
3308 skip_length = 0;
3309 } else {
3310 if (print_in_radiotap_namespace(ndo, &cpacker,
3311 &flags, presentflags, bit0) != 0) {
3312 /*
3313 * Fatal error - can't process anything
3314 * more in the radiotap header.
3315 */
3316 break;
3317 }
3318 }
dyoung00511ce2004-09-23 21:57:24 +00003319
Guy Harrisea1182b2016-01-11 15:47:31 -08003320 /*
3321 * Handle the namespace switch bits; we've already handled
3322 * the extension bit in all but the last word above.
3323 */
3324 switch (presentflags &
3325 (BIT(IEEE80211_RADIOTAP_NAMESPACE)|BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE))) {
dyoung00511ce2004-09-23 21:57:24 +00003326
Guy Harrisea1182b2016-01-11 15:47:31 -08003327 case 0:
3328 /*
3329 * We're not changing namespaces.
3330 * advance to the next 32 bits in the current
3331 * namespace.
3332 */
3333 bit0 += 32;
3334 break;
3335
3336 case BIT(IEEE80211_RADIOTAP_NAMESPACE):
3337 /*
3338 * We're switching to the radiotap namespace.
3339 * Reset the presence-bitmap index to 0, and
3340 * reset the namespace to the default radiotap
3341 * namespace.
3342 */
3343 bit0 = 0;
3344 vendor_namespace = 0;
3345 memset(vendor_oui, 0, 3);
3346 vendor_subnamespace = 0;
3347 skip_length = 0;
3348 break;
3349
3350 case BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE):
3351 /*
3352 * We're switching to a vendor namespace.
3353 * Reset the presence-bitmap index to 0,
3354 * note that we're in a vendor namespace,
3355 * and fetch the fields of the Vendor Namespace
3356 * item.
3357 */
3358 bit0 = 0;
3359 vendor_namespace = 1;
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003360 if ((nd_cpack_align_and_reserve(&cpacker, 2)) == NULL) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003361 nd_print_trunc(ndo);
Guy Harrisea1182b2016-01-11 15:47:31 -08003362 break;
3363 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003364 if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[0]) != 0) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003365 nd_print_trunc(ndo);
Guy Harrisea1182b2016-01-11 15:47:31 -08003366 break;
3367 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003368 if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[1]) != 0) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003369 nd_print_trunc(ndo);
Guy Harrisea1182b2016-01-11 15:47:31 -08003370 break;
3371 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003372 if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[2]) != 0) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003373 nd_print_trunc(ndo);
Guy Harrisea1182b2016-01-11 15:47:31 -08003374 break;
3375 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003376 if (nd_cpack_uint8(ndo, &cpacker, &vendor_subnamespace) != 0) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003377 nd_print_trunc(ndo);
Guy Harrisea1182b2016-01-11 15:47:31 -08003378 break;
3379 }
Denis Ovsienko7810dd32020-09-30 19:15:42 +01003380 if (nd_cpack_uint16(ndo, &cpacker, &skip_length) != 0) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003381 nd_print_trunc(ndo);
Guy Harrisea1182b2016-01-11 15:47:31 -08003382 break;
3383 }
3384 break;
3385
3386 default:
3387 /*
3388 * Illegal combination. The behavior in this
3389 * case is undefined by the radiotap spec; we
3390 * just ignore both bits.
3391 */
3392 break;
dyoung00511ce2004-09-23 21:57:24 +00003393 }
3394 }
Guy Harrisf2aee3e2009-01-15 02:35:19 -08003395
3396 if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
3397 pad = 1; /* Atheros padding */
3398 if (flags & IEEE80211_RADIOTAP_F_FCS)
3399 fcslen = 4; /* FCS at end of packet */
Denis Ovsienko26498832014-03-31 16:46:12 +04003400 return len + ieee802_11_print(ndo, p + len, length - len, caplen - len, pad,
Guy Harrisf2aee3e2009-01-15 02:35:19 -08003401 fcslen);
dyoung00511ce2004-09-23 21:57:24 +00003402#undef BITNO_32
3403#undef BITNO_16
3404#undef BITNO_8
3405#undef BITNO_4
3406#undef BITNO_2
3407#undef BIT
3408}
3409
3410static u_int
Francois-Xavier Le Bail75397ef2018-03-14 18:36:23 +01003411ieee802_11_radio_avs_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01003412 const u_char *p, u_int length, u_int caplen)
dyoung00511ce2004-09-23 21:57:24 +00003413{
Guy Harrised85e202014-04-23 00:20:40 -07003414 uint32_t caphdr_len;
guy46c77e72002-12-17 09:13:45 +00003415
Francois-Xavier Le Bail546558e2018-03-14 16:54:17 +01003416 ndo->ndo_protocol = "802.11_radio_avs";
guyefb80782007-12-20 08:13:35 +00003417 if (caplen < 8) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003418 nd_print_trunc(ndo);
guyefb80782007-12-20 08:13:35 +00003419 return caplen;
3420 }
3421
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02003422 caphdr_len = GET_BE_U_4(p + 4);
guy46c77e72002-12-17 09:13:45 +00003423 if (caphdr_len < 8) {
3424 /*
3425 * Yow! The capture header length is claimed not
3426 * to be large enough to include even the version
3427 * cookie or capture header length!
3428 */
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003429 nd_print_trunc(ndo);
guy4bec97f2002-12-19 09:39:10 +00003430 return caplen;
guy46c77e72002-12-17 09:13:45 +00003431 }
3432
3433 if (caplen < caphdr_len) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003434 nd_print_trunc(ndo);
guy4bec97f2002-12-19 09:39:10 +00003435 return caplen;
guy46c77e72002-12-17 09:13:45 +00003436 }
3437
Denis Ovsienko26498832014-03-31 16:46:12 +04003438 return caphdr_len + ieee802_11_print(ndo, p + caphdr_len,
Guy Harrisf2aee3e2009-01-15 02:35:19 -08003439 length - caphdr_len, caplen - caphdr_len, 0, 0);
guy46c77e72002-12-17 09:13:45 +00003440}
3441
3442#define PRISM_HDR_LEN 144
3443
guy9f7024c2007-12-29 23:25:02 +00003444#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
guy46c77e72002-12-17 09:13:45 +00003445#define WLANCAP_MAGIC_COOKIE_V1 0x80211001
guy9f7024c2007-12-29 23:25:02 +00003446#define WLANCAP_MAGIC_COOKIE_V2 0x80211002
guyc52bf5a2002-12-12 07:28:35 +00003447
3448/*
3449 * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
3450 * containing information such as radio information, which we
3451 * currently ignore.
guy46c77e72002-12-17 09:13:45 +00003452 *
guy9f7024c2007-12-29 23:25:02 +00003453 * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or
3454 * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS
3455 * (currently, on Linux, there's no ARPHRD_ type for
3456 * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM
3457 * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for
3458 * the AVS header, and the first 4 bytes of the header are used to
3459 * indicate whether it's a Prism header or an AVS header).
guyc52bf5a2002-12-12 07:28:35 +00003460 */
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003461void
Denis Ovsienko26498832014-03-31 16:46:12 +04003462prism_if_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01003463 const struct pcap_pkthdr *h, const u_char *p)
guyc52bf5a2002-12-12 07:28:35 +00003464{
3465 u_int caplen = h->caplen;
3466 u_int length = h->len;
Guy Harrised85e202014-04-23 00:20:40 -07003467 uint32_t msgcode;
guyc52bf5a2002-12-12 07:28:35 +00003468
Francois-Xavier Le Bail4eb7a802020-08-02 11:36:05 +02003469 ndo->ndo_protocol = "prism";
guy46c77e72002-12-17 09:13:45 +00003470 if (caplen < 4) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003471 nd_print_trunc(ndo);
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003472 ndo->ndo_ll_hdr_len += caplen;
3473 return;
guyc52bf5a2002-12-12 07:28:35 +00003474 }
3475
Francois-Xavier Le Bailee68aa32018-06-16 17:23:21 +02003476 msgcode = GET_BE_U_4(p);
guy9f7024c2007-12-29 23:25:02 +00003477 if (msgcode == WLANCAP_MAGIC_COOKIE_V1 ||
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003478 msgcode == WLANCAP_MAGIC_COOKIE_V2) {
3479 ndo->ndo_ll_hdr_len += ieee802_11_radio_avs_print(ndo, p, length, caplen);
3480 return;
3481 }
guy46c77e72002-12-17 09:13:45 +00003482
guyd8add7c2003-07-22 17:35:04 +00003483 if (caplen < PRISM_HDR_LEN) {
Francois-Xavier Le Bailba8936b2018-05-02 17:15:04 +02003484 nd_print_trunc(ndo);
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003485 ndo->ndo_ll_hdr_len += caplen;
3486 return;
guy46c77e72002-12-17 09:13:45 +00003487 }
guyd8add7c2003-07-22 17:35:04 +00003488
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003489 p += PRISM_HDR_LEN;
3490 length -= PRISM_HDR_LEN;
3491 caplen -= PRISM_HDR_LEN;
Francois-Xavier Le Bail627051e2020-08-02 10:48:50 +02003492 ndo->ndo_ll_hdr_len += PRISM_HDR_LEN;
3493 ndo->ndo_ll_hdr_len += ieee802_11_print(ndo, p, length, caplen, 0, 0);
guyc52bf5a2002-12-12 07:28:35 +00003494}
3495
guyc52bf5a2002-12-12 07:28:35 +00003496/*
3497 * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra
guyefb80782007-12-20 08:13:35 +00003498 * header, containing information such as radio information.
guyc52bf5a2002-12-12 07:28:35 +00003499 */
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003500void
Denis Ovsienko26498832014-03-31 16:46:12 +04003501ieee802_11_radio_if_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01003502 const struct pcap_pkthdr *h, const u_char *p)
guyc52bf5a2002-12-12 07:28:35 +00003503{
Francois-Xavier Le Bail4eb7a802020-08-02 11:36:05 +02003504 ndo->ndo_protocol = "802.11_radio";
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003505 ndo->ndo_ll_hdr_len += ieee802_11_radio_print(ndo, p, h->len, h->caplen);
guyefb80782007-12-20 08:13:35 +00003506}
guyc52bf5a2002-12-12 07:28:35 +00003507
guyefb80782007-12-20 08:13:35 +00003508/*
3509 * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an
3510 * extra header, containing information such as radio information,
3511 * which we currently ignore.
3512 */
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003513void
Denis Ovsienko26498832014-03-31 16:46:12 +04003514ieee802_11_radio_avs_if_print(netdissect_options *ndo,
Francois-Xavier Le Bail6d855c72019-02-24 09:44:14 +01003515 const struct pcap_pkthdr *h, const u_char *p)
guyefb80782007-12-20 08:13:35 +00003516{
Francois-Xavier Le Bail4eb7a802020-08-02 11:36:05 +02003517 ndo->ndo_protocol = "802.11_radio_avs";
Francois-Xavier Le Baildc8a38c2020-08-02 09:46:30 +02003518 ndo->ndo_ll_hdr_len += ieee802_11_radio_avs_print(ndo, p, h->len, h->caplen);
guy15b5a0a2001-06-12 05:17:16 +00003519}