xref: /aosp_15_r20/external/tcpdump/print-802_11.c (revision 05b00f6010a2396e3db2409989fc67270046269f)
1*05b00f60SXin Li /*
2*05b00f60SXin Li  * Copyright (c) 2001
3*05b00f60SXin Li  *	Fortress Technologies, Inc.  All rights reserved.
4*05b00f60SXin Li  *      Charlie Lenahan ([email protected])
5*05b00f60SXin Li  *
6*05b00f60SXin Li  * Redistribution and use in source and binary forms, with or without
7*05b00f60SXin Li  * modification, are permitted provided that: (1) source code distributions
8*05b00f60SXin Li  * retain the above copyright notice and this paragraph in its entirety, (2)
9*05b00f60SXin Li  * distributions including binary code include the above copyright notice and
10*05b00f60SXin Li  * this paragraph in its entirety in the documentation or other materials
11*05b00f60SXin Li  * provided with the distribution, and (3) all advertising materials mentioning
12*05b00f60SXin Li  * features or use of this software display the following acknowledgement:
13*05b00f60SXin Li  * ``This product includes software developed by the University of California,
14*05b00f60SXin Li  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15*05b00f60SXin Li  * the University nor the names of its contributors may be used to endorse
16*05b00f60SXin Li  * or promote products derived from this software without specific prior
17*05b00f60SXin Li  * written permission.
18*05b00f60SXin Li  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19*05b00f60SXin Li  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20*05b00f60SXin Li  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21*05b00f60SXin Li  */
22*05b00f60SXin Li 
23*05b00f60SXin Li /* \summary: IEEE 802.11 printer */
24*05b00f60SXin Li 
25*05b00f60SXin Li #ifdef HAVE_CONFIG_H
26*05b00f60SXin Li #include <config.h>
27*05b00f60SXin Li #endif
28*05b00f60SXin Li 
29*05b00f60SXin Li #include "netdissect-stdinc.h"
30*05b00f60SXin Li 
31*05b00f60SXin Li #include <string.h>
32*05b00f60SXin Li 
33*05b00f60SXin Li #include "netdissect.h"
34*05b00f60SXin Li #include "addrtoname.h"
35*05b00f60SXin Li 
36*05b00f60SXin Li #include "extract.h"
37*05b00f60SXin Li 
38*05b00f60SXin Li #include "cpack.h"
39*05b00f60SXin Li 
40*05b00f60SXin Li 
41*05b00f60SXin Li /* Lengths of 802.11 header components. */
42*05b00f60SXin Li #define	IEEE802_11_FC_LEN		2
43*05b00f60SXin Li #define	IEEE802_11_DUR_LEN		2
44*05b00f60SXin Li #define	IEEE802_11_DA_LEN		6
45*05b00f60SXin Li #define	IEEE802_11_SA_LEN		6
46*05b00f60SXin Li #define	IEEE802_11_BSSID_LEN		6
47*05b00f60SXin Li #define	IEEE802_11_RA_LEN		6
48*05b00f60SXin Li #define	IEEE802_11_TA_LEN		6
49*05b00f60SXin Li #define	IEEE802_11_ADDR1_LEN		6
50*05b00f60SXin Li #define	IEEE802_11_SEQ_LEN		2
51*05b00f60SXin Li #define	IEEE802_11_CTL_LEN		2
52*05b00f60SXin Li #define	IEEE802_11_CARRIED_FC_LEN	2
53*05b00f60SXin Li #define	IEEE802_11_HT_CONTROL_LEN	4
54*05b00f60SXin Li #define	IEEE802_11_IV_LEN		3
55*05b00f60SXin Li #define	IEEE802_11_KID_LEN		1
56*05b00f60SXin Li 
57*05b00f60SXin Li /* Frame check sequence length. */
58*05b00f60SXin Li #define	IEEE802_11_FCS_LEN		4
59*05b00f60SXin Li 
60*05b00f60SXin Li /* Lengths of beacon components. */
61*05b00f60SXin Li #define	IEEE802_11_TSTAMP_LEN		8
62*05b00f60SXin Li #define	IEEE802_11_BCNINT_LEN		2
63*05b00f60SXin Li #define	IEEE802_11_CAPINFO_LEN		2
64*05b00f60SXin Li #define	IEEE802_11_LISTENINT_LEN	2
65*05b00f60SXin Li 
66*05b00f60SXin Li #define	IEEE802_11_AID_LEN		2
67*05b00f60SXin Li #define	IEEE802_11_STATUS_LEN		2
68*05b00f60SXin Li #define	IEEE802_11_REASON_LEN		2
69*05b00f60SXin Li 
70*05b00f60SXin Li /* Length of previous AP in reassocation frame */
71*05b00f60SXin Li #define	IEEE802_11_AP_LEN		6
72*05b00f60SXin Li 
73*05b00f60SXin Li #define	T_MGMT 0x0  /* management */
74*05b00f60SXin Li #define	T_CTRL 0x1  /* control */
75*05b00f60SXin Li #define	T_DATA 0x2 /* data */
76*05b00f60SXin Li #define	T_RESV 0x3  /* reserved */
77*05b00f60SXin Li 
78*05b00f60SXin Li #define	ST_ASSOC_REQUEST	0x0
79*05b00f60SXin Li #define	ST_ASSOC_RESPONSE	0x1
80*05b00f60SXin Li #define	ST_REASSOC_REQUEST	0x2
81*05b00f60SXin Li #define	ST_REASSOC_RESPONSE	0x3
82*05b00f60SXin Li #define	ST_PROBE_REQUEST	0x4
83*05b00f60SXin Li #define	ST_PROBE_RESPONSE	0x5
84*05b00f60SXin Li /* RESERVED			0x6  */
85*05b00f60SXin Li /* RESERVED			0x7  */
86*05b00f60SXin Li #define	ST_BEACON		0x8
87*05b00f60SXin Li #define	ST_ATIM			0x9
88*05b00f60SXin Li #define	ST_DISASSOC		0xA
89*05b00f60SXin Li #define	ST_AUTH			0xB
90*05b00f60SXin Li #define	ST_DEAUTH		0xC
91*05b00f60SXin Li #define	ST_ACTION		0xD
92*05b00f60SXin Li /* RESERVED			0xE  */
93*05b00f60SXin Li /* RESERVED			0xF  */
94*05b00f60SXin Li 
95*05b00f60SXin Li static const struct tok st_str[] = {
96*05b00f60SXin Li 	{ ST_ASSOC_REQUEST,    "Assoc Request"    },
97*05b00f60SXin Li 	{ ST_ASSOC_RESPONSE,   "Assoc Response"   },
98*05b00f60SXin Li 	{ ST_REASSOC_REQUEST,  "ReAssoc Request"  },
99*05b00f60SXin Li 	{ ST_REASSOC_RESPONSE, "ReAssoc Response" },
100*05b00f60SXin Li 	{ ST_PROBE_REQUEST,    "Probe Request"    },
101*05b00f60SXin Li 	{ ST_PROBE_RESPONSE,   "Probe Response"   },
102*05b00f60SXin Li 	{ ST_BEACON,           "Beacon"           },
103*05b00f60SXin Li 	{ ST_ATIM,             "ATIM"             },
104*05b00f60SXin Li 	{ ST_DISASSOC,         "Disassociation"   },
105*05b00f60SXin Li 	{ ST_AUTH,             "Authentication"   },
106*05b00f60SXin Li 	{ ST_DEAUTH,           "DeAuthentication" },
107*05b00f60SXin Li 	{ ST_ACTION,           "Action"           },
108*05b00f60SXin Li 	{ 0, NULL }
109*05b00f60SXin Li };
110*05b00f60SXin Li 
111*05b00f60SXin Li #define CTRL_CONTROL_WRAPPER	0x7
112*05b00f60SXin Li #define	CTRL_BAR	0x8
113*05b00f60SXin Li #define	CTRL_BA		0x9
114*05b00f60SXin Li #define	CTRL_PS_POLL	0xA
115*05b00f60SXin Li #define	CTRL_RTS	0xB
116*05b00f60SXin Li #define	CTRL_CTS	0xC
117*05b00f60SXin Li #define	CTRL_ACK	0xD
118*05b00f60SXin Li #define	CTRL_CF_END	0xE
119*05b00f60SXin Li #define	CTRL_END_ACK	0xF
120*05b00f60SXin Li 
121*05b00f60SXin Li static const struct tok ctrl_str[] = {
122*05b00f60SXin Li 	{ CTRL_CONTROL_WRAPPER, "Control Wrapper" },
123*05b00f60SXin Li 	{ CTRL_BAR,             "BAR"             },
124*05b00f60SXin Li 	{ CTRL_BA,              "BA"              },
125*05b00f60SXin Li 	{ CTRL_PS_POLL,         "Power Save-Poll" },
126*05b00f60SXin Li 	{ CTRL_RTS,             "Request-To-Send" },
127*05b00f60SXin Li 	{ CTRL_CTS,             "Clear-To-Send"   },
128*05b00f60SXin Li 	{ CTRL_ACK,             "Acknowledgment"  },
129*05b00f60SXin Li 	{ CTRL_CF_END,          "CF-End"          },
130*05b00f60SXin Li 	{ CTRL_END_ACK,         "CF-End+CF-Ack"   },
131*05b00f60SXin Li 	{ 0, NULL }
132*05b00f60SXin Li };
133*05b00f60SXin Li 
134*05b00f60SXin Li #define	DATA_DATA			0x0
135*05b00f60SXin Li #define	DATA_DATA_CF_ACK		0x1
136*05b00f60SXin Li #define	DATA_DATA_CF_POLL		0x2
137*05b00f60SXin Li #define	DATA_DATA_CF_ACK_POLL		0x3
138*05b00f60SXin Li #define	DATA_NODATA			0x4
139*05b00f60SXin Li #define	DATA_NODATA_CF_ACK		0x5
140*05b00f60SXin Li #define	DATA_NODATA_CF_POLL		0x6
141*05b00f60SXin Li #define	DATA_NODATA_CF_ACK_POLL		0x7
142*05b00f60SXin Li 
143*05b00f60SXin Li #define DATA_QOS_DATA			0x8
144*05b00f60SXin Li #define DATA_QOS_DATA_CF_ACK		0x9
145*05b00f60SXin Li #define DATA_QOS_DATA_CF_POLL		0xA
146*05b00f60SXin Li #define DATA_QOS_DATA_CF_ACK_POLL	0xB
147*05b00f60SXin Li #define DATA_QOS_NODATA			0xC
148*05b00f60SXin Li #define DATA_QOS_CF_POLL_NODATA		0xE
149*05b00f60SXin Li #define DATA_QOS_CF_ACK_POLL_NODATA	0xF
150*05b00f60SXin Li 
151*05b00f60SXin Li /*
152*05b00f60SXin Li  * The subtype field of a data frame is, in effect, composed of 4 flag
153*05b00f60SXin Li  * bits - CF-Ack, CF-Poll, Null (means the frame doesn't actually have
154*05b00f60SXin Li  * any data), and QoS.
155*05b00f60SXin Li  */
156*05b00f60SXin Li #define DATA_FRAME_IS_CF_ACK(x)		((x) & 0x01)
157*05b00f60SXin Li #define DATA_FRAME_IS_CF_POLL(x)	((x) & 0x02)
158*05b00f60SXin Li #define DATA_FRAME_IS_NULL(x)		((x) & 0x04)
159*05b00f60SXin Li #define DATA_FRAME_IS_QOS(x)		((x) & 0x08)
160*05b00f60SXin Li 
161*05b00f60SXin Li /*
162*05b00f60SXin Li  * Bits in the frame control field.
163*05b00f60SXin Li  */
164*05b00f60SXin Li #define	FC_VERSION(fc)		((fc) & 0x3)
165*05b00f60SXin Li #define	FC_TYPE(fc)		(((fc) >> 2) & 0x3)
166*05b00f60SXin Li #define	FC_SUBTYPE(fc)		(((fc) >> 4) & 0xF)
167*05b00f60SXin Li #define	FC_TO_DS(fc)		((fc) & 0x0100)
168*05b00f60SXin Li #define	FC_FROM_DS(fc)		((fc) & 0x0200)
169*05b00f60SXin Li #define	FC_MORE_FLAG(fc)	((fc) & 0x0400)
170*05b00f60SXin Li #define	FC_RETRY(fc)		((fc) & 0x0800)
171*05b00f60SXin Li #define	FC_POWER_MGMT(fc)	((fc) & 0x1000)
172*05b00f60SXin Li #define	FC_MORE_DATA(fc)	((fc) & 0x2000)
173*05b00f60SXin Li #define	FC_PROTECTED(fc)	((fc) & 0x4000)
174*05b00f60SXin Li #define	FC_ORDER(fc)		((fc) & 0x8000)
175*05b00f60SXin Li 
176*05b00f60SXin Li struct mgmt_header_t {
177*05b00f60SXin Li 	nd_uint16_t	fc;
178*05b00f60SXin Li 	nd_uint16_t	duration;
179*05b00f60SXin Li 	nd_mac_addr	da;
180*05b00f60SXin Li 	nd_mac_addr	sa;
181*05b00f60SXin Li 	nd_mac_addr	bssid;
182*05b00f60SXin Li 	nd_uint16_t	seq_ctrl;
183*05b00f60SXin Li };
184*05b00f60SXin Li 
185*05b00f60SXin Li #define	MGMT_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
186*05b00f60SXin Li 			 IEEE802_11_DA_LEN+IEEE802_11_SA_LEN+\
187*05b00f60SXin Li 			 IEEE802_11_BSSID_LEN+IEEE802_11_SEQ_LEN)
188*05b00f60SXin Li 
189*05b00f60SXin Li #define	CAPABILITY_ESS(cap)	((cap) & 0x0001)
190*05b00f60SXin Li #define	CAPABILITY_IBSS(cap)	((cap) & 0x0002)
191*05b00f60SXin Li #define	CAPABILITY_CFP(cap)	((cap) & 0x0004)
192*05b00f60SXin Li #define	CAPABILITY_CFP_REQ(cap)	((cap) & 0x0008)
193*05b00f60SXin Li #define	CAPABILITY_PRIVACY(cap)	((cap) & 0x0010)
194*05b00f60SXin Li 
195*05b00f60SXin Li struct ssid_t {
196*05b00f60SXin Li 	uint8_t		element_id;
197*05b00f60SXin Li 	uint8_t		length;
198*05b00f60SXin Li 	u_char		ssid[33];  /* 32 + 1 for null */
199*05b00f60SXin Li };
200*05b00f60SXin Li 
201*05b00f60SXin Li struct rates_t {
202*05b00f60SXin Li 	uint8_t		element_id;
203*05b00f60SXin Li 	uint8_t		length;
204*05b00f60SXin Li 	uint8_t		rate[16];
205*05b00f60SXin Li };
206*05b00f60SXin Li 
207*05b00f60SXin Li struct challenge_t {
208*05b00f60SXin Li 	uint8_t		element_id;
209*05b00f60SXin Li 	uint8_t		length;
210*05b00f60SXin Li 	uint8_t		text[254]; /* 1-253 + 1 for null */
211*05b00f60SXin Li };
212*05b00f60SXin Li 
213*05b00f60SXin Li struct fh_t {
214*05b00f60SXin Li 	uint8_t		element_id;
215*05b00f60SXin Li 	uint8_t		length;
216*05b00f60SXin Li 	uint16_t	dwell_time;
217*05b00f60SXin Li 	uint8_t		hop_set;
218*05b00f60SXin Li 	uint8_t	hop_pattern;
219*05b00f60SXin Li 	uint8_t		hop_index;
220*05b00f60SXin Li };
221*05b00f60SXin Li 
222*05b00f60SXin Li struct ds_t {
223*05b00f60SXin Li 	uint8_t		element_id;
224*05b00f60SXin Li 	uint8_t		length;
225*05b00f60SXin Li 	uint8_t		channel;
226*05b00f60SXin Li };
227*05b00f60SXin Li 
228*05b00f60SXin Li struct cf_t {
229*05b00f60SXin Li 	uint8_t		element_id;
230*05b00f60SXin Li 	uint8_t		length;
231*05b00f60SXin Li 	uint8_t		count;
232*05b00f60SXin Li 	uint8_t		period;
233*05b00f60SXin Li 	uint16_t	max_duration;
234*05b00f60SXin Li 	uint16_t	dur_remaining;
235*05b00f60SXin Li };
236*05b00f60SXin Li 
237*05b00f60SXin Li struct tim_t {
238*05b00f60SXin Li 	uint8_t		element_id;
239*05b00f60SXin Li 	uint8_t		length;
240*05b00f60SXin Li 	uint8_t		count;
241*05b00f60SXin Li 	uint8_t		period;
242*05b00f60SXin Li 	uint8_t		bitmap_control;
243*05b00f60SXin Li 	uint8_t		bitmap[251];
244*05b00f60SXin Li };
245*05b00f60SXin Li 
246*05b00f60SXin Li #define	E_SSID		0
247*05b00f60SXin Li #define	E_RATES	1
248*05b00f60SXin Li #define	E_FH		2
249*05b00f60SXin Li #define	E_DS		3
250*05b00f60SXin Li #define	E_CF		4
251*05b00f60SXin Li #define	E_TIM		5
252*05b00f60SXin Li #define	E_IBSS		6
253*05b00f60SXin Li /* reserved		7 */
254*05b00f60SXin Li /* reserved		8 */
255*05b00f60SXin Li /* reserved		9 */
256*05b00f60SXin Li /* reserved		10 */
257*05b00f60SXin Li /* reserved		11 */
258*05b00f60SXin Li /* reserved		12 */
259*05b00f60SXin Li /* reserved		13 */
260*05b00f60SXin Li /* reserved		14 */
261*05b00f60SXin Li /* reserved		15 */
262*05b00f60SXin Li /* reserved		16 */
263*05b00f60SXin Li 
264*05b00f60SXin Li #define	E_CHALLENGE	16
265*05b00f60SXin Li /* reserved		17 */
266*05b00f60SXin Li /* reserved		18 */
267*05b00f60SXin Li /* reserved		19 */
268*05b00f60SXin Li /* reserved		16 */
269*05b00f60SXin Li /* reserved		16 */
270*05b00f60SXin Li 
271*05b00f60SXin Li 
272*05b00f60SXin Li struct mgmt_body_t {
273*05b00f60SXin Li 	uint8_t		timestamp[IEEE802_11_TSTAMP_LEN];
274*05b00f60SXin Li 	uint16_t	beacon_interval;
275*05b00f60SXin Li 	uint16_t	listen_interval;
276*05b00f60SXin Li 	uint16_t	status_code;
277*05b00f60SXin Li 	uint16_t	aid;
278*05b00f60SXin Li 	u_char		ap[IEEE802_11_AP_LEN];
279*05b00f60SXin Li 	uint16_t	reason_code;
280*05b00f60SXin Li 	uint16_t	auth_alg;
281*05b00f60SXin Li 	uint16_t	auth_trans_seq_num;
282*05b00f60SXin Li 	int		challenge_present;
283*05b00f60SXin Li 	struct challenge_t  challenge;
284*05b00f60SXin Li 	uint16_t	capability_info;
285*05b00f60SXin Li 	int		ssid_present;
286*05b00f60SXin Li 	struct ssid_t	ssid;
287*05b00f60SXin Li 	int		rates_present;
288*05b00f60SXin Li 	struct rates_t	rates;
289*05b00f60SXin Li 	int		ds_present;
290*05b00f60SXin Li 	struct ds_t	ds;
291*05b00f60SXin Li 	int		cf_present;
292*05b00f60SXin Li 	struct cf_t	cf;
293*05b00f60SXin Li 	int		fh_present;
294*05b00f60SXin Li 	struct fh_t	fh;
295*05b00f60SXin Li 	int		tim_present;
296*05b00f60SXin Li 	struct tim_t	tim;
297*05b00f60SXin Li };
298*05b00f60SXin Li 
299*05b00f60SXin Li struct ctrl_control_wrapper_hdr_t {
300*05b00f60SXin Li 	nd_uint16_t	fc;
301*05b00f60SXin Li 	nd_uint16_t	duration;
302*05b00f60SXin Li 	nd_mac_addr	addr1;
303*05b00f60SXin Li 	nd_uint16_t	carried_fc[IEEE802_11_CARRIED_FC_LEN];
304*05b00f60SXin Li 	nd_uint16_t	ht_control[IEEE802_11_HT_CONTROL_LEN];
305*05b00f60SXin Li };
306*05b00f60SXin Li 
307*05b00f60SXin Li #define	CTRL_CONTROL_WRAPPER_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
308*05b00f60SXin Li 					 IEEE802_11_ADDR1_LEN+\
309*05b00f60SXin Li 					 IEEE802_11_CARRIED_FC_LEN+\
310*05b00f60SXin Li 					 IEEE802_11_HT_CONTROL_LEN)
311*05b00f60SXin Li 
312*05b00f60SXin Li struct ctrl_rts_hdr_t {
313*05b00f60SXin Li 	nd_uint16_t	fc;
314*05b00f60SXin Li 	nd_uint16_t	duration;
315*05b00f60SXin Li 	nd_mac_addr	ra;
316*05b00f60SXin Li 	nd_mac_addr	ta;
317*05b00f60SXin Li };
318*05b00f60SXin Li 
319*05b00f60SXin Li #define	CTRL_RTS_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
320*05b00f60SXin Li 			 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN)
321*05b00f60SXin Li 
322*05b00f60SXin Li struct ctrl_cts_hdr_t {
323*05b00f60SXin Li 	nd_uint16_t	fc;
324*05b00f60SXin Li 	nd_uint16_t	duration;
325*05b00f60SXin Li 	nd_mac_addr	ra;
326*05b00f60SXin Li };
327*05b00f60SXin Li 
328*05b00f60SXin Li #define	CTRL_CTS_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
329*05b00f60SXin Li 
330*05b00f60SXin Li struct ctrl_ack_hdr_t {
331*05b00f60SXin Li 	nd_uint16_t	fc;
332*05b00f60SXin Li 	nd_uint16_t	duration;
333*05b00f60SXin Li 	nd_mac_addr	ra;
334*05b00f60SXin Li };
335*05b00f60SXin Li 
336*05b00f60SXin Li #define	CTRL_ACK_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
337*05b00f60SXin Li 
338*05b00f60SXin Li struct ctrl_ps_poll_hdr_t {
339*05b00f60SXin Li 	nd_uint16_t	fc;
340*05b00f60SXin Li 	nd_uint16_t	aid;
341*05b00f60SXin Li 	nd_mac_addr	bssid;
342*05b00f60SXin Li 	nd_mac_addr	ta;
343*05b00f60SXin Li };
344*05b00f60SXin Li 
345*05b00f60SXin Li #define	CTRL_PS_POLL_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_AID_LEN+\
346*05b00f60SXin Li 				 IEEE802_11_BSSID_LEN+IEEE802_11_TA_LEN)
347*05b00f60SXin Li 
348*05b00f60SXin Li struct ctrl_end_hdr_t {
349*05b00f60SXin Li 	nd_uint16_t	fc;
350*05b00f60SXin Li 	nd_uint16_t	duration;
351*05b00f60SXin Li 	nd_mac_addr	ra;
352*05b00f60SXin Li 	nd_mac_addr	bssid;
353*05b00f60SXin Li };
354*05b00f60SXin Li 
355*05b00f60SXin Li #define	CTRL_END_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
356*05b00f60SXin Li 			 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
357*05b00f60SXin Li 
358*05b00f60SXin Li struct ctrl_end_ack_hdr_t {
359*05b00f60SXin Li 	nd_uint16_t	fc;
360*05b00f60SXin Li 	nd_uint16_t	duration;
361*05b00f60SXin Li 	nd_mac_addr	ra;
362*05b00f60SXin Li 	nd_mac_addr	bssid;
363*05b00f60SXin Li };
364*05b00f60SXin Li 
365*05b00f60SXin Li #define	CTRL_END_ACK_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
366*05b00f60SXin Li 				 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
367*05b00f60SXin Li 
368*05b00f60SXin Li struct ctrl_ba_hdr_t {
369*05b00f60SXin Li 	nd_uint16_t	fc;
370*05b00f60SXin Li 	nd_uint16_t	duration;
371*05b00f60SXin Li 	nd_mac_addr	ra;
372*05b00f60SXin Li };
373*05b00f60SXin Li 
374*05b00f60SXin Li #define	CTRL_BA_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
375*05b00f60SXin Li 
376*05b00f60SXin Li struct ctrl_bar_hdr_t {
377*05b00f60SXin Li 	nd_uint16_t	fc;
378*05b00f60SXin Li 	nd_uint16_t	dur;
379*05b00f60SXin Li 	nd_mac_addr	ra;
380*05b00f60SXin Li 	nd_mac_addr	ta;
381*05b00f60SXin Li 	nd_uint16_t	ctl;
382*05b00f60SXin Li 	nd_uint16_t	seq;
383*05b00f60SXin Li };
384*05b00f60SXin Li 
385*05b00f60SXin Li #define	CTRL_BAR_HDRLEN		(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
386*05b00f60SXin Li 				 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN+\
387*05b00f60SXin Li 				 IEEE802_11_CTL_LEN+IEEE802_11_SEQ_LEN)
388*05b00f60SXin Li 
389*05b00f60SXin Li struct meshcntl_t {
390*05b00f60SXin Li 	nd_uint8_t	flags;
391*05b00f60SXin Li 	nd_uint8_t	ttl;
392*05b00f60SXin Li 	nd_uint32_t	seq;
393*05b00f60SXin Li 	nd_mac_addr	addr4;
394*05b00f60SXin Li 	nd_mac_addr	addr5;
395*05b00f60SXin Li 	nd_mac_addr	addr6;
396*05b00f60SXin Li };
397*05b00f60SXin Li 
398*05b00f60SXin Li #define	IV_IV(iv)	((iv) & 0xFFFFFF)
399*05b00f60SXin Li #define	IV_PAD(iv)	(((iv) >> 24) & 0x3F)
400*05b00f60SXin Li #define	IV_KEYID(iv)	(((iv) >> 30) & 0x03)
401*05b00f60SXin Li 
402*05b00f60SXin Li #define PRINT_SSID(p) \
403*05b00f60SXin Li 	if (p.ssid_present) { \
404*05b00f60SXin Li 		ND_PRINT(" ("); \
405*05b00f60SXin Li 		fn_print_str(ndo, p.ssid.ssid); \
406*05b00f60SXin Li 		ND_PRINT(")"); \
407*05b00f60SXin Li 	}
408*05b00f60SXin Li 
409*05b00f60SXin Li #define PRINT_RATE(_sep, _r, _suf) \
410*05b00f60SXin Li 	ND_PRINT("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
411*05b00f60SXin Li #define PRINT_RATES(p) \
412*05b00f60SXin Li 	if (p.rates_present) { \
413*05b00f60SXin Li 		int z; \
414*05b00f60SXin Li 		const char *sep = " ["; \
415*05b00f60SXin Li 		for (z = 0; z < p.rates.length ; z++) { \
416*05b00f60SXin Li 			PRINT_RATE(sep, p.rates.rate[z], \
417*05b00f60SXin Li 				(p.rates.rate[z] & 0x80 ? "*" : "")); \
418*05b00f60SXin Li 			sep = " "; \
419*05b00f60SXin Li 		} \
420*05b00f60SXin Li 		if (p.rates.length != 0) \
421*05b00f60SXin Li 			ND_PRINT(" Mbit]"); \
422*05b00f60SXin Li 	}
423*05b00f60SXin Li 
424*05b00f60SXin Li #define PRINT_DS_CHANNEL(p) \
425*05b00f60SXin Li 	if (p.ds_present) \
426*05b00f60SXin Li 		ND_PRINT(" CH: %u", p.ds.channel); \
427*05b00f60SXin Li 	ND_PRINT("%s", \
428*05b00f60SXin Li 	    CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "");
429*05b00f60SXin Li 
430*05b00f60SXin Li #define MAX_MCS_INDEX	76
431*05b00f60SXin Li 
432*05b00f60SXin Li /*
433*05b00f60SXin Li  * Indices are:
434*05b00f60SXin Li  *
435*05b00f60SXin Li  *	the MCS index (0-76);
436*05b00f60SXin Li  *
437*05b00f60SXin Li  *	0 for 20 MHz, 1 for 40 MHz;
438*05b00f60SXin Li  *
439*05b00f60SXin Li  *	0 for a long guard interval, 1 for a short guard interval.
440*05b00f60SXin Li  */
441*05b00f60SXin Li static const float ieee80211_float_htrates[MAX_MCS_INDEX+1][2][2] = {
442*05b00f60SXin Li 	/* MCS  0  */
443*05b00f60SXin Li 	{	/* 20 Mhz */ {    6.5f,		/* SGI */    7.2f, },
444*05b00f60SXin Li 		/* 40 Mhz */ {   13.5f,		/* SGI */   15.0f, },
445*05b00f60SXin Li 	},
446*05b00f60SXin Li 
447*05b00f60SXin Li 	/* MCS  1  */
448*05b00f60SXin Li 	{	/* 20 Mhz */ {   13.0f,		/* SGI */   14.4f, },
449*05b00f60SXin Li 		/* 40 Mhz */ {   27.0f,		/* SGI */   30.0f, },
450*05b00f60SXin Li 	},
451*05b00f60SXin Li 
452*05b00f60SXin Li 	/* MCS  2  */
453*05b00f60SXin Li 	{	/* 20 Mhz */ {   19.5f,		/* SGI */   21.7f, },
454*05b00f60SXin Li 		/* 40 Mhz */ {   40.5f,		/* SGI */   45.0f, },
455*05b00f60SXin Li 	},
456*05b00f60SXin Li 
457*05b00f60SXin Li 	/* MCS  3  */
458*05b00f60SXin Li 	{	/* 20 Mhz */ {   26.0f,		/* SGI */   28.9f, },
459*05b00f60SXin Li 		/* 40 Mhz */ {   54.0f,		/* SGI */   60.0f, },
460*05b00f60SXin Li 	},
461*05b00f60SXin Li 
462*05b00f60SXin Li 	/* MCS  4  */
463*05b00f60SXin Li 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
464*05b00f60SXin Li 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
465*05b00f60SXin Li 	},
466*05b00f60SXin Li 
467*05b00f60SXin Li 	/* MCS  5  */
468*05b00f60SXin Li 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
469*05b00f60SXin Li 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
470*05b00f60SXin Li 	},
471*05b00f60SXin Li 
472*05b00f60SXin Li 	/* MCS  6  */
473*05b00f60SXin Li 	{	/* 20 Mhz */ {   58.5f,		/* SGI */   65.0f, },
474*05b00f60SXin Li 		/* 40 Mhz */ {  121.5f,		/* SGI */  135.0f, },
475*05b00f60SXin Li 	},
476*05b00f60SXin Li 
477*05b00f60SXin Li 	/* MCS  7  */
478*05b00f60SXin Li 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
479*05b00f60SXin Li 		/* 40 Mhz */ {   135.0f,	/* SGI */  150.0f, },
480*05b00f60SXin Li 	},
481*05b00f60SXin Li 
482*05b00f60SXin Li 	/* MCS  8  */
483*05b00f60SXin Li 	{	/* 20 Mhz */ {   13.0f,		/* SGI */   14.4f, },
484*05b00f60SXin Li 		/* 40 Mhz */ {   27.0f,		/* SGI */   30.0f, },
485*05b00f60SXin Li 	},
486*05b00f60SXin Li 
487*05b00f60SXin Li 	/* MCS  9  */
488*05b00f60SXin Li 	{	/* 20 Mhz */ {   26.0f,		/* SGI */   28.9f, },
489*05b00f60SXin Li 		/* 40 Mhz */ {   54.0f,		/* SGI */   60.0f, },
490*05b00f60SXin Li 	},
491*05b00f60SXin Li 
492*05b00f60SXin Li 	/* MCS 10  */
493*05b00f60SXin Li 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
494*05b00f60SXin Li 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
495*05b00f60SXin Li 	},
496*05b00f60SXin Li 
497*05b00f60SXin Li 	/* MCS 11  */
498*05b00f60SXin Li 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
499*05b00f60SXin Li 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
500*05b00f60SXin Li 	},
501*05b00f60SXin Li 
502*05b00f60SXin Li 	/* MCS 12  */
503*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
504*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
505*05b00f60SXin Li 	},
506*05b00f60SXin Li 
507*05b00f60SXin Li 	/* MCS 13  */
508*05b00f60SXin Li 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
509*05b00f60SXin Li 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
510*05b00f60SXin Li 	},
511*05b00f60SXin Li 
512*05b00f60SXin Li 	/* MCS 14  */
513*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
514*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
515*05b00f60SXin Li 	},
516*05b00f60SXin Li 
517*05b00f60SXin Li 	/* MCS 15  */
518*05b00f60SXin Li 	{	/* 20 Mhz */ {  130.0f,		/* SGI */  144.4f, },
519*05b00f60SXin Li 		/* 40 Mhz */ {  270.0f,		/* SGI */  300.0f, },
520*05b00f60SXin Li 	},
521*05b00f60SXin Li 
522*05b00f60SXin Li 	/* MCS 16  */
523*05b00f60SXin Li 	{	/* 20 Mhz */ {   19.5f,		/* SGI */   21.7f, },
524*05b00f60SXin Li 		/* 40 Mhz */ {   40.5f,		/* SGI */   45.0f, },
525*05b00f60SXin Li 	},
526*05b00f60SXin Li 
527*05b00f60SXin Li 	/* MCS 17  */
528*05b00f60SXin Li 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
529*05b00f60SXin Li 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
530*05b00f60SXin Li 	},
531*05b00f60SXin Li 
532*05b00f60SXin Li 	/* MCS 18  */
533*05b00f60SXin Li 	{	/* 20 Mhz */ {   58.5f,		/* SGI */   65.0f, },
534*05b00f60SXin Li 		/* 40 Mhz */ {  121.5f,		/* SGI */  135.0f, },
535*05b00f60SXin Li 	},
536*05b00f60SXin Li 
537*05b00f60SXin Li 	/* MCS 19  */
538*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
539*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
540*05b00f60SXin Li 	},
541*05b00f60SXin Li 
542*05b00f60SXin Li 	/* MCS 20  */
543*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
544*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
545*05b00f60SXin Li 	},
546*05b00f60SXin Li 
547*05b00f60SXin Li 	/* MCS 21  */
548*05b00f60SXin Li 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
549*05b00f60SXin Li 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
550*05b00f60SXin Li 	},
551*05b00f60SXin Li 
552*05b00f60SXin Li 	/* MCS 22  */
553*05b00f60SXin Li 	{	/* 20 Mhz */ {  175.5f,		/* SGI */  195.0f, },
554*05b00f60SXin Li 		/* 40 Mhz */ {  364.5f,		/* SGI */  405.0f, },
555*05b00f60SXin Li 	},
556*05b00f60SXin Li 
557*05b00f60SXin Li 	/* MCS 23  */
558*05b00f60SXin Li 	{	/* 20 Mhz */ {  195.0f,		/* SGI */  216.7f, },
559*05b00f60SXin Li 		/* 40 Mhz */ {  405.0f,		/* SGI */  450.0f, },
560*05b00f60SXin Li 	},
561*05b00f60SXin Li 
562*05b00f60SXin Li 	/* MCS 24  */
563*05b00f60SXin Li 	{	/* 20 Mhz */ {   26.0f,		/* SGI */   28.9f, },
564*05b00f60SXin Li 		/* 40 Mhz */ {   54.0f,		/* SGI */   60.0f, },
565*05b00f60SXin Li 	},
566*05b00f60SXin Li 
567*05b00f60SXin Li 	/* MCS 25  */
568*05b00f60SXin Li 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
569*05b00f60SXin Li 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
570*05b00f60SXin Li 	},
571*05b00f60SXin Li 
572*05b00f60SXin Li 	/* MCS 26  */
573*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
574*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
575*05b00f60SXin Li 	},
576*05b00f60SXin Li 
577*05b00f60SXin Li 	/* MCS 27  */
578*05b00f60SXin Li 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
579*05b00f60SXin Li 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
580*05b00f60SXin Li 	},
581*05b00f60SXin Li 
582*05b00f60SXin Li 	/* MCS 28  */
583*05b00f60SXin Li 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
584*05b00f60SXin Li 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
585*05b00f60SXin Li 	},
586*05b00f60SXin Li 
587*05b00f60SXin Li 	/* MCS 29  */
588*05b00f60SXin Li 	{	/* 20 Mhz */ {  208.0f,		/* SGI */  231.1f, },
589*05b00f60SXin Li 		/* 40 Mhz */ {  432.0f,		/* SGI */  480.0f, },
590*05b00f60SXin Li 	},
591*05b00f60SXin Li 
592*05b00f60SXin Li 	/* MCS 30  */
593*05b00f60SXin Li 	{	/* 20 Mhz */ {  234.0f,		/* SGI */  260.0f, },
594*05b00f60SXin Li 		/* 40 Mhz */ {  486.0f,		/* SGI */  540.0f, },
595*05b00f60SXin Li 	},
596*05b00f60SXin Li 
597*05b00f60SXin Li 	/* MCS 31  */
598*05b00f60SXin Li 	{	/* 20 Mhz */ {  260.0f,		/* SGI */  288.9f, },
599*05b00f60SXin Li 		/* 40 Mhz */ {  540.0f,		/* SGI */  600.0f, },
600*05b00f60SXin Li 	},
601*05b00f60SXin Li 
602*05b00f60SXin Li 	/* MCS 32  */
603*05b00f60SXin Li 	{	/* 20 Mhz */ {    0.0f,		/* SGI */    0.0f, }, /* not valid */
604*05b00f60SXin Li 		/* 40 Mhz */ {    6.0f,		/* SGI */    6.7f, },
605*05b00f60SXin Li 	},
606*05b00f60SXin Li 
607*05b00f60SXin Li 	/* MCS 33  */
608*05b00f60SXin Li 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
609*05b00f60SXin Li 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
610*05b00f60SXin Li 	},
611*05b00f60SXin Li 
612*05b00f60SXin Li 	/* MCS 34  */
613*05b00f60SXin Li 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
614*05b00f60SXin Li 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
615*05b00f60SXin Li 	},
616*05b00f60SXin Li 
617*05b00f60SXin Li 	/* MCS 35  */
618*05b00f60SXin Li 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
619*05b00f60SXin Li 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
620*05b00f60SXin Li 	},
621*05b00f60SXin Li 
622*05b00f60SXin Li 	/* MCS 36  */
623*05b00f60SXin Li 	{	/* 20 Mhz */ {   58.5f,		/* SGI */   65.0f, },
624*05b00f60SXin Li 		/* 40 Mhz */ {  121.5f,		/* SGI */  135.0f, },
625*05b00f60SXin Li 	},
626*05b00f60SXin Li 
627*05b00f60SXin Li 	/* MCS 37  */
628*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
629*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
630*05b00f60SXin Li 	},
631*05b00f60SXin Li 
632*05b00f60SXin Li 	/* MCS 38  */
633*05b00f60SXin Li 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
634*05b00f60SXin Li 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
635*05b00f60SXin Li 	},
636*05b00f60SXin Li 
637*05b00f60SXin Li 	/* MCS 39  */
638*05b00f60SXin Li 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
639*05b00f60SXin Li 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
640*05b00f60SXin Li 	},
641*05b00f60SXin Li 
642*05b00f60SXin Li 	/* MCS 40  */
643*05b00f60SXin Li 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
644*05b00f60SXin Li 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
645*05b00f60SXin Li 	},
646*05b00f60SXin Li 
647*05b00f60SXin Li 	/* MCS 41  */
648*05b00f60SXin Li 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
649*05b00f60SXin Li 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
650*05b00f60SXin Li 	},
651*05b00f60SXin Li 
652*05b00f60SXin Li 	/* MCS 42  */
653*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
654*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
655*05b00f60SXin Li 	},
656*05b00f60SXin Li 
657*05b00f60SXin Li 	/* MCS 43  */
658*05b00f60SXin Li 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
659*05b00f60SXin Li 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
660*05b00f60SXin Li 	},
661*05b00f60SXin Li 
662*05b00f60SXin Li 	/* MCS 44  */
663*05b00f60SXin Li 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
664*05b00f60SXin Li 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
665*05b00f60SXin Li 	},
666*05b00f60SXin Li 
667*05b00f60SXin Li 	/* MCS 45  */
668*05b00f60SXin Li 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
669*05b00f60SXin Li 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
670*05b00f60SXin Li 	},
671*05b00f60SXin Li 
672*05b00f60SXin Li 	/* MCS 46  */
673*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
674*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
675*05b00f60SXin Li 	},
676*05b00f60SXin Li 
677*05b00f60SXin Li 	/* MCS 47  */
678*05b00f60SXin Li 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
679*05b00f60SXin Li 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
680*05b00f60SXin Li 	},
681*05b00f60SXin Li 
682*05b00f60SXin Li 	/* MCS 48  */
683*05b00f60SXin Li 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
684*05b00f60SXin Li 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
685*05b00f60SXin Li 	},
686*05b00f60SXin Li 
687*05b00f60SXin Li 	/* MCS 49  */
688*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
689*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
690*05b00f60SXin Li 	},
691*05b00f60SXin Li 
692*05b00f60SXin Li 	/* MCS 50  */
693*05b00f60SXin Li 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
694*05b00f60SXin Li 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
695*05b00f60SXin Li 	},
696*05b00f60SXin Li 
697*05b00f60SXin Li 	/* MCS 51  */
698*05b00f60SXin Li 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
699*05b00f60SXin Li 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
700*05b00f60SXin Li 	},
701*05b00f60SXin Li 
702*05b00f60SXin Li 	/* MCS 52  */
703*05b00f60SXin Li 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
704*05b00f60SXin Li 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
705*05b00f60SXin Li 	},
706*05b00f60SXin Li 
707*05b00f60SXin Li 	/* MCS 53  */
708*05b00f60SXin Li 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
709*05b00f60SXin Li 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
710*05b00f60SXin Li 	},
711*05b00f60SXin Li 
712*05b00f60SXin Li 	/* MCS 54  */
713*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
714*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
715*05b00f60SXin Li 	},
716*05b00f60SXin Li 
717*05b00f60SXin Li 	/* MCS 55  */
718*05b00f60SXin Li 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
719*05b00f60SXin Li 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
720*05b00f60SXin Li 	},
721*05b00f60SXin Li 
722*05b00f60SXin Li 	/* MCS 56  */
723*05b00f60SXin Li 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
724*05b00f60SXin Li 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
725*05b00f60SXin Li 	},
726*05b00f60SXin Li 
727*05b00f60SXin Li 	/* MCS 57  */
728*05b00f60SXin Li 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
729*05b00f60SXin Li 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
730*05b00f60SXin Li 	},
731*05b00f60SXin Li 
732*05b00f60SXin Li 	/* MCS 58  */
733*05b00f60SXin Li 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
734*05b00f60SXin Li 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
735*05b00f60SXin Li 	},
736*05b00f60SXin Li 
737*05b00f60SXin Li 	/* MCS 59  */
738*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
739*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
740*05b00f60SXin Li 	},
741*05b00f60SXin Li 
742*05b00f60SXin Li 	/* MCS 60  */
743*05b00f60SXin Li 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
744*05b00f60SXin Li 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
745*05b00f60SXin Li 	},
746*05b00f60SXin Li 
747*05b00f60SXin Li 	/* MCS 61  */
748*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
749*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
750*05b00f60SXin Li 	},
751*05b00f60SXin Li 
752*05b00f60SXin Li 	/* MCS 62  */
753*05b00f60SXin Li 	{	/* 20 Mhz */ {  130.0f,		/* SGI */  144.4f, },
754*05b00f60SXin Li 		/* 40 Mhz */ {  270.0f,		/* SGI */  300.0f, },
755*05b00f60SXin Li 	},
756*05b00f60SXin Li 
757*05b00f60SXin Li 	/* MCS 63  */
758*05b00f60SXin Li 	{	/* 20 Mhz */ {  130.0f,		/* SGI */  144.4f, },
759*05b00f60SXin Li 		/* 40 Mhz */ {  270.0f,		/* SGI */  300.0f, },
760*05b00f60SXin Li 	},
761*05b00f60SXin Li 
762*05b00f60SXin Li 	/* MCS 64  */
763*05b00f60SXin Li 	{	/* 20 Mhz */ {  143.0f,		/* SGI */  158.9f, },
764*05b00f60SXin Li 		/* 40 Mhz */ {  297.0f,		/* SGI */  330.0f, },
765*05b00f60SXin Li 	},
766*05b00f60SXin Li 
767*05b00f60SXin Li 	/* MCS 65  */
768*05b00f60SXin Li 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
769*05b00f60SXin Li 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
770*05b00f60SXin Li 	},
771*05b00f60SXin Li 
772*05b00f60SXin Li 	/* MCS 66  */
773*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
774*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
775*05b00f60SXin Li 	},
776*05b00f60SXin Li 
777*05b00f60SXin Li 	/* MCS 67  */
778*05b00f60SXin Li 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
779*05b00f60SXin Li 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
780*05b00f60SXin Li 	},
781*05b00f60SXin Li 
782*05b00f60SXin Li 	/* MCS 68  */
783*05b00f60SXin Li 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
784*05b00f60SXin Li 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
785*05b00f60SXin Li 	},
786*05b00f60SXin Li 
787*05b00f60SXin Li 	/* MCS 69  */
788*05b00f60SXin Li 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
789*05b00f60SXin Li 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
790*05b00f60SXin Li 	},
791*05b00f60SXin Li 
792*05b00f60SXin Li 	/* MCS 70  */
793*05b00f60SXin Li 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
794*05b00f60SXin Li 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
795*05b00f60SXin Li 	},
796*05b00f60SXin Li 
797*05b00f60SXin Li 	/* MCS 71  */
798*05b00f60SXin Li 	{	/* 20 Mhz */ {  175.5f,		/* SGI */  195.0f, },
799*05b00f60SXin Li 		/* 40 Mhz */ {  364.5f,		/* SGI */  405.0f, },
800*05b00f60SXin Li 	},
801*05b00f60SXin Li 
802*05b00f60SXin Li 	/* MCS 72  */
803*05b00f60SXin Li 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
804*05b00f60SXin Li 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
805*05b00f60SXin Li 	},
806*05b00f60SXin Li 
807*05b00f60SXin Li 	/* MCS 73  */
808*05b00f60SXin Li 	{	/* 20 Mhz */ {  175.5f,		/* SGI */  195.0f, },
809*05b00f60SXin Li 		/* 40 Mhz */ {  364.5f,		/* SGI */  405.0f, },
810*05b00f60SXin Li 	},
811*05b00f60SXin Li 
812*05b00f60SXin Li 	/* MCS 74  */
813*05b00f60SXin Li 	{	/* 20 Mhz */ {  195.0f,		/* SGI */  216.7f, },
814*05b00f60SXin Li 		/* 40 Mhz */ {  405.0f,		/* SGI */  450.0f, },
815*05b00f60SXin Li 	},
816*05b00f60SXin Li 
817*05b00f60SXin Li 	/* MCS 75  */
818*05b00f60SXin Li 	{	/* 20 Mhz */ {  195.0f,		/* SGI */  216.7f, },
819*05b00f60SXin Li 		/* 40 Mhz */ {  405.0f,		/* SGI */  450.0f, },
820*05b00f60SXin Li 	},
821*05b00f60SXin Li 
822*05b00f60SXin Li 	/* MCS 76  */
823*05b00f60SXin Li 	{	/* 20 Mhz */ {  214.5f,		/* SGI */  238.3f, },
824*05b00f60SXin Li 		/* 40 Mhz */ {  445.5f,		/* SGI */  495.0f, },
825*05b00f60SXin Li 	},
826*05b00f60SXin Li };
827*05b00f60SXin Li 
828*05b00f60SXin Li static const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
829*05b00f60SXin Li #define NUM_AUTH_ALGS	(sizeof(auth_alg_text) / sizeof(auth_alg_text[0]))
830*05b00f60SXin Li 
831*05b00f60SXin Li static const char *status_text[] = {
832*05b00f60SXin Li 	"Successful",						/*  0 */
833*05b00f60SXin Li 	"Unspecified failure",					/*  1 */
834*05b00f60SXin Li 	"TDLS wakeup schedule rejected but alternative schedule "
835*05b00f60SXin Li 	  "provided",					/*  2 */
836*05b00f60SXin Li 	"TDLS wakeup schedule rejected",/*  3 */
837*05b00f60SXin Li 	"Reserved",						/*  4 */
838*05b00f60SXin Li 	"Security disabled",			/*  5 */
839*05b00f60SXin Li 	"Unacceptable lifetime",		/*  6 */
840*05b00f60SXin Li 	"Not in same BSS",				/*  7 */
841*05b00f60SXin Li 	"Reserved",						/*  8 */
842*05b00f60SXin Li 	"Reserved",						/*  9 */
843*05b00f60SXin Li 	"Cannot Support all requested capabilities in the Capability "
844*05b00f60SXin Li 	  "Information field",					/* 10 */
845*05b00f60SXin Li 	"Reassociation denied due to inability to confirm that association "
846*05b00f60SXin Li 	  "exists",						/* 11 */
847*05b00f60SXin Li 	"Association denied due to reason outside the scope of this "
848*05b00f60SXin Li 	  "standard",						/* 12 */
849*05b00f60SXin Li 	"Responding STA does not support the specified authentication "
850*05b00f60SXin Li 	  "algorithm",						/* 13 */
851*05b00f60SXin Li 	"Received an Authentication frame with authentication transaction "
852*05b00f60SXin Li 	  "sequence number out of expected sequence",		/* 14 */
853*05b00f60SXin Li 	"Authentication rejected because of challenge failure",	/* 15 */
854*05b00f60SXin Li 	"Authentication rejected due to timeout waiting for next frame in "
855*05b00f60SXin Li 	  "sequence",						/* 16 */
856*05b00f60SXin Li 	"Association denied because AP is unable to handle "
857*05b00f60SXin Li 	  "additional associated STAs",				/* 17 */
858*05b00f60SXin Li 	"Association denied due to requesting STA not supporting "
859*05b00f60SXin Li 	  "all of the data rates in the BSSBasicRateSet parameter, "
860*05b00f60SXin Li 	  "the Basic HT-MCS Set field of the HT Operation "
861*05b00f60SXin Li 	  "parameter, or the Basic VHT-MCS and NSS Set field in "
862*05b00f60SXin Li 	  "the VHT Operation parameter",	/* 18 */
863*05b00f60SXin Li 	"Association denied due to requesting STA not supporting "
864*05b00f60SXin Li 	  "the short preamble option",				/* 19 */
865*05b00f60SXin Li 	"Reserved",					/* 20 */
866*05b00f60SXin Li 	"Reserved",					/* 21 */
867*05b00f60SXin Li 	"Association request rejected because Spectrum Management "
868*05b00f60SXin Li 	  "capability is required",				/* 22 */
869*05b00f60SXin Li 	"Association request rejected because the information in the "
870*05b00f60SXin Li 	  "Power Capability element is unacceptable",		/* 23 */
871*05b00f60SXin Li 	"Association request rejected because the information in the "
872*05b00f60SXin Li 	  "Supported Channels element is unacceptable",		/* 24 */
873*05b00f60SXin Li 	"Association denied due to requesting STA not supporting "
874*05b00f60SXin Li 	  "the Short Slot Time option",				/* 25 */
875*05b00f60SXin Li 	"Reserved",				/* 26 */
876*05b00f60SXin Li 	"Association denied because the requested STA does not support HT "
877*05b00f60SXin Li 	  "features",						/* 27 */
878*05b00f60SXin Li 	"R0KH unreachable",					/* 28 */
879*05b00f60SXin Li 	"Association denied because the requesting STA does not "
880*05b00f60SXin Li 	  "support the phased coexistence operation (PCO) "
881*05b00f60SXin Li 	  "transition time required by the AP",		/* 29 */
882*05b00f60SXin Li 	"Association request rejected temporarily; try again "
883*05b00f60SXin Li 	  "later",							/* 30 */
884*05b00f60SXin Li 	"Robust management frame policy violation",	/* 31 */
885*05b00f60SXin Li 	"Unspecified, QoS-related failure",			/* 32 */
886*05b00f60SXin Li 	"Association denied because QoS AP or PCP has "
887*05b00f60SXin Li 	  "insufficient bandwidth to handle another QoS "
888*05b00f60SXin Li 	  "STA",									/* 33 */
889*05b00f60SXin Li 	"Association denied due to excessive frame loss rates and/or "
890*05b00f60SXin Li 	  "poor conditions on current operating channel",	/* 34 */
891*05b00f60SXin Li 	"Association (with QoS BSS) denied because the requesting STA "
892*05b00f60SXin Li 	  "does not support the QoS facility",			/* 35 */
893*05b00f60SXin Li 	"Reserved",									/* 36 */
894*05b00f60SXin Li 	"The request has been declined",			/* 37 */
895*05b00f60SXin Li 	"The request has not been successful as one or more parameters "
896*05b00f60SXin Li 	  "have invalid values",				/* 38 */
897*05b00f60SXin Li 	"The allocation or TS has not been created because the request "
898*05b00f60SXin Li 	  "cannot be honored; however, a suggested TSPEC/DMG TSPEC is "
899*05b00f60SXin Li 	  "provided so that the initiating STA can attempt to set "
900*05b00f60SXin Li 	  "another allocation or TS with the suggested changes to the "
901*05b00f60SXin Li 	  "TSPEC/DMG TSPEC",					/* 39 */
902*05b00f60SXin Li 	"Invalid element, i.e., an element defined in this standard "
903*05b00f60SXin Li 	  "for which the content does not meet the specifications in "
904*05b00f60SXin Li 	  "Clause 9",								/* 40 */
905*05b00f60SXin Li 	"Invalid group cipher",						/* 41 */
906*05b00f60SXin Li 	"Invalid pairwise cipher",					/* 42 */
907*05b00f60SXin Li 	"Invalid AKMP",								/* 43 */
908*05b00f60SXin Li 	"Unsupported RSNE version",					/* 44 */
909*05b00f60SXin Li 	"Invalid RSNE capabilities",				/* 45 */
910*05b00f60SXin Li 	"Cipher suite rejected because of security policy",		/* 46 */
911*05b00f60SXin Li 	"The TS or allocation has not been created; however, the "
912*05b00f60SXin Li 	  "HC or PCP might be capable of creating a TS or "
913*05b00f60SXin Li 	  "allocation, in response to a request, after the time "
914*05b00f60SXin Li 	  "indicated in the TS Delay element",		/* 47 */
915*05b00f60SXin Li 	"Direct Link is not allowed in the BSS by policy",	/* 48 */
916*05b00f60SXin Li 	"The Destination STA is not present within this BSS",	/* 49 */
917*05b00f60SXin Li 	"The Destination STA is not a QoS STA",		/* 50 */
918*05b00f60SXin Li 
919*05b00f60SXin Li 	"Association denied because the listen interval is "
920*05b00f60SXin Li 	  "too large",								/* 51 */
921*05b00f60SXin Li 	"Invalid FT Action frame count",			/* 52 */
922*05b00f60SXin Li 	"Invalid pairwise master key identifier (PMKID)", /* 53 */
923*05b00f60SXin Li 	"Invalid MDE",								/* 54 */
924*05b00f60SXin Li 	"Invalid FTE",								/* 55 */
925*05b00f60SXin Li 	"Requested TCLAS processing is not supported by the AP "
926*05b00f60SXin Li 	  "or PCP",									/* 56 */
927*05b00f60SXin Li 	"The AP or PCP has insufficient TCLAS processing "
928*05b00f60SXin Li 	  "resources to satisfy the request",		/* 57 */
929*05b00f60SXin Li 	"The TS has not been created because the request "
930*05b00f60SXin Li 	  "cannot be honored; however, the HC or PCP suggests "
931*05b00f60SXin Li 	  "that the STA transition to a different BSS to set up "
932*05b00f60SXin Li 	  "the TS",									/* 58 */
933*05b00f60SXin Li 	"GAS Advertisement Protocol not supported",	/* 59 */
934*05b00f60SXin Li 	"No outstanding GAS request",				/* 60 */
935*05b00f60SXin Li 	"GAS Response not received from the Advertisement "
936*05b00f60SXin Li 	  "Server",									/* 61 */
937*05b00f60SXin Li 	"STA timed out waiting for GAS Query Response", /* 62 */
938*05b00f60SXin Li 	"LARGE GAS Response is larger than query response "
939*05b00f60SXin Li 	  "length limit",							/* 63 */
940*05b00f60SXin Li 	"Request refused because home network does not support "
941*05b00f60SXin Li 	  "request",								/* 64 */
942*05b00f60SXin Li 	"Advertisement Server in the network is not currently "
943*05b00f60SXin Li 	  "reachable",								/* 65 */
944*05b00f60SXin Li 	"Reserved",									/* 66 */
945*05b00f60SXin Li 	"Request refused due to permissions received via SSPN "
946*05b00f60SXin Li 	  "interface",								/* 67 */
947*05b00f60SXin Li 	"Request refused because the AP or PCP does not "
948*05b00f60SXin Li 	  "support unauthenticated access",			/* 68 */
949*05b00f60SXin Li 	"Reserved",									/* 69 */
950*05b00f60SXin Li 	"Reserved",									/* 70 */
951*05b00f60SXin Li 	"Reserved",									/* 71 */
952*05b00f60SXin Li 	"Invalid contents of RSNE",				/* 72 */
953*05b00f60SXin Li 	"U-APSD coexistence is not supported",		/* 73 */
954*05b00f60SXin Li 	"Requested U-APSD coexistence mode is not supported", /* 74 */
955*05b00f60SXin Li 	"Requested Interval/Duration value cannot be "
956*05b00f60SXin Li 	  "supported with U-APSD coexistence",		/* 75 */
957*05b00f60SXin Li 	"Authentication is rejected because an Anti-Clogging "
958*05b00f60SXin Li 	  "Token is required",						/* 76 */
959*05b00f60SXin Li 	"Authentication is rejected because the offered "
960*05b00f60SXin Li 	  "finite cyclic group is not supported",	/* 77 */
961*05b00f60SXin Li 	"The TBTT adjustment request has not been successful "
962*05b00f60SXin Li 	  "because the STA could not find an alternative TBTT", /* 78 */
963*05b00f60SXin Li 	"Transmission failure",						/* 79 */
964*05b00f60SXin Li 	"Requested TCLAS Not Supported",			/* 80 */
965*05b00f60SXin Li 	"TCLAS Resources Exhausted",				/* 81 */
966*05b00f60SXin Li 	"Rejected with Suggested BSS transition",	/* 82 */
967*05b00f60SXin Li 	"Reject with recommended schedule",			/* 83 */
968*05b00f60SXin Li 	"Reject because no wakeup schedule specified", /* 84 */
969*05b00f60SXin Li 	"Success, the destination STA is in power save mode", /* 85 */
970*05b00f60SXin Li 	"FST pending, in process of admitting FST session", /* 86 */
971*05b00f60SXin Li 	"Performing FST now",						/* 87 */
972*05b00f60SXin Li 	"FST pending, gap(s) in block ack window",	/* 88 */
973*05b00f60SXin Li 	"Reject because of U-PID setting",			/* 89 */
974*05b00f60SXin Li 	"Reserved",									/* 90 */
975*05b00f60SXin Li 	"Reserved",									/* 91 */
976*05b00f60SXin Li 	"(Re)Association refused for some external reason", /* 92 */
977*05b00f60SXin Li 	"(Re)Association refused because of memory limits "
978*05b00f60SXin Li 	  "at the AP",								/* 93 */
979*05b00f60SXin Li 	"(Re)Association refused because emergency services "
980*05b00f60SXin Li 	  "are not supported at the AP",			/* 94 */
981*05b00f60SXin Li 	"GAS query response not yet received",		/* 95 */
982*05b00f60SXin Li 	"Reject since the request is for transition to a "
983*05b00f60SXin Li 	  "frequency band subject to DSE procedures and "
984*05b00f60SXin Li 	  "FST Initiator is a dependent STA",		/* 96 */
985*05b00f60SXin Li 	"Requested TCLAS processing has been terminated by "
986*05b00f60SXin Li 	  "the AP",									/* 97 */
987*05b00f60SXin Li 	"The TS schedule conflicts with an existing "
988*05b00f60SXin Li 	  "schedule; an alternative schedule is provided", /* 98 */
989*05b00f60SXin Li 	"The association has been denied; however, one or "
990*05b00f60SXin Li 	  "more Multi-band elements are included that can "
991*05b00f60SXin Li 	  "be used by the receiving STA to join the BSS", /* 99 */
992*05b00f60SXin Li 	"The request failed due to a reservation conflict", /* 100 */
993*05b00f60SXin Li 	"The request failed due to exceeded MAF limit", /* 101 */
994*05b00f60SXin Li 	"The request failed due to exceeded MCCA track "
995*05b00f60SXin Li 	  "limit",									/* 102 */
996*05b00f60SXin Li 	"Association denied because the information in the"
997*05b00f60SXin Li 	  "Spectrum Management field is unacceptable", /* 103 */
998*05b00f60SXin Li 	"Association denied because the requesting STA "
999*05b00f60SXin Li 	  "does not support VHT features",			/* 104 */
1000*05b00f60SXin Li 	"Enablement denied",						/* 105 */
1001*05b00f60SXin Li 	"Enablement denied due to restriction from an "
1002*05b00f60SXin Li 	  "authorized GDB",							/* 106 */
1003*05b00f60SXin Li 	"Authorization deenabled",					/* 107 */
1004*05b00f60SXin Li };
1005*05b00f60SXin Li #define NUM_STATUSES	(sizeof(status_text) / sizeof(status_text[0]))
1006*05b00f60SXin Li 
1007*05b00f60SXin Li static const char *reason_text[] = {
1008*05b00f60SXin Li 	"Reserved",						/* 0 */
1009*05b00f60SXin Li 	"Unspecified reason",					/* 1 */
1010*05b00f60SXin Li 	"Previous authentication no longer valid",		/* 2 */
1011*05b00f60SXin Li 	"Deauthenticated because sending STA is leaving (or has left) "
1012*05b00f60SXin Li 	  "IBSS or ESS",					/* 3 */
1013*05b00f60SXin Li 	"Disassociated due to inactivity",			/* 4 */
1014*05b00f60SXin Li 	"Disassociated because AP is unable to handle all currently "
1015*05b00f60SXin Li 	  " associated STAs",				/* 5 */
1016*05b00f60SXin Li 	"Class 2 frame received from nonauthenticated STA", /* 6 */
1017*05b00f60SXin Li 	"Class 3 frame received from nonassociated STA",	/* 7 */
1018*05b00f60SXin Li 	"Disassociated because sending STA is leaving "
1019*05b00f60SXin Li 	  "(or has left) BSS",					/* 8 */
1020*05b00f60SXin Li 	"STA requesting (re)association is not authenticated with "
1021*05b00f60SXin Li 	  "responding STA",					/* 9 */
1022*05b00f60SXin Li 	"Disassociated because the information in the Power Capability "
1023*05b00f60SXin Li 	  "element is unacceptable",				/* 10 */
1024*05b00f60SXin Li 	"Disassociated because the information in the Supported Channels "
1025*05b00f60SXin Li 	  "element is unacceptable",				/* 11 */
1026*05b00f60SXin Li 	"Disassociated due to BSS transition management",	/* 12 */
1027*05b00f60SXin Li 	"Invalid element, i.e., an element defined in this standard for "
1028*05b00f60SXin Li 	  "which the content does not meet the specifications "
1029*05b00f60SXin Li 	  "in Clause 9",						/* 13 */
1030*05b00f60SXin Li 	"Message integrity code (MIC) failure",	/* 14 */
1031*05b00f60SXin Li 	"4-Way Handshake timeout",				/* 15 */
1032*05b00f60SXin Li 	"Group key handshake timeout",			/* 16 */
1033*05b00f60SXin Li 	"Information element in 4-Way Handshake different from (Re)Association"
1034*05b00f60SXin Li 	  "Request/Probe Response/Beacon frame",	/* 17 */
1035*05b00f60SXin Li 	"Invalid group cipher",					/* 18 */
1036*05b00f60SXin Li 	"Invalid pairwise cipher",				/* 19 */
1037*05b00f60SXin Li 	"Invalid AKMP",							/* 20 */
1038*05b00f60SXin Li 	"Unsupported RSNE version",				/* 21 */
1039*05b00f60SXin Li 	"Invalid RSNE capabilities",				/* 22 */
1040*05b00f60SXin Li 	"IEEE 802.1X authentication failed",			/* 23 */
1041*05b00f60SXin Li 	"Cipher suite rejected because of the security policy",		/* 24 */
1042*05b00f60SXin Li 	"TDLS direct-link teardown due to TDLS peer STA "
1043*05b00f60SXin Li 	  "unreachable via the TDLS direct link",				/* 25 */
1044*05b00f60SXin Li 	"TDLS direct-link teardown for unspecified reason",		/* 26 */
1045*05b00f60SXin Li 	"Disassociated because session terminated by SSP request",/* 27 */
1046*05b00f60SXin Li 	"Disassociated because of lack of SSP roaming agreement",/* 28 */
1047*05b00f60SXin Li 	"Requested service rejected because of SSP cipher suite or "
1048*05b00f60SXin Li 	  "AKM requirement",						/* 29 */
1049*05b00f60SXin Li 	"Requested service not authorized in this location",	/* 30 */
1050*05b00f60SXin Li 	"TS deleted because QoS AP lacks sufficient bandwidth for this "
1051*05b00f60SXin Li 	  "QoS STA due to a change in BSS service characteristics or "
1052*05b00f60SXin Li 	  "operational mode (e.g. an HT BSS change from 40 MHz channel "
1053*05b00f60SXin Li 	  "to 20 MHz channel)",					/* 31 */
1054*05b00f60SXin Li 	"Disassociated for unspecified, QoS-related reason",	/* 32 */
1055*05b00f60SXin Li 	"Disassociated because QoS AP lacks sufficient bandwidth for this "
1056*05b00f60SXin Li 	  "QoS STA",						/* 33 */
1057*05b00f60SXin Li 	"Disassociated because of excessive number of frames that need to be "
1058*05b00f60SXin Li 	  "acknowledged, but are not acknowledged due to AP transmissions "
1059*05b00f60SXin Li 	  "and/or poor channel conditions",			/* 34 */
1060*05b00f60SXin Li 	"Disassociated because STA is transmitting outside the limits "
1061*05b00f60SXin Li 	  "of its TXOPs",					/* 35 */
1062*05b00f60SXin Li 	"Requested from peer STA as the STA is leaving the BSS "
1063*05b00f60SXin Li 	  "(or resetting)",					/* 36 */
1064*05b00f60SXin Li 	"Requested from peer STA as it does not want to use the "
1065*05b00f60SXin Li 	  "mechanism",						/* 37 */
1066*05b00f60SXin Li 	"Requested from peer STA as the STA received frames using the "
1067*05b00f60SXin Li 	  "mechanism for which a set up is required",		/* 38 */
1068*05b00f60SXin Li 	"Requested from peer STA due to time out",		/* 39 */
1069*05b00f60SXin Li 	"Reserved",						/* 40 */
1070*05b00f60SXin Li 	"Reserved",						/* 41 */
1071*05b00f60SXin Li 	"Reserved",						/* 42 */
1072*05b00f60SXin Li 	"Reserved",						/* 43 */
1073*05b00f60SXin Li 	"Reserved",						/* 44 */
1074*05b00f60SXin Li 	"Peer STA does not support the requested cipher suite",	/* 45 */
1075*05b00f60SXin Li 	"In a DLS Teardown frame: The teardown was initiated by the "
1076*05b00f60SXin Li 	  "DLS peer. In a Disassociation frame: Disassociated because "
1077*05b00f60SXin Li 	  "authorized access limit reached",					/* 46 */
1078*05b00f60SXin Li 	"In a DLS Teardown frame: The teardown was initiated by the "
1079*05b00f60SXin Li 	  "AP. In a Disassociation frame: Disassociated due to external "
1080*05b00f60SXin Li 	  "service requirements",								/* 47 */
1081*05b00f60SXin Li 	"Invalid FT Action frame count",						/* 48 */
1082*05b00f60SXin Li 	"Invalid pairwise master key identifier (PMKID)",		/* 49 */
1083*05b00f60SXin Li 	"Invalid MDE",											/* 50 */
1084*05b00f60SXin Li 	"Invalid FTE",											/* 51 */
1085*05b00f60SXin Li 	"Mesh peering canceled for unknown reasons",			/* 52 */
1086*05b00f60SXin Li 	"The mesh STA has reached the supported maximum number of "
1087*05b00f60SXin Li 	  "peer mesh STAs",										/* 53 */
1088*05b00f60SXin Li 	"The received information violates the Mesh Configuration "
1089*05b00f60SXin Li 	  "policy configured in the mesh STA profile",			/* 54 */
1090*05b00f60SXin Li 	"The mesh STA has received a Mesh Peering Close frame "
1091*05b00f60SXin Li 	  "requesting to close the mesh peering",				/* 55 */
1092*05b00f60SXin Li 	"The mesh STA has resent dot11MeshMaxRetries Mesh "
1093*05b00f60SXin Li 	  "Peering Open frames, without receiving a Mesh Peering "
1094*05b00f60SXin Li 	  "Confirm frame",										/* 56 */
1095*05b00f60SXin Li 	"The confirmTimer for the mesh peering instance times out",	/* 57 */
1096*05b00f60SXin Li 	"The mesh STA fails to unwrap the GTK or the values in the "
1097*05b00f60SXin Li 	  "wrapped contents do not match",						/* 58 */
1098*05b00f60SXin Li 	"The mesh STA receives inconsistent information about the "
1099*05b00f60SXin Li 	  "mesh parameters between mesh peering Management frames",	/* 59 */
1100*05b00f60SXin Li 	"The mesh STA fails the authenticated mesh peering exchange "
1101*05b00f60SXin Li 	  "because due to failure in selecting either the pairwise "
1102*05b00f60SXin Li 	  "ciphersuite or group ciphersuite",					/* 60 */
1103*05b00f60SXin Li 	"The mesh STA does not have proxy information for this "
1104*05b00f60SXin Li 	  "external destination",								/* 61 */
1105*05b00f60SXin Li 	"The mesh STA does not have forwarding information for this "
1106*05b00f60SXin Li 	  "destination",										/* 62 */
1107*05b00f60SXin Li 	"The mesh STA determines that the link to the next hop of an "
1108*05b00f60SXin Li 	  "active path in its forwarding information is no longer "
1109*05b00f60SXin Li 	  "usable",												/* 63 */
1110*05b00f60SXin Li 	"The Deauthentication frame was sent because the MAC "
1111*05b00f60SXin Li 	  "address of the STA already exists in the mesh BSS",	/* 64 */
1112*05b00f60SXin Li 	"The mesh STA performs channel switch to meet regulatory "
1113*05b00f60SXin Li 	  "requirements",										/* 65 */
1114*05b00f60SXin Li 	"The mesh STA performs channel switching with unspecified "
1115*05b00f60SXin Li 	  "reason",												/* 66 */
1116*05b00f60SXin Li };
1117*05b00f60SXin Li #define NUM_REASONS	(sizeof(reason_text) / sizeof(reason_text[0]))
1118*05b00f60SXin Li 
1119*05b00f60SXin Li static int
wep_print(netdissect_options * ndo,const u_char * p)1120*05b00f60SXin Li wep_print(netdissect_options *ndo,
1121*05b00f60SXin Li 	  const u_char *p)
1122*05b00f60SXin Li {
1123*05b00f60SXin Li 	uint32_t iv;
1124*05b00f60SXin Li 
1125*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN);
1126*05b00f60SXin Li 	iv = GET_LE_U_4(p);
1127*05b00f60SXin Li 
1128*05b00f60SXin Li 	ND_PRINT(" IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
1129*05b00f60SXin Li 	    IV_KEYID(iv));
1130*05b00f60SXin Li 
1131*05b00f60SXin Li 	return 1;
1132*05b00f60SXin Li trunc:
1133*05b00f60SXin Li 	return 0;
1134*05b00f60SXin Li }
1135*05b00f60SXin Li 
1136*05b00f60SXin Li static int
parse_elements(netdissect_options * ndo,struct mgmt_body_t * pbody,const u_char * p,int offset,u_int length)1137*05b00f60SXin Li parse_elements(netdissect_options *ndo,
1138*05b00f60SXin Li 	       struct mgmt_body_t *pbody, const u_char *p, int offset,
1139*05b00f60SXin Li 	       u_int length)
1140*05b00f60SXin Li {
1141*05b00f60SXin Li 	u_int elementlen;
1142*05b00f60SXin Li 	struct ssid_t ssid;
1143*05b00f60SXin Li 	struct challenge_t challenge;
1144*05b00f60SXin Li 	struct rates_t rates;
1145*05b00f60SXin Li 	struct ds_t ds;
1146*05b00f60SXin Li 	struct cf_t cf;
1147*05b00f60SXin Li 	struct tim_t tim;
1148*05b00f60SXin Li 
1149*05b00f60SXin Li 	/*
1150*05b00f60SXin Li 	 * We haven't seen any elements yet.
1151*05b00f60SXin Li 	 */
1152*05b00f60SXin Li 	pbody->challenge_present = 0;
1153*05b00f60SXin Li 	pbody->ssid_present = 0;
1154*05b00f60SXin Li 	pbody->rates_present = 0;
1155*05b00f60SXin Li 	pbody->ds_present = 0;
1156*05b00f60SXin Li 	pbody->cf_present = 0;
1157*05b00f60SXin Li 	pbody->tim_present = 0;
1158*05b00f60SXin Li 
1159*05b00f60SXin Li 	while (length != 0) {
1160*05b00f60SXin Li 		/* Make sure we at least have the element ID and length. */
1161*05b00f60SXin Li 		ND_TCHECK_2(p + offset);
1162*05b00f60SXin Li 		if (length < 2)
1163*05b00f60SXin Li 			goto trunc;
1164*05b00f60SXin Li 		elementlen = GET_U_1(p + offset + 1);
1165*05b00f60SXin Li 
1166*05b00f60SXin Li 		/* Make sure we have the entire element. */
1167*05b00f60SXin Li 		ND_TCHECK_LEN(p + offset + 2, elementlen);
1168*05b00f60SXin Li 		if (length < elementlen + 2)
1169*05b00f60SXin Li 			goto trunc;
1170*05b00f60SXin Li 
1171*05b00f60SXin Li 		switch (GET_U_1(p + offset)) {
1172*05b00f60SXin Li 		case E_SSID:
1173*05b00f60SXin Li 			memcpy(&ssid, p + offset, 2);
1174*05b00f60SXin Li 			offset += 2;
1175*05b00f60SXin Li 			length -= 2;
1176*05b00f60SXin Li 			if (ssid.length != 0) {
1177*05b00f60SXin Li 				if (ssid.length > sizeof(ssid.ssid) - 1)
1178*05b00f60SXin Li 					return 0;
1179*05b00f60SXin Li 				memcpy(&ssid.ssid, p + offset, ssid.length);
1180*05b00f60SXin Li 				offset += ssid.length;
1181*05b00f60SXin Li 				length -= ssid.length;
1182*05b00f60SXin Li 			}
1183*05b00f60SXin Li 			ssid.ssid[ssid.length] = '\0';
1184*05b00f60SXin Li 			/*
1185*05b00f60SXin Li 			 * Present and not truncated.
1186*05b00f60SXin Li 			 *
1187*05b00f60SXin Li 			 * If we haven't already seen an SSID IE,
1188*05b00f60SXin Li 			 * copy this one, otherwise ignore this one,
1189*05b00f60SXin Li 			 * so we later report the first one we saw.
1190*05b00f60SXin Li 			 */
1191*05b00f60SXin Li 			if (!pbody->ssid_present) {
1192*05b00f60SXin Li 				pbody->ssid = ssid;
1193*05b00f60SXin Li 				pbody->ssid_present = 1;
1194*05b00f60SXin Li 			}
1195*05b00f60SXin Li 			break;
1196*05b00f60SXin Li 		case E_CHALLENGE:
1197*05b00f60SXin Li 			memcpy(&challenge, p + offset, 2);
1198*05b00f60SXin Li 			offset += 2;
1199*05b00f60SXin Li 			length -= 2;
1200*05b00f60SXin Li 			if (challenge.length != 0) {
1201*05b00f60SXin Li 				if (challenge.length >
1202*05b00f60SXin Li 				    sizeof(challenge.text) - 1)
1203*05b00f60SXin Li 					return 0;
1204*05b00f60SXin Li 				memcpy(&challenge.text, p + offset,
1205*05b00f60SXin Li 				    challenge.length);
1206*05b00f60SXin Li 				offset += challenge.length;
1207*05b00f60SXin Li 				length -= challenge.length;
1208*05b00f60SXin Li 			}
1209*05b00f60SXin Li 			challenge.text[challenge.length] = '\0';
1210*05b00f60SXin Li 			/*
1211*05b00f60SXin Li 			 * Present and not truncated.
1212*05b00f60SXin Li 			 *
1213*05b00f60SXin Li 			 * If we haven't already seen a challenge IE,
1214*05b00f60SXin Li 			 * copy this one, otherwise ignore this one,
1215*05b00f60SXin Li 			 * so we later report the first one we saw.
1216*05b00f60SXin Li 			 */
1217*05b00f60SXin Li 			if (!pbody->challenge_present) {
1218*05b00f60SXin Li 				pbody->challenge = challenge;
1219*05b00f60SXin Li 				pbody->challenge_present = 1;
1220*05b00f60SXin Li 			}
1221*05b00f60SXin Li 			break;
1222*05b00f60SXin Li 		case E_RATES:
1223*05b00f60SXin Li 			memcpy(&rates, p + offset, 2);
1224*05b00f60SXin Li 			offset += 2;
1225*05b00f60SXin Li 			length -= 2;
1226*05b00f60SXin Li 			if (rates.length != 0) {
1227*05b00f60SXin Li 				if (rates.length > sizeof(rates.rate))
1228*05b00f60SXin Li 					return 0;
1229*05b00f60SXin Li 				memcpy(&rates.rate, p + offset, rates.length);
1230*05b00f60SXin Li 				offset += rates.length;
1231*05b00f60SXin Li 				length -= rates.length;
1232*05b00f60SXin Li 			}
1233*05b00f60SXin Li 			/*
1234*05b00f60SXin Li 			 * Present and not truncated.
1235*05b00f60SXin Li 			 *
1236*05b00f60SXin Li 			 * If we haven't already seen a rates IE,
1237*05b00f60SXin Li 			 * copy this one if it's not zero-length,
1238*05b00f60SXin Li 			 * otherwise ignore this one, so we later
1239*05b00f60SXin Li 			 * report the first one we saw.
1240*05b00f60SXin Li 			 *
1241*05b00f60SXin Li 			 * We ignore zero-length rates IEs as some
1242*05b00f60SXin Li 			 * devices seem to put a zero-length rates
1243*05b00f60SXin Li 			 * IE, followed by an SSID IE, followed by
1244*05b00f60SXin Li 			 * a non-zero-length rates IE into frames,
1245*05b00f60SXin Li 			 * even though IEEE Std 802.11-2007 doesn't
1246*05b00f60SXin Li 			 * seem to indicate that a zero-length rates
1247*05b00f60SXin Li 			 * IE is valid.
1248*05b00f60SXin Li 			 */
1249*05b00f60SXin Li 			if (!pbody->rates_present && rates.length != 0) {
1250*05b00f60SXin Li 				pbody->rates = rates;
1251*05b00f60SXin Li 				pbody->rates_present = 1;
1252*05b00f60SXin Li 			}
1253*05b00f60SXin Li 			break;
1254*05b00f60SXin Li 		case E_DS:
1255*05b00f60SXin Li 			memcpy(&ds, p + offset, 2);
1256*05b00f60SXin Li 			offset += 2;
1257*05b00f60SXin Li 			length -= 2;
1258*05b00f60SXin Li 			if (ds.length != 1) {
1259*05b00f60SXin Li 				offset += ds.length;
1260*05b00f60SXin Li 				length -= ds.length;
1261*05b00f60SXin Li 				break;
1262*05b00f60SXin Li 			}
1263*05b00f60SXin Li 			ds.channel = GET_U_1(p + offset);
1264*05b00f60SXin Li 			offset += 1;
1265*05b00f60SXin Li 			length -= 1;
1266*05b00f60SXin Li 			/*
1267*05b00f60SXin Li 			 * Present and not truncated.
1268*05b00f60SXin Li 			 *
1269*05b00f60SXin Li 			 * If we haven't already seen a DS IE,
1270*05b00f60SXin Li 			 * copy this one, otherwise ignore this one,
1271*05b00f60SXin Li 			 * so we later report the first one we saw.
1272*05b00f60SXin Li 			 */
1273*05b00f60SXin Li 			if (!pbody->ds_present) {
1274*05b00f60SXin Li 				pbody->ds = ds;
1275*05b00f60SXin Li 				pbody->ds_present = 1;
1276*05b00f60SXin Li 			}
1277*05b00f60SXin Li 			break;
1278*05b00f60SXin Li 		case E_CF:
1279*05b00f60SXin Li 			memcpy(&cf, p + offset, 2);
1280*05b00f60SXin Li 			offset += 2;
1281*05b00f60SXin Li 			length -= 2;
1282*05b00f60SXin Li 			if (cf.length != 6) {
1283*05b00f60SXin Li 				offset += cf.length;
1284*05b00f60SXin Li 				length -= cf.length;
1285*05b00f60SXin Li 				break;
1286*05b00f60SXin Li 			}
1287*05b00f60SXin Li 			cf.count = GET_U_1(p + offset);
1288*05b00f60SXin Li 			offset += 1;
1289*05b00f60SXin Li 			length -= 1;
1290*05b00f60SXin Li 			cf.period = GET_U_1(p + offset);
1291*05b00f60SXin Li 			offset += 1;
1292*05b00f60SXin Li 			length -= 1;
1293*05b00f60SXin Li 			cf.max_duration = GET_LE_U_2(p + offset);
1294*05b00f60SXin Li 			offset += 2;
1295*05b00f60SXin Li 			length -= 2;
1296*05b00f60SXin Li 			cf.dur_remaining = GET_LE_U_2(p + offset);
1297*05b00f60SXin Li 			offset += 2;
1298*05b00f60SXin Li 			length -= 2;
1299*05b00f60SXin Li 			/*
1300*05b00f60SXin Li 			 * Present and not truncated.
1301*05b00f60SXin Li 			 *
1302*05b00f60SXin Li 			 * If we haven't already seen a CF IE,
1303*05b00f60SXin Li 			 * copy this one, otherwise ignore this one,
1304*05b00f60SXin Li 			 * so we later report the first one we saw.
1305*05b00f60SXin Li 			 */
1306*05b00f60SXin Li 			if (!pbody->cf_present) {
1307*05b00f60SXin Li 				pbody->cf = cf;
1308*05b00f60SXin Li 				pbody->cf_present = 1;
1309*05b00f60SXin Li 			}
1310*05b00f60SXin Li 			break;
1311*05b00f60SXin Li 		case E_TIM:
1312*05b00f60SXin Li 			memcpy(&tim, p + offset, 2);
1313*05b00f60SXin Li 			offset += 2;
1314*05b00f60SXin Li 			length -= 2;
1315*05b00f60SXin Li 			if (tim.length <= 3U) {
1316*05b00f60SXin Li 				offset += tim.length;
1317*05b00f60SXin Li 				length -= tim.length;
1318*05b00f60SXin Li 				break;
1319*05b00f60SXin Li 			}
1320*05b00f60SXin Li 			if (tim.length - 3U > sizeof(tim.bitmap))
1321*05b00f60SXin Li 				return 0;
1322*05b00f60SXin Li 			tim.count = GET_U_1(p + offset);
1323*05b00f60SXin Li 			offset += 1;
1324*05b00f60SXin Li 			length -= 1;
1325*05b00f60SXin Li 			tim.period = GET_U_1(p + offset);
1326*05b00f60SXin Li 			offset += 1;
1327*05b00f60SXin Li 			length -= 1;
1328*05b00f60SXin Li 			tim.bitmap_control = GET_U_1(p + offset);
1329*05b00f60SXin Li 			offset += 1;
1330*05b00f60SXin Li 			length -= 1;
1331*05b00f60SXin Li 			memcpy(tim.bitmap, p + offset, tim.length - 3);
1332*05b00f60SXin Li 			offset += tim.length - 3;
1333*05b00f60SXin Li 			length -= tim.length - 3;
1334*05b00f60SXin Li 			/*
1335*05b00f60SXin Li 			 * Present and not truncated.
1336*05b00f60SXin Li 			 *
1337*05b00f60SXin Li 			 * If we haven't already seen a TIM IE,
1338*05b00f60SXin Li 			 * copy this one, otherwise ignore this one,
1339*05b00f60SXin Li 			 * so we later report the first one we saw.
1340*05b00f60SXin Li 			 */
1341*05b00f60SXin Li 			if (!pbody->tim_present) {
1342*05b00f60SXin Li 				pbody->tim = tim;
1343*05b00f60SXin Li 				pbody->tim_present = 1;
1344*05b00f60SXin Li 			}
1345*05b00f60SXin Li 			break;
1346*05b00f60SXin Li 		default:
1347*05b00f60SXin Li #if 0
1348*05b00f60SXin Li 			ND_PRINT("(1) unhandled element_id (%u)  ",
1349*05b00f60SXin Li 			    GET_U_1(p + offset));
1350*05b00f60SXin Li #endif
1351*05b00f60SXin Li 			offset += 2 + elementlen;
1352*05b00f60SXin Li 			length -= 2 + elementlen;
1353*05b00f60SXin Li 			break;
1354*05b00f60SXin Li 		}
1355*05b00f60SXin Li 	}
1356*05b00f60SXin Li 
1357*05b00f60SXin Li 	/* No problems found. */
1358*05b00f60SXin Li 	return 1;
1359*05b00f60SXin Li trunc:
1360*05b00f60SXin Li 	return 0;
1361*05b00f60SXin Li }
1362*05b00f60SXin Li 
1363*05b00f60SXin Li /*********************************************************************************
1364*05b00f60SXin Li  * Print Handle functions for the management frame types
1365*05b00f60SXin Li  *********************************************************************************/
1366*05b00f60SXin Li 
1367*05b00f60SXin Li static int
handle_beacon(netdissect_options * ndo,const u_char * p,u_int length)1368*05b00f60SXin Li handle_beacon(netdissect_options *ndo,
1369*05b00f60SXin Li 	      const u_char *p, u_int length)
1370*05b00f60SXin Li {
1371*05b00f60SXin Li 	struct mgmt_body_t pbody;
1372*05b00f60SXin Li 	int offset = 0;
1373*05b00f60SXin Li 	int ret;
1374*05b00f60SXin Li 
1375*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1376*05b00f60SXin Li 
1377*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1378*05b00f60SXin Li 		      IEEE802_11_CAPINFO_LEN);
1379*05b00f60SXin Li 	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1380*05b00f60SXin Li 	    IEEE802_11_CAPINFO_LEN)
1381*05b00f60SXin Li 		goto trunc;
1382*05b00f60SXin Li 	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
1383*05b00f60SXin Li 	offset += IEEE802_11_TSTAMP_LEN;
1384*05b00f60SXin Li 	length -= IEEE802_11_TSTAMP_LEN;
1385*05b00f60SXin Li 	pbody.beacon_interval = GET_LE_U_2(p + offset);
1386*05b00f60SXin Li 	offset += IEEE802_11_BCNINT_LEN;
1387*05b00f60SXin Li 	length -= IEEE802_11_BCNINT_LEN;
1388*05b00f60SXin Li 	pbody.capability_info = GET_LE_U_2(p + offset);
1389*05b00f60SXin Li 	offset += IEEE802_11_CAPINFO_LEN;
1390*05b00f60SXin Li 	length -= IEEE802_11_CAPINFO_LEN;
1391*05b00f60SXin Li 
1392*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1393*05b00f60SXin Li 
1394*05b00f60SXin Li 	PRINT_SSID(pbody);
1395*05b00f60SXin Li 	PRINT_RATES(pbody);
1396*05b00f60SXin Li 	ND_PRINT(" %s",
1397*05b00f60SXin Li 	    CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
1398*05b00f60SXin Li 	PRINT_DS_CHANNEL(pbody);
1399*05b00f60SXin Li 
1400*05b00f60SXin Li 	return ret;
1401*05b00f60SXin Li trunc:
1402*05b00f60SXin Li 	return 0;
1403*05b00f60SXin Li }
1404*05b00f60SXin Li 
1405*05b00f60SXin Li static int
handle_assoc_request(netdissect_options * ndo,const u_char * p,u_int length)1406*05b00f60SXin Li handle_assoc_request(netdissect_options *ndo,
1407*05b00f60SXin Li 		     const u_char *p, u_int length)
1408*05b00f60SXin Li {
1409*05b00f60SXin Li 	struct mgmt_body_t pbody;
1410*05b00f60SXin Li 	int offset = 0;
1411*05b00f60SXin Li 	int ret;
1412*05b00f60SXin Li 
1413*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1414*05b00f60SXin Li 
1415*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN);
1416*05b00f60SXin Li 	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
1417*05b00f60SXin Li 		goto trunc;
1418*05b00f60SXin Li 	pbody.capability_info = GET_LE_U_2(p);
1419*05b00f60SXin Li 	offset += IEEE802_11_CAPINFO_LEN;
1420*05b00f60SXin Li 	length -= IEEE802_11_CAPINFO_LEN;
1421*05b00f60SXin Li 	pbody.listen_interval = GET_LE_U_2(p + offset);
1422*05b00f60SXin Li 	offset += IEEE802_11_LISTENINT_LEN;
1423*05b00f60SXin Li 	length -= IEEE802_11_LISTENINT_LEN;
1424*05b00f60SXin Li 
1425*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1426*05b00f60SXin Li 
1427*05b00f60SXin Li 	PRINT_SSID(pbody);
1428*05b00f60SXin Li 	PRINT_RATES(pbody);
1429*05b00f60SXin Li 	return ret;
1430*05b00f60SXin Li trunc:
1431*05b00f60SXin Li 	return 0;
1432*05b00f60SXin Li }
1433*05b00f60SXin Li 
1434*05b00f60SXin Li static int
handle_assoc_response(netdissect_options * ndo,const u_char * p,u_int length)1435*05b00f60SXin Li handle_assoc_response(netdissect_options *ndo,
1436*05b00f60SXin Li 		      const u_char *p, u_int length)
1437*05b00f60SXin Li {
1438*05b00f60SXin Li 	struct mgmt_body_t pbody;
1439*05b00f60SXin Li 	int offset = 0;
1440*05b00f60SXin Li 	int ret;
1441*05b00f60SXin Li 
1442*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1443*05b00f60SXin Li 
1444*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1445*05b00f60SXin Li 		      IEEE802_11_AID_LEN);
1446*05b00f60SXin Li 	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1447*05b00f60SXin Li 	    IEEE802_11_AID_LEN)
1448*05b00f60SXin Li 		goto trunc;
1449*05b00f60SXin Li 	pbody.capability_info = GET_LE_U_2(p);
1450*05b00f60SXin Li 	offset += IEEE802_11_CAPINFO_LEN;
1451*05b00f60SXin Li 	length -= IEEE802_11_CAPINFO_LEN;
1452*05b00f60SXin Li 	pbody.status_code = GET_LE_U_2(p + offset);
1453*05b00f60SXin Li 	offset += IEEE802_11_STATUS_LEN;
1454*05b00f60SXin Li 	length -= IEEE802_11_STATUS_LEN;
1455*05b00f60SXin Li 	pbody.aid = GET_LE_U_2(p + offset);
1456*05b00f60SXin Li 	offset += IEEE802_11_AID_LEN;
1457*05b00f60SXin Li 	length -= IEEE802_11_AID_LEN;
1458*05b00f60SXin Li 
1459*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1460*05b00f60SXin Li 
1461*05b00f60SXin Li 	ND_PRINT(" AID(%x) :%s: %s", ((uint16_t)(pbody.aid << 2 )) >> 2 ,
1462*05b00f60SXin Li 	    CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
1463*05b00f60SXin Li 	    (pbody.status_code < NUM_STATUSES
1464*05b00f60SXin Li 		? status_text[pbody.status_code]
1465*05b00f60SXin Li 		: "n/a"));
1466*05b00f60SXin Li 
1467*05b00f60SXin Li 	return ret;
1468*05b00f60SXin Li trunc:
1469*05b00f60SXin Li 	return 0;
1470*05b00f60SXin Li }
1471*05b00f60SXin Li 
1472*05b00f60SXin Li static int
handle_reassoc_request(netdissect_options * ndo,const u_char * p,u_int length)1473*05b00f60SXin Li handle_reassoc_request(netdissect_options *ndo,
1474*05b00f60SXin Li 		       const u_char *p, u_int length)
1475*05b00f60SXin Li {
1476*05b00f60SXin Li 	struct mgmt_body_t pbody;
1477*05b00f60SXin Li 	int offset = 0;
1478*05b00f60SXin Li 	int ret;
1479*05b00f60SXin Li 
1480*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1481*05b00f60SXin Li 
1482*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1483*05b00f60SXin Li 		      IEEE802_11_AP_LEN);
1484*05b00f60SXin Li 	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1485*05b00f60SXin Li 	    IEEE802_11_AP_LEN)
1486*05b00f60SXin Li 		goto trunc;
1487*05b00f60SXin Li 	pbody.capability_info = GET_LE_U_2(p);
1488*05b00f60SXin Li 	offset += IEEE802_11_CAPINFO_LEN;
1489*05b00f60SXin Li 	length -= IEEE802_11_CAPINFO_LEN;
1490*05b00f60SXin Li 	pbody.listen_interval = GET_LE_U_2(p + offset);
1491*05b00f60SXin Li 	offset += IEEE802_11_LISTENINT_LEN;
1492*05b00f60SXin Li 	length -= IEEE802_11_LISTENINT_LEN;
1493*05b00f60SXin Li 	memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
1494*05b00f60SXin Li 	offset += IEEE802_11_AP_LEN;
1495*05b00f60SXin Li 	length -= IEEE802_11_AP_LEN;
1496*05b00f60SXin Li 
1497*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1498*05b00f60SXin Li 
1499*05b00f60SXin Li 	PRINT_SSID(pbody);
1500*05b00f60SXin Li 	ND_PRINT(" AP : %s", etheraddr_string(ndo,  pbody.ap ));
1501*05b00f60SXin Li 
1502*05b00f60SXin Li 	return ret;
1503*05b00f60SXin Li trunc:
1504*05b00f60SXin Li 	return 0;
1505*05b00f60SXin Li }
1506*05b00f60SXin Li 
1507*05b00f60SXin Li static int
handle_reassoc_response(netdissect_options * ndo,const u_char * p,u_int length)1508*05b00f60SXin Li handle_reassoc_response(netdissect_options *ndo,
1509*05b00f60SXin Li 			const u_char *p, u_int length)
1510*05b00f60SXin Li {
1511*05b00f60SXin Li 	/* Same as a Association Response */
1512*05b00f60SXin Li 	return handle_assoc_response(ndo, p, length);
1513*05b00f60SXin Li }
1514*05b00f60SXin Li 
1515*05b00f60SXin Li static int
handle_probe_request(netdissect_options * ndo,const u_char * p,u_int length)1516*05b00f60SXin Li handle_probe_request(netdissect_options *ndo,
1517*05b00f60SXin Li 		     const u_char *p, u_int length)
1518*05b00f60SXin Li {
1519*05b00f60SXin Li 	struct mgmt_body_t  pbody;
1520*05b00f60SXin Li 	int offset = 0;
1521*05b00f60SXin Li 	int ret;
1522*05b00f60SXin Li 
1523*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1524*05b00f60SXin Li 
1525*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1526*05b00f60SXin Li 
1527*05b00f60SXin Li 	PRINT_SSID(pbody);
1528*05b00f60SXin Li 	PRINT_RATES(pbody);
1529*05b00f60SXin Li 
1530*05b00f60SXin Li 	return ret;
1531*05b00f60SXin Li }
1532*05b00f60SXin Li 
1533*05b00f60SXin Li static int
handle_probe_response(netdissect_options * ndo,const u_char * p,u_int length)1534*05b00f60SXin Li handle_probe_response(netdissect_options *ndo,
1535*05b00f60SXin Li 		      const u_char *p, u_int length)
1536*05b00f60SXin Li {
1537*05b00f60SXin Li 	struct mgmt_body_t  pbody;
1538*05b00f60SXin Li 	int offset = 0;
1539*05b00f60SXin Li 	int ret;
1540*05b00f60SXin Li 
1541*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1542*05b00f60SXin Li 
1543*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1544*05b00f60SXin Li 		      IEEE802_11_CAPINFO_LEN);
1545*05b00f60SXin Li 	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1546*05b00f60SXin Li 	    IEEE802_11_CAPINFO_LEN)
1547*05b00f60SXin Li 		goto trunc;
1548*05b00f60SXin Li 	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
1549*05b00f60SXin Li 	offset += IEEE802_11_TSTAMP_LEN;
1550*05b00f60SXin Li 	length -= IEEE802_11_TSTAMP_LEN;
1551*05b00f60SXin Li 	pbody.beacon_interval = GET_LE_U_2(p + offset);
1552*05b00f60SXin Li 	offset += IEEE802_11_BCNINT_LEN;
1553*05b00f60SXin Li 	length -= IEEE802_11_BCNINT_LEN;
1554*05b00f60SXin Li 	pbody.capability_info = GET_LE_U_2(p + offset);
1555*05b00f60SXin Li 	offset += IEEE802_11_CAPINFO_LEN;
1556*05b00f60SXin Li 	length -= IEEE802_11_CAPINFO_LEN;
1557*05b00f60SXin Li 
1558*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1559*05b00f60SXin Li 
1560*05b00f60SXin Li 	PRINT_SSID(pbody);
1561*05b00f60SXin Li 	PRINT_RATES(pbody);
1562*05b00f60SXin Li 	PRINT_DS_CHANNEL(pbody);
1563*05b00f60SXin Li 
1564*05b00f60SXin Li 	return ret;
1565*05b00f60SXin Li trunc:
1566*05b00f60SXin Li 	return 0;
1567*05b00f60SXin Li }
1568*05b00f60SXin Li 
1569*05b00f60SXin Li static int
handle_atim(void)1570*05b00f60SXin Li handle_atim(void)
1571*05b00f60SXin Li {
1572*05b00f60SXin Li 	/* the frame body for ATIM is null. */
1573*05b00f60SXin Li 	return 1;
1574*05b00f60SXin Li }
1575*05b00f60SXin Li 
1576*05b00f60SXin Li static int
handle_disassoc(netdissect_options * ndo,const u_char * p,u_int length)1577*05b00f60SXin Li handle_disassoc(netdissect_options *ndo,
1578*05b00f60SXin Li 		const u_char *p, u_int length)
1579*05b00f60SXin Li {
1580*05b00f60SXin Li 	struct mgmt_body_t  pbody;
1581*05b00f60SXin Li 
1582*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1583*05b00f60SXin Li 
1584*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_REASON_LEN);
1585*05b00f60SXin Li 	if (length < IEEE802_11_REASON_LEN)
1586*05b00f60SXin Li 		goto trunc;
1587*05b00f60SXin Li 	pbody.reason_code = GET_LE_U_2(p);
1588*05b00f60SXin Li 
1589*05b00f60SXin Li 	ND_PRINT(": %s",
1590*05b00f60SXin Li 	    (pbody.reason_code < NUM_REASONS)
1591*05b00f60SXin Li 		? reason_text[pbody.reason_code]
1592*05b00f60SXin Li 		: "Reserved");
1593*05b00f60SXin Li 
1594*05b00f60SXin Li 	return 1;
1595*05b00f60SXin Li trunc:
1596*05b00f60SXin Li 	return 0;
1597*05b00f60SXin Li }
1598*05b00f60SXin Li 
1599*05b00f60SXin Li static int
handle_auth(netdissect_options * ndo,const u_char * p,u_int length)1600*05b00f60SXin Li handle_auth(netdissect_options *ndo,
1601*05b00f60SXin Li 	    const u_char *p, u_int length)
1602*05b00f60SXin Li {
1603*05b00f60SXin Li 	struct mgmt_body_t  pbody;
1604*05b00f60SXin Li 	int offset = 0;
1605*05b00f60SXin Li 	int ret;
1606*05b00f60SXin Li 
1607*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1608*05b00f60SXin Li 
1609*05b00f60SXin Li 	ND_TCHECK_6(p);
1610*05b00f60SXin Li 	if (length < 6)
1611*05b00f60SXin Li 		goto trunc;
1612*05b00f60SXin Li 	pbody.auth_alg = GET_LE_U_2(p);
1613*05b00f60SXin Li 	offset += 2;
1614*05b00f60SXin Li 	length -= 2;
1615*05b00f60SXin Li 	pbody.auth_trans_seq_num = GET_LE_U_2(p + offset);
1616*05b00f60SXin Li 	offset += 2;
1617*05b00f60SXin Li 	length -= 2;
1618*05b00f60SXin Li 	pbody.status_code = GET_LE_U_2(p + offset);
1619*05b00f60SXin Li 	offset += 2;
1620*05b00f60SXin Li 	length -= 2;
1621*05b00f60SXin Li 
1622*05b00f60SXin Li 	ret = parse_elements(ndo, &pbody, p, offset, length);
1623*05b00f60SXin Li 
1624*05b00f60SXin Li 	if ((pbody.auth_alg == 1) &&
1625*05b00f60SXin Li 	    ((pbody.auth_trans_seq_num == 2) ||
1626*05b00f60SXin Li 	     (pbody.auth_trans_seq_num == 3))) {
1627*05b00f60SXin Li 		ND_PRINT(" (%s)-%x [Challenge Text] %s",
1628*05b00f60SXin Li 		    (pbody.auth_alg < NUM_AUTH_ALGS)
1629*05b00f60SXin Li 			? auth_alg_text[pbody.auth_alg]
1630*05b00f60SXin Li 			: "Reserved",
1631*05b00f60SXin Li 		    pbody.auth_trans_seq_num,
1632*05b00f60SXin Li 		    ((pbody.auth_trans_seq_num % 2)
1633*05b00f60SXin Li 			? ((pbody.status_code < NUM_STATUSES)
1634*05b00f60SXin Li 			       ? status_text[pbody.status_code]
1635*05b00f60SXin Li 			       : "n/a") : ""));
1636*05b00f60SXin Li 		return ret;
1637*05b00f60SXin Li 	}
1638*05b00f60SXin Li 	ND_PRINT(" (%s)-%x: %s",
1639*05b00f60SXin Li 	    (pbody.auth_alg < NUM_AUTH_ALGS)
1640*05b00f60SXin Li 		? auth_alg_text[pbody.auth_alg]
1641*05b00f60SXin Li 		: "Reserved",
1642*05b00f60SXin Li 	    pbody.auth_trans_seq_num,
1643*05b00f60SXin Li 	    (pbody.auth_trans_seq_num % 2)
1644*05b00f60SXin Li 		? ((pbody.status_code < NUM_STATUSES)
1645*05b00f60SXin Li 		    ? status_text[pbody.status_code]
1646*05b00f60SXin Li 		    : "n/a")
1647*05b00f60SXin Li 		: "");
1648*05b00f60SXin Li 
1649*05b00f60SXin Li 	return ret;
1650*05b00f60SXin Li trunc:
1651*05b00f60SXin Li 	return 0;
1652*05b00f60SXin Li }
1653*05b00f60SXin Li 
1654*05b00f60SXin Li static int
handle_deauth(netdissect_options * ndo,const uint8_t * src,const u_char * p,u_int length)1655*05b00f60SXin Li handle_deauth(netdissect_options *ndo,
1656*05b00f60SXin Li 	      const uint8_t *src, const u_char *p, u_int length)
1657*05b00f60SXin Li {
1658*05b00f60SXin Li 	struct mgmt_body_t  pbody;
1659*05b00f60SXin Li 	const char *reason = NULL;
1660*05b00f60SXin Li 
1661*05b00f60SXin Li 	memset(&pbody, 0, sizeof(pbody));
1662*05b00f60SXin Li 
1663*05b00f60SXin Li 	ND_TCHECK_LEN(p, IEEE802_11_REASON_LEN);
1664*05b00f60SXin Li 	if (length < IEEE802_11_REASON_LEN)
1665*05b00f60SXin Li 		goto trunc;
1666*05b00f60SXin Li 	pbody.reason_code = GET_LE_U_2(p);
1667*05b00f60SXin Li 
1668*05b00f60SXin Li 	reason = (pbody.reason_code < NUM_REASONS)
1669*05b00f60SXin Li 			? reason_text[pbody.reason_code]
1670*05b00f60SXin Li 			: "Reserved";
1671*05b00f60SXin Li 
1672*05b00f60SXin Li 	if (ndo->ndo_eflag) {
1673*05b00f60SXin Li 		ND_PRINT(": %s", reason);
1674*05b00f60SXin Li 	} else {
1675*05b00f60SXin Li 		ND_PRINT(" (%s): %s", GET_ETHERADDR_STRING(src), reason);
1676*05b00f60SXin Li 	}
1677*05b00f60SXin Li 	return 1;
1678*05b00f60SXin Li trunc:
1679*05b00f60SXin Li 	return 0;
1680*05b00f60SXin Li }
1681*05b00f60SXin Li 
1682*05b00f60SXin Li #define	PRINT_HT_ACTION(v) (\
1683*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("TxChWidth"): \
1684*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("MIMOPwrSave"): \
1685*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1686*05b00f60SXin Li #define	PRINT_BA_ACTION(v) (\
1687*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("ADDBA Request"): \
1688*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("ADDBA Response"): \
1689*05b00f60SXin Li 	(v) == 2 ? ND_PRINT("DELBA"): \
1690*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1691*05b00f60SXin Li #define	PRINT_MESHLINK_ACTION(v) (\
1692*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("Request"): \
1693*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("Report"): \
1694*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1695*05b00f60SXin Li #define	PRINT_MESHPEERING_ACTION(v) (\
1696*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("Open"): \
1697*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("Confirm"): \
1698*05b00f60SXin Li 	(v) == 2 ? ND_PRINT("Close"): \
1699*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1700*05b00f60SXin Li #define	PRINT_MESHPATH_ACTION(v) (\
1701*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("Request"): \
1702*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("Report"): \
1703*05b00f60SXin Li 	(v) == 2 ? ND_PRINT("Error"): \
1704*05b00f60SXin Li 	(v) == 3 ? ND_PRINT("RootAnnouncement"): \
1705*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1706*05b00f60SXin Li 
1707*05b00f60SXin Li #define PRINT_MESH_ACTION(v) (\
1708*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("MeshLink"): \
1709*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("HWMP"): \
1710*05b00f60SXin Li 	(v) == 2 ? ND_PRINT("Gate Announcement"): \
1711*05b00f60SXin Li 	(v) == 3 ? ND_PRINT("Congestion Control"): \
1712*05b00f60SXin Li 	(v) == 4 ? ND_PRINT("MCCA Setup Request"): \
1713*05b00f60SXin Li 	(v) == 5 ? ND_PRINT("MCCA Setup Reply"): \
1714*05b00f60SXin Li 	(v) == 6 ? ND_PRINT("MCCA Advertisement Request"): \
1715*05b00f60SXin Li 	(v) == 7 ? ND_PRINT("MCCA Advertisement"): \
1716*05b00f60SXin Li 	(v) == 8 ? ND_PRINT("MCCA Teardown"): \
1717*05b00f60SXin Li 	(v) == 9 ? ND_PRINT("TBTT Adjustment Request"): \
1718*05b00f60SXin Li 	(v) == 10 ? ND_PRINT("TBTT Adjustment Response"): \
1719*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1720*05b00f60SXin Li #define PRINT_MULTIHOP_ACTION(v) (\
1721*05b00f60SXin Li 	(v) == 0 ? ND_PRINT("Proxy Update"): \
1722*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("Proxy Update Confirmation"): \
1723*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1724*05b00f60SXin Li #define PRINT_SELFPROT_ACTION(v) (\
1725*05b00f60SXin Li 	(v) == 1 ? ND_PRINT("Peering Open"): \
1726*05b00f60SXin Li 	(v) == 2 ? ND_PRINT("Peering Confirm"): \
1727*05b00f60SXin Li 	(v) == 3 ? ND_PRINT("Peering Close"): \
1728*05b00f60SXin Li 	(v) == 4 ? ND_PRINT("Group Key Inform"): \
1729*05b00f60SXin Li 	(v) == 5 ? ND_PRINT("Group Key Acknowledge"): \
1730*05b00f60SXin Li 		   ND_PRINT("Act#%u", (v)))
1731*05b00f60SXin Li 
1732*05b00f60SXin Li static int
handle_action(netdissect_options * ndo,const uint8_t * src,const u_char * p,u_int length)1733*05b00f60SXin Li handle_action(netdissect_options *ndo,
1734*05b00f60SXin Li 	      const uint8_t *src, const u_char *p, u_int length)
1735*05b00f60SXin Li {
1736*05b00f60SXin Li 	ND_TCHECK_2(p);
1737*05b00f60SXin Li 	if (length < 2)
1738*05b00f60SXin Li 		goto trunc;
1739*05b00f60SXin Li 	if (ndo->ndo_eflag) {
1740*05b00f60SXin Li 		ND_PRINT(": ");
1741*05b00f60SXin Li 	} else {
1742*05b00f60SXin Li 		ND_PRINT(" (%s): ", GET_ETHERADDR_STRING(src));
1743*05b00f60SXin Li 	}
1744*05b00f60SXin Li 	switch (GET_U_1(p)) {
1745*05b00f60SXin Li 	case 0: ND_PRINT("Spectrum Management Act#%u", GET_U_1(p + 1)); break;
1746*05b00f60SXin Li 	case 1: ND_PRINT("QoS Act#%u", GET_U_1(p + 1)); break;
1747*05b00f60SXin Li 	case 2: ND_PRINT("DLS Act#%u", GET_U_1(p + 1)); break;
1748*05b00f60SXin Li 	case 3: ND_PRINT("BA "); PRINT_BA_ACTION(GET_U_1(p + 1)); break;
1749*05b00f60SXin Li 	case 7: ND_PRINT("HT "); PRINT_HT_ACTION(GET_U_1(p + 1)); break;
1750*05b00f60SXin Li 	case 13: ND_PRINT("MeshAction "); PRINT_MESH_ACTION(GET_U_1(p + 1)); break;
1751*05b00f60SXin Li 	case 14:
1752*05b00f60SXin Li 		ND_PRINT("MultiohopAction ");
1753*05b00f60SXin Li 		PRINT_MULTIHOP_ACTION(GET_U_1(p + 1)); break;
1754*05b00f60SXin Li 	case 15:
1755*05b00f60SXin Li 		ND_PRINT("SelfprotectAction ");
1756*05b00f60SXin Li 		PRINT_SELFPROT_ACTION(GET_U_1(p + 1)); break;
1757*05b00f60SXin Li 	case 127: ND_PRINT("Vendor Act#%u", GET_U_1(p + 1)); break;
1758*05b00f60SXin Li 	default:
1759*05b00f60SXin Li 		ND_PRINT("Reserved(%u) Act#%u", GET_U_1(p), GET_U_1(p + 1));
1760*05b00f60SXin Li 		break;
1761*05b00f60SXin Li 	}
1762*05b00f60SXin Li 	return 1;
1763*05b00f60SXin Li trunc:
1764*05b00f60SXin Li 	return 0;
1765*05b00f60SXin Li }
1766*05b00f60SXin Li 
1767*05b00f60SXin Li 
1768*05b00f60SXin Li /*********************************************************************************
1769*05b00f60SXin Li  * Print Body funcs
1770*05b00f60SXin Li  *********************************************************************************/
1771*05b00f60SXin Li 
1772*05b00f60SXin Li 
1773*05b00f60SXin Li static int
mgmt_body_print(netdissect_options * ndo,uint16_t fc,const uint8_t * src,const u_char * p,u_int length)1774*05b00f60SXin Li mgmt_body_print(netdissect_options *ndo,
1775*05b00f60SXin Li 		uint16_t fc, const uint8_t *src, const u_char *p, u_int length)
1776*05b00f60SXin Li {
1777*05b00f60SXin Li 	ND_PRINT("%s", tok2str(st_str, "Unhandled Management subtype(%x)", FC_SUBTYPE(fc)));
1778*05b00f60SXin Li 
1779*05b00f60SXin Li 	/* There may be a problem w/ AP not having this bit set */
1780*05b00f60SXin Li 	if (FC_PROTECTED(fc))
1781*05b00f60SXin Li 		return wep_print(ndo, p);
1782*05b00f60SXin Li 	switch (FC_SUBTYPE(fc)) {
1783*05b00f60SXin Li 	case ST_ASSOC_REQUEST:
1784*05b00f60SXin Li 		return handle_assoc_request(ndo, p, length);
1785*05b00f60SXin Li 	case ST_ASSOC_RESPONSE:
1786*05b00f60SXin Li 		return handle_assoc_response(ndo, p, length);
1787*05b00f60SXin Li 	case ST_REASSOC_REQUEST:
1788*05b00f60SXin Li 		return handle_reassoc_request(ndo, p, length);
1789*05b00f60SXin Li 	case ST_REASSOC_RESPONSE:
1790*05b00f60SXin Li 		return handle_reassoc_response(ndo, p, length);
1791*05b00f60SXin Li 	case ST_PROBE_REQUEST:
1792*05b00f60SXin Li 		return handle_probe_request(ndo, p, length);
1793*05b00f60SXin Li 	case ST_PROBE_RESPONSE:
1794*05b00f60SXin Li 		return handle_probe_response(ndo, p, length);
1795*05b00f60SXin Li 	case ST_BEACON:
1796*05b00f60SXin Li 		return handle_beacon(ndo, p, length);
1797*05b00f60SXin Li 	case ST_ATIM:
1798*05b00f60SXin Li 		return handle_atim();
1799*05b00f60SXin Li 	case ST_DISASSOC:
1800*05b00f60SXin Li 		return handle_disassoc(ndo, p, length);
1801*05b00f60SXin Li 	case ST_AUTH:
1802*05b00f60SXin Li 		return handle_auth(ndo, p, length);
1803*05b00f60SXin Li 	case ST_DEAUTH:
1804*05b00f60SXin Li 		return handle_deauth(ndo, src, p, length);
1805*05b00f60SXin Li 	case ST_ACTION:
1806*05b00f60SXin Li 		return handle_action(ndo, src, p, length);
1807*05b00f60SXin Li 	default:
1808*05b00f60SXin Li 		return 1;
1809*05b00f60SXin Li 	}
1810*05b00f60SXin Li }
1811*05b00f60SXin Li 
1812*05b00f60SXin Li 
1813*05b00f60SXin Li /*********************************************************************************
1814*05b00f60SXin Li  * Handles printing all the control frame types
1815*05b00f60SXin Li  *********************************************************************************/
1816*05b00f60SXin Li 
1817*05b00f60SXin Li static int
ctrl_body_print(netdissect_options * ndo,uint16_t fc,const u_char * p)1818*05b00f60SXin Li ctrl_body_print(netdissect_options *ndo,
1819*05b00f60SXin Li 		uint16_t fc, const u_char *p)
1820*05b00f60SXin Li {
1821*05b00f60SXin Li 	ND_PRINT("%s", tok2str(ctrl_str, "Unknown Ctrl Subtype", FC_SUBTYPE(fc)));
1822*05b00f60SXin Li 	switch (FC_SUBTYPE(fc)) {
1823*05b00f60SXin Li 	case CTRL_CONTROL_WRAPPER:
1824*05b00f60SXin Li 		/* XXX - requires special handling */
1825*05b00f60SXin Li 		break;
1826*05b00f60SXin Li 	case CTRL_BAR:
1827*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_BAR_HDRLEN);
1828*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1829*05b00f60SXin Li 			ND_PRINT(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
1830*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ra),
1831*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ta),
1832*05b00f60SXin Li 			    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->ctl),
1833*05b00f60SXin Li 			    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->seq));
1834*05b00f60SXin Li 		break;
1835*05b00f60SXin Li 	case CTRL_BA:
1836*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_BA_HDRLEN);
1837*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1838*05b00f60SXin Li 			ND_PRINT(" RA:%s ",
1839*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ra));
1840*05b00f60SXin Li 		break;
1841*05b00f60SXin Li 	case CTRL_PS_POLL:
1842*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_PS_POLL_HDRLEN);
1843*05b00f60SXin Li 		ND_PRINT(" AID(%x)",
1844*05b00f60SXin Li 		    GET_LE_U_2(((const struct ctrl_ps_poll_hdr_t *)p)->aid));
1845*05b00f60SXin Li 		break;
1846*05b00f60SXin Li 	case CTRL_RTS:
1847*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_RTS_HDRLEN);
1848*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1849*05b00f60SXin Li 			ND_PRINT(" TA:%s ",
1850*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ta));
1851*05b00f60SXin Li 		break;
1852*05b00f60SXin Li 	case CTRL_CTS:
1853*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_CTS_HDRLEN);
1854*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1855*05b00f60SXin Li 			ND_PRINT(" RA:%s ",
1856*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_cts_hdr_t *)p)->ra));
1857*05b00f60SXin Li 		break;
1858*05b00f60SXin Li 	case CTRL_ACK:
1859*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_ACK_HDRLEN);
1860*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1861*05b00f60SXin Li 			ND_PRINT(" RA:%s ",
1862*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_ack_hdr_t *)p)->ra));
1863*05b00f60SXin Li 		break;
1864*05b00f60SXin Li 	case CTRL_CF_END:
1865*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_END_HDRLEN);
1866*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1867*05b00f60SXin Li 			ND_PRINT(" RA:%s ",
1868*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->ra));
1869*05b00f60SXin Li 		break;
1870*05b00f60SXin Li 	case CTRL_END_ACK:
1871*05b00f60SXin Li 		ND_TCHECK_LEN(p, CTRL_END_ACK_HDRLEN);
1872*05b00f60SXin Li 		if (!ndo->ndo_eflag)
1873*05b00f60SXin Li 			ND_PRINT(" RA:%s ",
1874*05b00f60SXin Li 			    GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->ra));
1875*05b00f60SXin Li 		break;
1876*05b00f60SXin Li 	}
1877*05b00f60SXin Li 	return 1;
1878*05b00f60SXin Li trunc:
1879*05b00f60SXin Li 	return 0;
1880*05b00f60SXin Li }
1881*05b00f60SXin Li 
1882*05b00f60SXin Li /*
1883*05b00f60SXin Li  *  Data Frame - Address field contents
1884*05b00f60SXin Li  *
1885*05b00f60SXin Li  *  To Ds  | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
1886*05b00f60SXin Li  *    0    |  0      |  DA    | SA     | BSSID  | n/a
1887*05b00f60SXin Li  *    0    |  1      |  DA    | BSSID  | SA     | n/a
1888*05b00f60SXin Li  *    1    |  0      |  BSSID | SA     | DA     | n/a
1889*05b00f60SXin Li  *    1    |  1      |  RA    | TA     | DA     | SA
1890*05b00f60SXin Li  */
1891*05b00f60SXin Li 
1892*05b00f60SXin Li /*
1893*05b00f60SXin Li  * Function to get source and destination MAC addresses for a data frame.
1894*05b00f60SXin Li  */
1895*05b00f60SXin Li static void
get_data_src_dst_mac(uint16_t fc,const u_char * p,const uint8_t ** srcp,const uint8_t ** dstp)1896*05b00f60SXin Li get_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp,
1897*05b00f60SXin Li 		     const uint8_t **dstp)
1898*05b00f60SXin Li {
1899*05b00f60SXin Li #define ADDR1  (p + 4)
1900*05b00f60SXin Li #define ADDR2  (p + 10)
1901*05b00f60SXin Li #define ADDR3  (p + 16)
1902*05b00f60SXin Li #define ADDR4  (p + 24)
1903*05b00f60SXin Li 
1904*05b00f60SXin Li 	if (!FC_TO_DS(fc)) {
1905*05b00f60SXin Li 		if (!FC_FROM_DS(fc)) {
1906*05b00f60SXin Li 			/* not To DS and not From DS */
1907*05b00f60SXin Li 			*srcp = ADDR2;
1908*05b00f60SXin Li 			*dstp = ADDR1;
1909*05b00f60SXin Li 		} else {
1910*05b00f60SXin Li 			/* not To DS and From DS */
1911*05b00f60SXin Li 			*srcp = ADDR3;
1912*05b00f60SXin Li 			*dstp = ADDR1;
1913*05b00f60SXin Li 		}
1914*05b00f60SXin Li 	} else {
1915*05b00f60SXin Li 		if (!FC_FROM_DS(fc)) {
1916*05b00f60SXin Li 			/* To DS and not From DS */
1917*05b00f60SXin Li 			*srcp = ADDR2;
1918*05b00f60SXin Li 			*dstp = ADDR3;
1919*05b00f60SXin Li 		} else {
1920*05b00f60SXin Li 			/* To DS and From DS */
1921*05b00f60SXin Li 			*srcp = ADDR4;
1922*05b00f60SXin Li 			*dstp = ADDR3;
1923*05b00f60SXin Li 		}
1924*05b00f60SXin Li 	}
1925*05b00f60SXin Li 
1926*05b00f60SXin Li #undef ADDR1
1927*05b00f60SXin Li #undef ADDR2
1928*05b00f60SXin Li #undef ADDR3
1929*05b00f60SXin Li #undef ADDR4
1930*05b00f60SXin Li }
1931*05b00f60SXin Li 
1932*05b00f60SXin Li static void
get_mgmt_src_dst_mac(const u_char * p,const uint8_t ** srcp,const uint8_t ** dstp)1933*05b00f60SXin Li get_mgmt_src_dst_mac(const u_char *p, const uint8_t **srcp, const uint8_t **dstp)
1934*05b00f60SXin Li {
1935*05b00f60SXin Li 	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
1936*05b00f60SXin Li 
1937*05b00f60SXin Li 	if (srcp != NULL)
1938*05b00f60SXin Li 		*srcp = hp->sa;
1939*05b00f60SXin Li 	if (dstp != NULL)
1940*05b00f60SXin Li 		*dstp = hp->da;
1941*05b00f60SXin Li }
1942*05b00f60SXin Li 
1943*05b00f60SXin Li /*
1944*05b00f60SXin Li  * Print Header funcs
1945*05b00f60SXin Li  */
1946*05b00f60SXin Li 
1947*05b00f60SXin Li static void
data_header_print(netdissect_options * ndo,uint16_t fc,const u_char * p)1948*05b00f60SXin Li data_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
1949*05b00f60SXin Li {
1950*05b00f60SXin Li 	u_int subtype = FC_SUBTYPE(fc);
1951*05b00f60SXin Li 
1952*05b00f60SXin Li 	if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) ||
1953*05b00f60SXin Li 	    DATA_FRAME_IS_QOS(subtype)) {
1954*05b00f60SXin Li 		ND_PRINT("CF ");
1955*05b00f60SXin Li 		if (DATA_FRAME_IS_CF_ACK(subtype)) {
1956*05b00f60SXin Li 			if (DATA_FRAME_IS_CF_POLL(subtype))
1957*05b00f60SXin Li 				ND_PRINT("Ack/Poll");
1958*05b00f60SXin Li 			else
1959*05b00f60SXin Li 				ND_PRINT("Ack");
1960*05b00f60SXin Li 		} else {
1961*05b00f60SXin Li 			if (DATA_FRAME_IS_CF_POLL(subtype))
1962*05b00f60SXin Li 				ND_PRINT("Poll");
1963*05b00f60SXin Li 		}
1964*05b00f60SXin Li 		if (DATA_FRAME_IS_QOS(subtype))
1965*05b00f60SXin Li 			ND_PRINT("+QoS");
1966*05b00f60SXin Li 		ND_PRINT(" ");
1967*05b00f60SXin Li 	}
1968*05b00f60SXin Li 
1969*05b00f60SXin Li #define ADDR1  (p + 4)
1970*05b00f60SXin Li #define ADDR2  (p + 10)
1971*05b00f60SXin Li #define ADDR3  (p + 16)
1972*05b00f60SXin Li #define ADDR4  (p + 24)
1973*05b00f60SXin Li 
1974*05b00f60SXin Li 	if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1975*05b00f60SXin Li 		ND_PRINT("DA:%s SA:%s BSSID:%s ",
1976*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1977*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR3));
1978*05b00f60SXin Li 	} else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1979*05b00f60SXin Li 		ND_PRINT("DA:%s BSSID:%s SA:%s ",
1980*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1981*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR3));
1982*05b00f60SXin Li 	} else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1983*05b00f60SXin Li 		ND_PRINT("BSSID:%s SA:%s DA:%s ",
1984*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1985*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR3));
1986*05b00f60SXin Li 	} else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1987*05b00f60SXin Li 		ND_PRINT("RA:%s TA:%s DA:%s SA:%s ",
1988*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1989*05b00f60SXin Li 		    GET_ETHERADDR_STRING(ADDR3), GET_ETHERADDR_STRING(ADDR4));
1990*05b00f60SXin Li 	}
1991*05b00f60SXin Li 
1992*05b00f60SXin Li #undef ADDR1
1993*05b00f60SXin Li #undef ADDR2
1994*05b00f60SXin Li #undef ADDR3
1995*05b00f60SXin Li #undef ADDR4
1996*05b00f60SXin Li }
1997*05b00f60SXin Li 
1998*05b00f60SXin Li static void
mgmt_header_print(netdissect_options * ndo,const u_char * p)1999*05b00f60SXin Li mgmt_header_print(netdissect_options *ndo, const u_char *p)
2000*05b00f60SXin Li {
2001*05b00f60SXin Li 	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
2002*05b00f60SXin Li 
2003*05b00f60SXin Li 	ND_PRINT("BSSID:%s DA:%s SA:%s ",
2004*05b00f60SXin Li 	    GET_ETHERADDR_STRING((hp)->bssid), GET_ETHERADDR_STRING((hp)->da),
2005*05b00f60SXin Li 	    GET_ETHERADDR_STRING((hp)->sa));
2006*05b00f60SXin Li }
2007*05b00f60SXin Li 
2008*05b00f60SXin Li static void
ctrl_header_print(netdissect_options * ndo,uint16_t fc,const u_char * p)2009*05b00f60SXin Li ctrl_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
2010*05b00f60SXin Li {
2011*05b00f60SXin Li 	switch (FC_SUBTYPE(fc)) {
2012*05b00f60SXin Li 	case CTRL_BAR:
2013*05b00f60SXin Li 		ND_PRINT(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
2014*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ra),
2015*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ta),
2016*05b00f60SXin Li 		    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->ctl),
2017*05b00f60SXin Li 		    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->seq));
2018*05b00f60SXin Li 		break;
2019*05b00f60SXin Li 	case CTRL_BA:
2020*05b00f60SXin Li 		ND_PRINT("RA:%s ",
2021*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ra));
2022*05b00f60SXin Li 		break;
2023*05b00f60SXin Li 	case CTRL_PS_POLL:
2024*05b00f60SXin Li 		ND_PRINT("BSSID:%s TA:%s ",
2025*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_ps_poll_hdr_t *)p)->bssid),
2026*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_ps_poll_hdr_t *)p)->ta));
2027*05b00f60SXin Li 		break;
2028*05b00f60SXin Li 	case CTRL_RTS:
2029*05b00f60SXin Li 		ND_PRINT("RA:%s TA:%s ",
2030*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ra),
2031*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ta));
2032*05b00f60SXin Li 		break;
2033*05b00f60SXin Li 	case CTRL_CTS:
2034*05b00f60SXin Li 		ND_PRINT("RA:%s ",
2035*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_cts_hdr_t *)p)->ra));
2036*05b00f60SXin Li 		break;
2037*05b00f60SXin Li 	case CTRL_ACK:
2038*05b00f60SXin Li 		ND_PRINT("RA:%s ",
2039*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_ack_hdr_t *)p)->ra));
2040*05b00f60SXin Li 		break;
2041*05b00f60SXin Li 	case CTRL_CF_END:
2042*05b00f60SXin Li 		ND_PRINT("RA:%s BSSID:%s ",
2043*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->ra),
2044*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->bssid));
2045*05b00f60SXin Li 		break;
2046*05b00f60SXin Li 	case CTRL_END_ACK:
2047*05b00f60SXin Li 		ND_PRINT("RA:%s BSSID:%s ",
2048*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->ra),
2049*05b00f60SXin Li 		    GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->bssid));
2050*05b00f60SXin Li 		break;
2051*05b00f60SXin Li 	default:
2052*05b00f60SXin Li 		/* We shouldn't get here - we should already have quit */
2053*05b00f60SXin Li 		break;
2054*05b00f60SXin Li 	}
2055*05b00f60SXin Li }
2056*05b00f60SXin Li 
2057*05b00f60SXin Li static int
extract_header_length(netdissect_options * ndo,uint16_t fc)2058*05b00f60SXin Li extract_header_length(netdissect_options *ndo,
2059*05b00f60SXin Li 		      uint16_t fc)
2060*05b00f60SXin Li {
2061*05b00f60SXin Li 	int len;
2062*05b00f60SXin Li 
2063*05b00f60SXin Li 	switch (FC_TYPE(fc)) {
2064*05b00f60SXin Li 	case T_MGMT:
2065*05b00f60SXin Li 		return MGMT_HDRLEN;
2066*05b00f60SXin Li 	case T_CTRL:
2067*05b00f60SXin Li 		switch (FC_SUBTYPE(fc)) {
2068*05b00f60SXin Li 		case CTRL_CONTROL_WRAPPER:
2069*05b00f60SXin Li 			return CTRL_CONTROL_WRAPPER_HDRLEN;
2070*05b00f60SXin Li 		case CTRL_BAR:
2071*05b00f60SXin Li 			return CTRL_BAR_HDRLEN;
2072*05b00f60SXin Li 		case CTRL_BA:
2073*05b00f60SXin Li 			return CTRL_BA_HDRLEN;
2074*05b00f60SXin Li 		case CTRL_PS_POLL:
2075*05b00f60SXin Li 			return CTRL_PS_POLL_HDRLEN;
2076*05b00f60SXin Li 		case CTRL_RTS:
2077*05b00f60SXin Li 			return CTRL_RTS_HDRLEN;
2078*05b00f60SXin Li 		case CTRL_CTS:
2079*05b00f60SXin Li 			return CTRL_CTS_HDRLEN;
2080*05b00f60SXin Li 		case CTRL_ACK:
2081*05b00f60SXin Li 			return CTRL_ACK_HDRLEN;
2082*05b00f60SXin Li 		case CTRL_CF_END:
2083*05b00f60SXin Li 			return CTRL_END_HDRLEN;
2084*05b00f60SXin Li 		case CTRL_END_ACK:
2085*05b00f60SXin Li 			return CTRL_END_ACK_HDRLEN;
2086*05b00f60SXin Li 		default:
2087*05b00f60SXin Li 			ND_PRINT("unknown 802.11 ctrl frame subtype (%u)", FC_SUBTYPE(fc));
2088*05b00f60SXin Li 			return 0;
2089*05b00f60SXin Li 		}
2090*05b00f60SXin Li 	case T_DATA:
2091*05b00f60SXin Li 		len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
2092*05b00f60SXin Li 		if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
2093*05b00f60SXin Li 			len += 2;
2094*05b00f60SXin Li 		return len;
2095*05b00f60SXin Li 	default:
2096*05b00f60SXin Li 		ND_PRINT("unknown 802.11 frame type (%u)", FC_TYPE(fc));
2097*05b00f60SXin Li 		return 0;
2098*05b00f60SXin Li 	}
2099*05b00f60SXin Li }
2100*05b00f60SXin Li 
2101*05b00f60SXin Li static int
extract_mesh_header_length(netdissect_options * ndo,const u_char * p)2102*05b00f60SXin Li extract_mesh_header_length(netdissect_options *ndo, const u_char *p)
2103*05b00f60SXin Li {
2104*05b00f60SXin Li 	return (GET_U_1(p) &~ 3) ? 0 : 6*(1 + (GET_U_1(p) & 3));
2105*05b00f60SXin Li }
2106*05b00f60SXin Li 
2107*05b00f60SXin Li /*
2108*05b00f60SXin Li  * Print the 802.11 MAC header.
2109*05b00f60SXin Li  */
2110*05b00f60SXin Li static void
ieee_802_11_hdr_print(netdissect_options * ndo,uint16_t fc,const u_char * p,u_int hdrlen,u_int meshdrlen)2111*05b00f60SXin Li ieee_802_11_hdr_print(netdissect_options *ndo,
2112*05b00f60SXin Li 		      uint16_t fc, const u_char *p, u_int hdrlen,
2113*05b00f60SXin Li 		      u_int meshdrlen)
2114*05b00f60SXin Li {
2115*05b00f60SXin Li 	if (ndo->ndo_vflag) {
2116*05b00f60SXin Li 		if (FC_MORE_DATA(fc))
2117*05b00f60SXin Li 			ND_PRINT("More Data ");
2118*05b00f60SXin Li 		if (FC_MORE_FLAG(fc))
2119*05b00f60SXin Li 			ND_PRINT("More Fragments ");
2120*05b00f60SXin Li 		if (FC_POWER_MGMT(fc))
2121*05b00f60SXin Li 			ND_PRINT("Pwr Mgmt ");
2122*05b00f60SXin Li 		if (FC_RETRY(fc))
2123*05b00f60SXin Li 			ND_PRINT("Retry ");
2124*05b00f60SXin Li 		if (FC_ORDER(fc))
2125*05b00f60SXin Li 			ND_PRINT("Strictly Ordered ");
2126*05b00f60SXin Li 		if (FC_PROTECTED(fc))
2127*05b00f60SXin Li 			ND_PRINT("Protected ");
2128*05b00f60SXin Li 		if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL)
2129*05b00f60SXin Li 			ND_PRINT("%uus ",
2130*05b00f60SXin Li 			    GET_LE_U_2(((const struct mgmt_header_t *)p)->duration));
2131*05b00f60SXin Li 	}
2132*05b00f60SXin Li 	if (meshdrlen != 0) {
2133*05b00f60SXin Li 		const struct meshcntl_t *mc =
2134*05b00f60SXin Li 		    (const struct meshcntl_t *)(p + hdrlen - meshdrlen);
2135*05b00f60SXin Li 		u_int ae = GET_U_1(mc->flags) & 3;
2136*05b00f60SXin Li 
2137*05b00f60SXin Li 		ND_PRINT("MeshData (AE %u TTL %u seq %u", ae,
2138*05b00f60SXin Li 		    GET_U_1(mc->ttl), GET_LE_U_4(mc->seq));
2139*05b00f60SXin Li 		if (ae > 0)
2140*05b00f60SXin Li 			ND_PRINT(" A4:%s", GET_ETHERADDR_STRING(mc->addr4));
2141*05b00f60SXin Li 		if (ae > 1)
2142*05b00f60SXin Li 			ND_PRINT(" A5:%s", GET_ETHERADDR_STRING(mc->addr5));
2143*05b00f60SXin Li 		if (ae > 2)
2144*05b00f60SXin Li 			ND_PRINT(" A6:%s", GET_ETHERADDR_STRING(mc->addr6));
2145*05b00f60SXin Li 		ND_PRINT(") ");
2146*05b00f60SXin Li 	}
2147*05b00f60SXin Li 
2148*05b00f60SXin Li 	switch (FC_TYPE(fc)) {
2149*05b00f60SXin Li 	case T_MGMT:
2150*05b00f60SXin Li 		mgmt_header_print(ndo, p);
2151*05b00f60SXin Li 		break;
2152*05b00f60SXin Li 	case T_CTRL:
2153*05b00f60SXin Li 		ctrl_header_print(ndo, fc, p);
2154*05b00f60SXin Li 		break;
2155*05b00f60SXin Li 	case T_DATA:
2156*05b00f60SXin Li 		data_header_print(ndo, fc, p);
2157*05b00f60SXin Li 		break;
2158*05b00f60SXin Li 	default:
2159*05b00f60SXin Li 		break;
2160*05b00f60SXin Li 	}
2161*05b00f60SXin Li }
2162*05b00f60SXin Li 
2163*05b00f60SXin Li static u_int
ieee802_11_print(netdissect_options * ndo,const u_char * p,u_int length,u_int orig_caplen,int pad,u_int fcslen)2164*05b00f60SXin Li ieee802_11_print(netdissect_options *ndo,
2165*05b00f60SXin Li 		 const u_char *p, u_int length, u_int orig_caplen, int pad,
2166*05b00f60SXin Li 		 u_int fcslen)
2167*05b00f60SXin Li {
2168*05b00f60SXin Li 	uint16_t fc;
2169*05b00f60SXin Li 	u_int caplen, hdrlen, meshdrlen;
2170*05b00f60SXin Li 	struct lladdr_info src, dst;
2171*05b00f60SXin Li 	int llc_hdrlen;
2172*05b00f60SXin Li 
2173*05b00f60SXin Li 	ndo->ndo_protocol = "802.11";
2174*05b00f60SXin Li 	caplen = orig_caplen;
2175*05b00f60SXin Li 	/* Remove FCS, if present */
2176*05b00f60SXin Li 	if (length < fcslen) {
2177*05b00f60SXin Li 		nd_print_trunc(ndo);
2178*05b00f60SXin Li 		return caplen;
2179*05b00f60SXin Li 	}
2180*05b00f60SXin Li 	length -= fcslen;
2181*05b00f60SXin Li 	if (caplen > length) {
2182*05b00f60SXin Li 		/* Amount of FCS in actual packet data, if any */
2183*05b00f60SXin Li 		fcslen = caplen - length;
2184*05b00f60SXin Li 		caplen -= fcslen;
2185*05b00f60SXin Li 		ndo->ndo_snapend -= fcslen;
2186*05b00f60SXin Li 	}
2187*05b00f60SXin Li 
2188*05b00f60SXin Li 	if (caplen < IEEE802_11_FC_LEN) {
2189*05b00f60SXin Li 		nd_print_trunc(ndo);
2190*05b00f60SXin Li 		return orig_caplen;
2191*05b00f60SXin Li 	}
2192*05b00f60SXin Li 
2193*05b00f60SXin Li 	fc = GET_LE_U_2(p);
2194*05b00f60SXin Li 	hdrlen = extract_header_length(ndo, fc);
2195*05b00f60SXin Li 	if (hdrlen == 0) {
2196*05b00f60SXin Li 		/* Unknown frame type or control frame subtype; quit. */
2197*05b00f60SXin Li 		return (0);
2198*05b00f60SXin Li 	}
2199*05b00f60SXin Li 	if (pad)
2200*05b00f60SXin Li 		hdrlen = roundup2(hdrlen, 4);
2201*05b00f60SXin Li 	if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA &&
2202*05b00f60SXin Li 	    DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
2203*05b00f60SXin Li 		if(!ND_TTEST_1(p + hdrlen)) {
2204*05b00f60SXin Li 			nd_print_trunc(ndo);
2205*05b00f60SXin Li 			return hdrlen;
2206*05b00f60SXin Li 		}
2207*05b00f60SXin Li 		meshdrlen = extract_mesh_header_length(ndo, p + hdrlen);
2208*05b00f60SXin Li 		hdrlen += meshdrlen;
2209*05b00f60SXin Li 	} else
2210*05b00f60SXin Li 		meshdrlen = 0;
2211*05b00f60SXin Li 
2212*05b00f60SXin Li 	if (caplen < hdrlen) {
2213*05b00f60SXin Li 		nd_print_trunc(ndo);
2214*05b00f60SXin Li 		return hdrlen;
2215*05b00f60SXin Li 	}
2216*05b00f60SXin Li 
2217*05b00f60SXin Li 	if (ndo->ndo_eflag)
2218*05b00f60SXin Li 		ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen);
2219*05b00f60SXin Li 
2220*05b00f60SXin Li 	/*
2221*05b00f60SXin Li 	 * Go past the 802.11 header.
2222*05b00f60SXin Li 	 */
2223*05b00f60SXin Li 	length -= hdrlen;
2224*05b00f60SXin Li 	caplen -= hdrlen;
2225*05b00f60SXin Li 	p += hdrlen;
2226*05b00f60SXin Li 
2227*05b00f60SXin Li 	src.addr_string = etheraddr_string;
2228*05b00f60SXin Li 	dst.addr_string = etheraddr_string;
2229*05b00f60SXin Li 	switch (FC_TYPE(fc)) {
2230*05b00f60SXin Li 	case T_MGMT:
2231*05b00f60SXin Li 		get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr);
2232*05b00f60SXin Li 		if (!mgmt_body_print(ndo, fc, src.addr, p, length)) {
2233*05b00f60SXin Li 			nd_print_trunc(ndo);
2234*05b00f60SXin Li 			return hdrlen;
2235*05b00f60SXin Li 		}
2236*05b00f60SXin Li 		break;
2237*05b00f60SXin Li 	case T_CTRL:
2238*05b00f60SXin Li 		if (!ctrl_body_print(ndo, fc, p - hdrlen)) {
2239*05b00f60SXin Li 			nd_print_trunc(ndo);
2240*05b00f60SXin Li 			return hdrlen;
2241*05b00f60SXin Li 		}
2242*05b00f60SXin Li 		break;
2243*05b00f60SXin Li 	case T_DATA:
2244*05b00f60SXin Li 		if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
2245*05b00f60SXin Li 			return hdrlen;	/* no-data frame */
2246*05b00f60SXin Li 		/* There may be a problem w/ AP not having this bit set */
2247*05b00f60SXin Li 		if (FC_PROTECTED(fc)) {
2248*05b00f60SXin Li 			ND_PRINT("Data");
2249*05b00f60SXin Li 			if (!wep_print(ndo, p)) {
2250*05b00f60SXin Li 				nd_print_trunc(ndo);
2251*05b00f60SXin Li 				return hdrlen;
2252*05b00f60SXin Li 			}
2253*05b00f60SXin Li 		} else {
2254*05b00f60SXin Li 			get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr);
2255*05b00f60SXin Li 			llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
2256*05b00f60SXin Li 			if (llc_hdrlen < 0) {
2257*05b00f60SXin Li 				/*
2258*05b00f60SXin Li 				 * Some kinds of LLC packet we cannot
2259*05b00f60SXin Li 				 * handle intelligently
2260*05b00f60SXin Li 				 */
2261*05b00f60SXin Li 				if (!ndo->ndo_suppress_default_print)
2262*05b00f60SXin Li 					ND_DEFAULTPRINT(p, caplen);
2263*05b00f60SXin Li 				llc_hdrlen = -llc_hdrlen;
2264*05b00f60SXin Li 			}
2265*05b00f60SXin Li 			hdrlen += llc_hdrlen;
2266*05b00f60SXin Li 		}
2267*05b00f60SXin Li 		break;
2268*05b00f60SXin Li 	default:
2269*05b00f60SXin Li 		/* We shouldn't get here - we should already have quit */
2270*05b00f60SXin Li 		break;
2271*05b00f60SXin Li 	}
2272*05b00f60SXin Li 
2273*05b00f60SXin Li 	return hdrlen;
2274*05b00f60SXin Li }
2275*05b00f60SXin Li 
2276*05b00f60SXin Li /*
2277*05b00f60SXin Li  * This is the top level routine of the printer.  'p' points
2278*05b00f60SXin Li  * to the 802.11 header of the packet, 'h->ts' is the timestamp,
2279*05b00f60SXin Li  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
2280*05b00f60SXin Li  * is the number of bytes actually captured.
2281*05b00f60SXin Li  */
2282*05b00f60SXin Li void
ieee802_11_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h,const u_char * p)2283*05b00f60SXin Li ieee802_11_if_print(netdissect_options *ndo,
2284*05b00f60SXin Li 		    const struct pcap_pkthdr *h, const u_char *p)
2285*05b00f60SXin Li {
2286*05b00f60SXin Li 	ndo->ndo_protocol = "802.11";
2287*05b00f60SXin Li 	ndo->ndo_ll_hdr_len += ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0);
2288*05b00f60SXin Li }
2289*05b00f60SXin Li 
2290*05b00f60SXin Li 
2291*05b00f60SXin Li /* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
2292*05b00f60SXin Li /* NetBSD: ieee802_11_radio.h,v 1.2 2006/02/26 03:04:03 dyoung Exp  */
2293*05b00f60SXin Li 
2294*05b00f60SXin Li /*-
2295*05b00f60SXin Li  * Copyright (c) 2003, 2004 David Young.  All rights reserved.
2296*05b00f60SXin Li  *
2297*05b00f60SXin Li  * Redistribution and use in source and binary forms, with or without
2298*05b00f60SXin Li  * modification, are permitted provided that the following conditions
2299*05b00f60SXin Li  * are met:
2300*05b00f60SXin Li  * 1. Redistributions of source code must retain the above copyright
2301*05b00f60SXin Li  *    notice, this list of conditions and the following disclaimer.
2302*05b00f60SXin Li  * 2. Redistributions in binary form must reproduce the above copyright
2303*05b00f60SXin Li  *    notice, this list of conditions and the following disclaimer in the
2304*05b00f60SXin Li  *    documentation and/or other materials provided with the distribution.
2305*05b00f60SXin Li  * 3. The name of David Young may not be used to endorse or promote
2306*05b00f60SXin Li  *    products derived from this software without specific prior
2307*05b00f60SXin Li  *    written permission.
2308*05b00f60SXin Li  *
2309*05b00f60SXin Li  * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
2310*05b00f60SXin Li  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2311*05b00f60SXin Li  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2312*05b00f60SXin Li  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
2313*05b00f60SXin Li  * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2314*05b00f60SXin Li  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2315*05b00f60SXin Li  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2316*05b00f60SXin Li  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2317*05b00f60SXin Li  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2318*05b00f60SXin Li  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2319*05b00f60SXin Li  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
2320*05b00f60SXin Li  * OF SUCH DAMAGE.
2321*05b00f60SXin Li  */
2322*05b00f60SXin Li 
2323*05b00f60SXin Li /* A generic radio capture format is desirable. It must be
2324*05b00f60SXin Li  * rigidly defined (e.g., units for fields should be given),
2325*05b00f60SXin Li  * and easily extensible.
2326*05b00f60SXin Li  *
2327*05b00f60SXin Li  * The following is an extensible radio capture format. It is
2328*05b00f60SXin Li  * based on a bitmap indicating which fields are present.
2329*05b00f60SXin Li  *
2330*05b00f60SXin Li  * I am trying to describe precisely what the application programmer
2331*05b00f60SXin Li  * should expect in the following, and for that reason I tell the
2332*05b00f60SXin Li  * units and origin of each measurement (where it applies), or else I
2333*05b00f60SXin Li  * use sufficiently weaselly language ("is a monotonically nondecreasing
2334*05b00f60SXin Li  * function of...") that I cannot set false expectations for lawyerly
2335*05b00f60SXin Li  * readers.
2336*05b00f60SXin Li  */
2337*05b00f60SXin Li 
2338*05b00f60SXin Li /*
2339*05b00f60SXin Li  * The radio capture header precedes the 802.11 header.
2340*05b00f60SXin Li  *
2341*05b00f60SXin Li  * Note well: all radiotap fields are little-endian.
2342*05b00f60SXin Li  */
2343*05b00f60SXin Li struct ieee80211_radiotap_header {
2344*05b00f60SXin Li 	nd_uint8_t	it_version;	/* Version 0. Only increases
2345*05b00f60SXin Li 					 * for drastic changes,
2346*05b00f60SXin Li 					 * introduction of compatible
2347*05b00f60SXin Li 					 * new fields does not count.
2348*05b00f60SXin Li 					 */
2349*05b00f60SXin Li 	nd_uint8_t	it_pad;
2350*05b00f60SXin Li 	nd_uint16_t	it_len;		/* length of the whole
2351*05b00f60SXin Li 					 * header in bytes, including
2352*05b00f60SXin Li 					 * it_version, it_pad,
2353*05b00f60SXin Li 					 * it_len, and data fields.
2354*05b00f60SXin Li 					 */
2355*05b00f60SXin Li 	nd_uint32_t	it_present;	/* A bitmap telling which
2356*05b00f60SXin Li 					 * fields are present. Set bit 31
2357*05b00f60SXin Li 					 * (0x80000000) to extend the
2358*05b00f60SXin Li 					 * bitmap by another 32 bits.
2359*05b00f60SXin Li 					 * Additional extensions are made
2360*05b00f60SXin Li 					 * by setting bit 31.
2361*05b00f60SXin Li 					 */
2362*05b00f60SXin Li };
2363*05b00f60SXin Li 
2364*05b00f60SXin Li /* Name                                 Data type       Units
2365*05b00f60SXin Li  * ----                                 ---------       -----
2366*05b00f60SXin Li  *
2367*05b00f60SXin Li  * IEEE80211_RADIOTAP_TSFT              uint64_t       microseconds
2368*05b00f60SXin Li  *
2369*05b00f60SXin Li  *      Value in microseconds of the MAC's 64-bit 802.11 Time
2370*05b00f60SXin Li  *      Synchronization Function timer when the first bit of the
2371*05b00f60SXin Li  *      MPDU arrived at the MAC. For received frames, only.
2372*05b00f60SXin Li  *
2373*05b00f60SXin Li  * IEEE80211_RADIOTAP_CHANNEL           2 x uint16_t   MHz, bitmap
2374*05b00f60SXin Li  *
2375*05b00f60SXin Li  *      Tx/Rx frequency in MHz, followed by flags (see below).
2376*05b00f60SXin Li  *	Note that IEEE80211_RADIOTAP_XCHANNEL must be used to
2377*05b00f60SXin Li  *	represent an HT channel as there is not enough room in
2378*05b00f60SXin Li  *	the flags word.
2379*05b00f60SXin Li  *
2380*05b00f60SXin Li  * IEEE80211_RADIOTAP_FHSS              uint16_t       see below
2381*05b00f60SXin Li  *
2382*05b00f60SXin Li  *      For frequency-hopping radios, the hop set (first byte)
2383*05b00f60SXin Li  *      and pattern (second byte).
2384*05b00f60SXin Li  *
2385*05b00f60SXin Li  * IEEE80211_RADIOTAP_RATE              uint8_t        500kb/s or index
2386*05b00f60SXin Li  *
2387*05b00f60SXin Li  *      Tx/Rx data rate.  If bit 0x80 is set then it represents an
2388*05b00f60SXin Li  *	an MCS index and not an IEEE rate.
2389*05b00f60SXin Li  *
2390*05b00f60SXin Li  * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     int8_t         decibels from
2391*05b00f60SXin Li  *                                                     one milliwatt (dBm)
2392*05b00f60SXin Li  *
2393*05b00f60SXin Li  *      RF signal power at the antenna, decibel difference from
2394*05b00f60SXin Li  *      one milliwatt.
2395*05b00f60SXin Li  *
2396*05b00f60SXin Li  * IEEE80211_RADIOTAP_DBM_ANTNOISE      int8_t         decibels from
2397*05b00f60SXin Li  *                                                     one milliwatt (dBm)
2398*05b00f60SXin Li  *
2399*05b00f60SXin Li  *      RF noise power at the antenna, decibel difference from one
2400*05b00f60SXin Li  *      milliwatt.
2401*05b00f60SXin Li  *
2402*05b00f60SXin Li  * IEEE80211_RADIOTAP_DB_ANTSIGNAL      uint8_t        decibel (dB)
2403*05b00f60SXin Li  *
2404*05b00f60SXin Li  *      RF signal power at the antenna, decibel difference from an
2405*05b00f60SXin Li  *      arbitrary, fixed reference.
2406*05b00f60SXin Li  *
2407*05b00f60SXin Li  * IEEE80211_RADIOTAP_DB_ANTNOISE       uint8_t        decibel (dB)
2408*05b00f60SXin Li  *
2409*05b00f60SXin Li  *      RF noise power at the antenna, decibel difference from an
2410*05b00f60SXin Li  *      arbitrary, fixed reference point.
2411*05b00f60SXin Li  *
2412*05b00f60SXin Li  * IEEE80211_RADIOTAP_LOCK_QUALITY      uint16_t       unitless
2413*05b00f60SXin Li  *
2414*05b00f60SXin Li  *      Quality of Barker code lock. Unitless. Monotonically
2415*05b00f60SXin Li  *      nondecreasing with "better" lock strength. Called "Signal
2416*05b00f60SXin Li  *      Quality" in datasheets.  (Is there a standard way to measure
2417*05b00f60SXin Li  *      this?)
2418*05b00f60SXin Li  *
2419*05b00f60SXin Li  * IEEE80211_RADIOTAP_TX_ATTENUATION    uint16_t       unitless
2420*05b00f60SXin Li  *
2421*05b00f60SXin Li  *      Transmit power expressed as unitless distance from max
2422*05b00f60SXin Li  *      power set at factory calibration.  0 is max power.
2423*05b00f60SXin Li  *      Monotonically nondecreasing with lower power levels.
2424*05b00f60SXin Li  *
2425*05b00f60SXin Li  * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t       decibels (dB)
2426*05b00f60SXin Li  *
2427*05b00f60SXin Li  *      Transmit power expressed as decibel distance from max power
2428*05b00f60SXin Li  *      set at factory calibration.  0 is max power.  Monotonically
2429*05b00f60SXin Li  *      nondecreasing with lower power levels.
2430*05b00f60SXin Li  *
2431*05b00f60SXin Li  * IEEE80211_RADIOTAP_DBM_TX_POWER      int8_t         decibels from
2432*05b00f60SXin Li  *                                                     one milliwatt (dBm)
2433*05b00f60SXin Li  *
2434*05b00f60SXin Li  *      Transmit power expressed as dBm (decibels from a 1 milliwatt
2435*05b00f60SXin Li  *      reference). This is the absolute power level measured at
2436*05b00f60SXin Li  *      the antenna port.
2437*05b00f60SXin Li  *
2438*05b00f60SXin Li  * IEEE80211_RADIOTAP_FLAGS             uint8_t        bitmap
2439*05b00f60SXin Li  *
2440*05b00f60SXin Li  *      Properties of transmitted and received frames. See flags
2441*05b00f60SXin Li  *      defined below.
2442*05b00f60SXin Li  *
2443*05b00f60SXin Li  * IEEE80211_RADIOTAP_ANTENNA           uint8_t        antenna index
2444*05b00f60SXin Li  *
2445*05b00f60SXin Li  *      Unitless indication of the Rx/Tx antenna for this packet.
2446*05b00f60SXin Li  *      The first antenna is antenna 0.
2447*05b00f60SXin Li  *
2448*05b00f60SXin Li  * IEEE80211_RADIOTAP_RX_FLAGS          uint16_t       bitmap
2449*05b00f60SXin Li  *
2450*05b00f60SXin Li  *     Properties of received frames. See flags defined below.
2451*05b00f60SXin Li  *
2452*05b00f60SXin Li  * IEEE80211_RADIOTAP_XCHANNEL          uint32_t       bitmap
2453*05b00f60SXin Li  *					uint16_t       MHz
2454*05b00f60SXin Li  *					uint8_t        channel number
2455*05b00f60SXin Li  *					uint8_t        .5 dBm
2456*05b00f60SXin Li  *
2457*05b00f60SXin Li  *	Extended channel specification: flags (see below) followed by
2458*05b00f60SXin Li  *	frequency in MHz, the corresponding IEEE channel number, and
2459*05b00f60SXin Li  *	finally the maximum regulatory transmit power cap in .5 dBm
2460*05b00f60SXin Li  *	units.  This property supersedes IEEE80211_RADIOTAP_CHANNEL
2461*05b00f60SXin Li  *	and only one of the two should be present.
2462*05b00f60SXin Li  *
2463*05b00f60SXin Li  * IEEE80211_RADIOTAP_MCS		uint8_t        known
2464*05b00f60SXin Li  *					uint8_t        flags
2465*05b00f60SXin Li  *					uint8_t        mcs
2466*05b00f60SXin Li  *
2467*05b00f60SXin Li  *	Bitset indicating which fields have known values, followed
2468*05b00f60SXin Li  *	by bitset of flag values, followed by the MCS rate index as
2469*05b00f60SXin Li  *	in IEEE 802.11n.
2470*05b00f60SXin Li  *
2471*05b00f60SXin Li  *
2472*05b00f60SXin Li  * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless
2473*05b00f60SXin Li  *
2474*05b00f60SXin Li  *	Contains the AMPDU information for the subframe.
2475*05b00f60SXin Li  *
2476*05b00f60SXin Li  * IEEE80211_RADIOTAP_VHT	u16, u8, u8, u8[4], u8, u8, u16
2477*05b00f60SXin Li  *
2478*05b00f60SXin Li  *	Contains VHT information about this frame.
2479*05b00f60SXin Li  *
2480*05b00f60SXin Li  * IEEE80211_RADIOTAP_VENDOR_NAMESPACE
2481*05b00f60SXin Li  *					uint8_t  OUI[3]
2482*05b00f60SXin Li  *                                      uint8_t        subspace
2483*05b00f60SXin Li  *                                      uint16_t       length
2484*05b00f60SXin Li  *
2485*05b00f60SXin Li  *     The Vendor Namespace Field contains three sub-fields. The first
2486*05b00f60SXin Li  *     sub-field is 3 bytes long. It contains the vendor's IEEE 802
2487*05b00f60SXin Li  *     Organizationally Unique Identifier (OUI). The fourth byte is a
2488*05b00f60SXin Li  *     vendor-specific "namespace selector."
2489*05b00f60SXin Li  *
2490*05b00f60SXin Li  */
2491*05b00f60SXin Li enum ieee80211_radiotap_type {
2492*05b00f60SXin Li 	IEEE80211_RADIOTAP_TSFT = 0,
2493*05b00f60SXin Li 	IEEE80211_RADIOTAP_FLAGS = 1,
2494*05b00f60SXin Li 	IEEE80211_RADIOTAP_RATE = 2,
2495*05b00f60SXin Li 	IEEE80211_RADIOTAP_CHANNEL = 3,
2496*05b00f60SXin Li 	IEEE80211_RADIOTAP_FHSS = 4,
2497*05b00f60SXin Li 	IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
2498*05b00f60SXin Li 	IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
2499*05b00f60SXin Li 	IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
2500*05b00f60SXin Li 	IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
2501*05b00f60SXin Li 	IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
2502*05b00f60SXin Li 	IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
2503*05b00f60SXin Li 	IEEE80211_RADIOTAP_ANTENNA = 11,
2504*05b00f60SXin Li 	IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
2505*05b00f60SXin Li 	IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
2506*05b00f60SXin Li 	IEEE80211_RADIOTAP_RX_FLAGS = 14,
2507*05b00f60SXin Li 	/* NB: gap for netbsd definitions */
2508*05b00f60SXin Li 	IEEE80211_RADIOTAP_XCHANNEL = 18,
2509*05b00f60SXin Li 	IEEE80211_RADIOTAP_MCS = 19,
2510*05b00f60SXin Li 	IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
2511*05b00f60SXin Li 	IEEE80211_RADIOTAP_VHT = 21,
2512*05b00f60SXin Li 	IEEE80211_RADIOTAP_NAMESPACE = 29,
2513*05b00f60SXin Li 	IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
2514*05b00f60SXin Li 	IEEE80211_RADIOTAP_EXT = 31
2515*05b00f60SXin Li };
2516*05b00f60SXin Li 
2517*05b00f60SXin Li /* channel attributes */
2518*05b00f60SXin Li #define	IEEE80211_CHAN_TURBO	0x00010	/* Turbo channel */
2519*05b00f60SXin Li #define	IEEE80211_CHAN_CCK	0x00020	/* CCK channel */
2520*05b00f60SXin Li #define	IEEE80211_CHAN_OFDM	0x00040	/* OFDM channel */
2521*05b00f60SXin Li #define	IEEE80211_CHAN_2GHZ	0x00080	/* 2 GHz spectrum channel. */
2522*05b00f60SXin Li #define	IEEE80211_CHAN_5GHZ	0x00100	/* 5 GHz spectrum channel */
2523*05b00f60SXin Li #define	IEEE80211_CHAN_PASSIVE	0x00200	/* Only passive scan allowed */
2524*05b00f60SXin Li #define	IEEE80211_CHAN_DYN	0x00400	/* Dynamic CCK-OFDM channel */
2525*05b00f60SXin Li #define	IEEE80211_CHAN_GFSK	0x00800	/* GFSK channel (FHSS PHY) */
2526*05b00f60SXin Li #define	IEEE80211_CHAN_GSM	0x01000	/* 900 MHz spectrum channel */
2527*05b00f60SXin Li #define	IEEE80211_CHAN_STURBO	0x02000	/* 11a static turbo channel only */
2528*05b00f60SXin Li #define	IEEE80211_CHAN_HALF	0x04000	/* Half rate channel */
2529*05b00f60SXin Li #define	IEEE80211_CHAN_QUARTER	0x08000	/* Quarter rate channel */
2530*05b00f60SXin Li #define	IEEE80211_CHAN_HT20	0x10000	/* HT 20 channel */
2531*05b00f60SXin Li #define	IEEE80211_CHAN_HT40U	0x20000	/* HT 40 channel w/ ext above */
2532*05b00f60SXin Li #define	IEEE80211_CHAN_HT40D	0x40000	/* HT 40 channel w/ ext below */
2533*05b00f60SXin Li 
2534*05b00f60SXin Li /* Useful combinations of channel characteristics, borrowed from Ethereal */
2535*05b00f60SXin Li #define IEEE80211_CHAN_A \
2536*05b00f60SXin Li 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
2537*05b00f60SXin Li #define IEEE80211_CHAN_B \
2538*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
2539*05b00f60SXin Li #define IEEE80211_CHAN_G \
2540*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2541*05b00f60SXin Li #define IEEE80211_CHAN_TA \
2542*05b00f60SXin Li 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
2543*05b00f60SXin Li #define IEEE80211_CHAN_TG \
2544*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN  | IEEE80211_CHAN_TURBO)
2545*05b00f60SXin Li 
2546*05b00f60SXin Li 
2547*05b00f60SXin Li /* For IEEE80211_RADIOTAP_FLAGS */
2548*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
2549*05b00f60SXin Li 						 * during CFP
2550*05b00f60SXin Li 						 */
2551*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
2552*05b00f60SXin Li 						 * with short
2553*05b00f60SXin Li 						 * preamble
2554*05b00f60SXin Li 						 */
2555*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
2556*05b00f60SXin Li 						 * with WEP encryption
2557*05b00f60SXin Li 						 */
2558*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
2559*05b00f60SXin Li 						 * with fragmentation
2560*05b00f60SXin Li 						 */
2561*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
2562*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
2563*05b00f60SXin Li 						 * 802.11 header and payload
2564*05b00f60SXin Li 						 * (to 32-bit boundary)
2565*05b00f60SXin Li 						 */
2566*05b00f60SXin Li #define	IEEE80211_RADIOTAP_F_BADFCS	0x40	/* does not pass FCS check */
2567*05b00f60SXin Li 
2568*05b00f60SXin Li /* For IEEE80211_RADIOTAP_RX_FLAGS */
2569*05b00f60SXin Li #define IEEE80211_RADIOTAP_F_RX_BADFCS	0x0001	/* frame failed crc check */
2570*05b00f60SXin Li #define IEEE80211_RADIOTAP_F_RX_PLCP_CRC	0x0002	/* frame failed PLCP CRC check */
2571*05b00f60SXin Li 
2572*05b00f60SXin Li /* For IEEE80211_RADIOTAP_MCS known */
2573*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN		0x01
2574*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN		0x02	/* MCS index field */
2575*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN	0x04
2576*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN		0x08
2577*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN		0x10
2578*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_STBC_KNOWN		0x20
2579*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_NESS_KNOWN		0x40
2580*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_NESS_BIT_1		0x80
2581*05b00f60SXin Li 
2582*05b00f60SXin Li /* For IEEE80211_RADIOTAP_MCS flags */
2583*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK	0x03
2584*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20	0
2585*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_40	1
2586*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20L	2
2587*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20U	3
2588*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_SHORT_GI		0x04 /* short guard interval */
2589*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_HT_GREENFIELD	0x08
2590*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10
2591*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_STBC_MASK	0x60
2592*05b00f60SXin Li #define		IEEE80211_RADIOTAP_MCS_STBC_1	1
2593*05b00f60SXin Li #define		IEEE80211_RADIOTAP_MCS_STBC_2	2
2594*05b00f60SXin Li #define		IEEE80211_RADIOTAP_MCS_STBC_3	3
2595*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT	5
2596*05b00f60SXin Li #define IEEE80211_RADIOTAP_MCS_NESS_BIT_0	0x80
2597*05b00f60SXin Li 
2598*05b00f60SXin Li /* For IEEE80211_RADIOTAP_AMPDU_STATUS */
2599*05b00f60SXin Li #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN		0x0001
2600*05b00f60SXin Li #define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN		0x0002
2601*05b00f60SXin Li #define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN		0x0004
2602*05b00f60SXin Li #define IEEE80211_RADIOTAP_AMPDU_IS_LAST		0x0008
2603*05b00f60SXin Li #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR		0x0010
2604*05b00f60SXin Li #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN	0x0020
2605*05b00f60SXin Li 
2606*05b00f60SXin Li /* For IEEE80211_RADIOTAP_VHT known */
2607*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_STBC_KNOWN			0x0001
2608*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA_KNOWN			0x0002
2609*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN		0x0004
2610*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_SGI_NSYM_DIS_KNOWN		0x0008
2611*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM_KNOWN	0x0010
2612*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_BEAMFORMED_KNOWN			0x0020
2613*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN			0x0040
2614*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_GROUP_ID_KNOWN			0x0080
2615*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_PARTIAL_AID_KNOWN		0x0100
2616*05b00f60SXin Li 
2617*05b00f60SXin Li /* For IEEE80211_RADIOTAP_VHT flags */
2618*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_STBC			0x01
2619*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA		0x02
2620*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_SHORT_GI			0x04
2621*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_SGI_NSYM_M10_9		0x08
2622*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM	0x10
2623*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_BEAMFORMED		0x20
2624*05b00f60SXin Li 
2625*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK	0x1f
2626*05b00f60SXin Li 
2627*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_NSS_MASK		0x0f
2628*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_MCS_MASK		0xf0
2629*05b00f60SXin Li #define IEEE80211_RADIOTAP_VHT_MCS_SHIFT	4
2630*05b00f60SXin Li 
2631*05b00f60SXin Li #define IEEE80211_RADIOTAP_CODING_LDPC_USERn			0x01
2632*05b00f60SXin Li 
2633*05b00f60SXin Li #define	IEEE80211_CHAN_FHSS \
2634*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
2635*05b00f60SXin Li #define	IEEE80211_CHAN_A \
2636*05b00f60SXin Li 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
2637*05b00f60SXin Li #define	IEEE80211_CHAN_B \
2638*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
2639*05b00f60SXin Li #define	IEEE80211_CHAN_PUREG \
2640*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
2641*05b00f60SXin Li #define	IEEE80211_CHAN_G \
2642*05b00f60SXin Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2643*05b00f60SXin Li 
2644*05b00f60SXin Li #define	IS_CHAN_FHSS(flags) \
2645*05b00f60SXin Li 	((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
2646*05b00f60SXin Li #define	IS_CHAN_A(flags) \
2647*05b00f60SXin Li 	((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
2648*05b00f60SXin Li #define	IS_CHAN_B(flags) \
2649*05b00f60SXin Li 	((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
2650*05b00f60SXin Li #define	IS_CHAN_PUREG(flags) \
2651*05b00f60SXin Li 	((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
2652*05b00f60SXin Li #define	IS_CHAN_G(flags) \
2653*05b00f60SXin Li 	((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
2654*05b00f60SXin Li #define	IS_CHAN_ANYG(flags) \
2655*05b00f60SXin Li 	(IS_CHAN_PUREG(flags) || IS_CHAN_G(flags))
2656*05b00f60SXin Li 
2657*05b00f60SXin Li static void
print_chaninfo(netdissect_options * ndo,uint16_t freq,uint32_t flags,uint32_t presentflags)2658*05b00f60SXin Li print_chaninfo(netdissect_options *ndo,
2659*05b00f60SXin Li 	       uint16_t freq, uint32_t flags, uint32_t presentflags)
2660*05b00f60SXin Li {
2661*05b00f60SXin Li 	ND_PRINT("%u MHz", freq);
2662*05b00f60SXin Li 	if (presentflags & (1 << IEEE80211_RADIOTAP_MCS)) {
2663*05b00f60SXin Li 		/*
2664*05b00f60SXin Li 		 * We have the MCS field, so this is 11n, regardless
2665*05b00f60SXin Li 		 * of what the channel flags say.
2666*05b00f60SXin Li 		 */
2667*05b00f60SXin Li 		ND_PRINT(" 11n");
2668*05b00f60SXin Li 	} else {
2669*05b00f60SXin Li 		if (IS_CHAN_FHSS(flags))
2670*05b00f60SXin Li 			ND_PRINT(" FHSS");
2671*05b00f60SXin Li 		if (IS_CHAN_A(flags)) {
2672*05b00f60SXin Li 			if (flags & IEEE80211_CHAN_HALF)
2673*05b00f60SXin Li 				ND_PRINT(" 11a/10Mhz");
2674*05b00f60SXin Li 			else if (flags & IEEE80211_CHAN_QUARTER)
2675*05b00f60SXin Li 				ND_PRINT(" 11a/5Mhz");
2676*05b00f60SXin Li 			else
2677*05b00f60SXin Li 				ND_PRINT(" 11a");
2678*05b00f60SXin Li 		}
2679*05b00f60SXin Li 		if (IS_CHAN_ANYG(flags)) {
2680*05b00f60SXin Li 			if (flags & IEEE80211_CHAN_HALF)
2681*05b00f60SXin Li 				ND_PRINT(" 11g/10Mhz");
2682*05b00f60SXin Li 			else if (flags & IEEE80211_CHAN_QUARTER)
2683*05b00f60SXin Li 				ND_PRINT(" 11g/5Mhz");
2684*05b00f60SXin Li 			else
2685*05b00f60SXin Li 				ND_PRINT(" 11g");
2686*05b00f60SXin Li 		} else if (IS_CHAN_B(flags))
2687*05b00f60SXin Li 			ND_PRINT(" 11b");
2688*05b00f60SXin Li 		if (flags & IEEE80211_CHAN_TURBO)
2689*05b00f60SXin Li 			ND_PRINT(" Turbo");
2690*05b00f60SXin Li 	}
2691*05b00f60SXin Li 	/*
2692*05b00f60SXin Li 	 * These apply to 11n.
2693*05b00f60SXin Li 	 */
2694*05b00f60SXin Li 	if (flags & IEEE80211_CHAN_HT20)
2695*05b00f60SXin Li 		ND_PRINT(" ht/20");
2696*05b00f60SXin Li 	else if (flags & IEEE80211_CHAN_HT40D)
2697*05b00f60SXin Li 		ND_PRINT(" ht/40-");
2698*05b00f60SXin Li 	else if (flags & IEEE80211_CHAN_HT40U)
2699*05b00f60SXin Li 		ND_PRINT(" ht/40+");
2700*05b00f60SXin Li 	ND_PRINT(" ");
2701*05b00f60SXin Li }
2702*05b00f60SXin Li 
2703*05b00f60SXin Li static int
print_radiotap_field(netdissect_options * ndo,struct cpack_state * s,uint32_t bit,uint8_t * flagsp,uint32_t presentflags)2704*05b00f60SXin Li print_radiotap_field(netdissect_options *ndo,
2705*05b00f60SXin Li 		     struct cpack_state *s, uint32_t bit, uint8_t *flagsp,
2706*05b00f60SXin Li 		     uint32_t presentflags)
2707*05b00f60SXin Li {
2708*05b00f60SXin Li 	u_int i;
2709*05b00f60SXin Li 	int rc;
2710*05b00f60SXin Li 
2711*05b00f60SXin Li 	switch (bit) {
2712*05b00f60SXin Li 
2713*05b00f60SXin Li 	case IEEE80211_RADIOTAP_TSFT: {
2714*05b00f60SXin Li 		uint64_t tsft;
2715*05b00f60SXin Li 
2716*05b00f60SXin Li 		rc = nd_cpack_uint64(ndo, s, &tsft);
2717*05b00f60SXin Li 		if (rc != 0)
2718*05b00f60SXin Li 			goto trunc;
2719*05b00f60SXin Li 		ND_PRINT("%" PRIu64 "us tsft ", tsft);
2720*05b00f60SXin Li 		break;
2721*05b00f60SXin Li 		}
2722*05b00f60SXin Li 
2723*05b00f60SXin Li 	case IEEE80211_RADIOTAP_FLAGS: {
2724*05b00f60SXin Li 		uint8_t flagsval;
2725*05b00f60SXin Li 
2726*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &flagsval);
2727*05b00f60SXin Li 		if (rc != 0)
2728*05b00f60SXin Li 			goto trunc;
2729*05b00f60SXin Li 		*flagsp = flagsval;
2730*05b00f60SXin Li 		if (flagsval & IEEE80211_RADIOTAP_F_CFP)
2731*05b00f60SXin Li 			ND_PRINT("cfp ");
2732*05b00f60SXin Li 		if (flagsval & IEEE80211_RADIOTAP_F_SHORTPRE)
2733*05b00f60SXin Li 			ND_PRINT("short preamble ");
2734*05b00f60SXin Li 		if (flagsval & IEEE80211_RADIOTAP_F_WEP)
2735*05b00f60SXin Li 			ND_PRINT("wep ");
2736*05b00f60SXin Li 		if (flagsval & IEEE80211_RADIOTAP_F_FRAG)
2737*05b00f60SXin Li 			ND_PRINT("fragmented ");
2738*05b00f60SXin Li 		if (flagsval & IEEE80211_RADIOTAP_F_BADFCS)
2739*05b00f60SXin Li 			ND_PRINT("bad-fcs ");
2740*05b00f60SXin Li 		break;
2741*05b00f60SXin Li 		}
2742*05b00f60SXin Li 
2743*05b00f60SXin Li 	case IEEE80211_RADIOTAP_RATE: {
2744*05b00f60SXin Li 		uint8_t rate;
2745*05b00f60SXin Li 
2746*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &rate);
2747*05b00f60SXin Li 		if (rc != 0)
2748*05b00f60SXin Li 			goto trunc;
2749*05b00f60SXin Li 		/*
2750*05b00f60SXin Li 		 * XXX On FreeBSD rate & 0x80 means we have an MCS. On
2751*05b00f60SXin Li 		 * Linux and AirPcap it does not.  (What about
2752*05b00f60SXin Li 		 * macOS, NetBSD, OpenBSD, and DragonFly BSD?)
2753*05b00f60SXin Li 		 *
2754*05b00f60SXin Li 		 * This is an issue either for proprietary extensions
2755*05b00f60SXin Li 		 * to 11a or 11g, which do exist, or for 11n
2756*05b00f60SXin Li 		 * implementations that stuff a rate value into
2757*05b00f60SXin Li 		 * this field, which also appear to exist.
2758*05b00f60SXin Li 		 *
2759*05b00f60SXin Li 		 * We currently handle that by assuming that
2760*05b00f60SXin Li 		 * if the 0x80 bit is set *and* the remaining
2761*05b00f60SXin Li 		 * bits have a value between 0 and 15 it's
2762*05b00f60SXin Li 		 * an MCS value, otherwise it's a rate.  If
2763*05b00f60SXin Li 		 * there are cases where systems that use
2764*05b00f60SXin Li 		 * "0x80 + MCS index" for MCS indices > 15,
2765*05b00f60SXin Li 		 * or stuff a rate value here between 64 and
2766*05b00f60SXin Li 		 * 71.5 Mb/s in here, we'll need a preference
2767*05b00f60SXin Li 		 * setting.  Such rates do exist, e.g. 11n
2768*05b00f60SXin Li 		 * MCS 7 at 20 MHz with a long guard interval.
2769*05b00f60SXin Li 		 */
2770*05b00f60SXin Li 		if (rate >= 0x80 && rate <= 0x8f) {
2771*05b00f60SXin Li 			/*
2772*05b00f60SXin Li 			 * XXX - we don't know the channel width
2773*05b00f60SXin Li 			 * or guard interval length, so we can't
2774*05b00f60SXin Li 			 * convert this to a data rate.
2775*05b00f60SXin Li 			 *
2776*05b00f60SXin Li 			 * If you want us to show a data rate,
2777*05b00f60SXin Li 			 * use the MCS field, not the Rate field;
2778*05b00f60SXin Li 			 * the MCS field includes not only the
2779*05b00f60SXin Li 			 * MCS index, it also includes bandwidth
2780*05b00f60SXin Li 			 * and guard interval information.
2781*05b00f60SXin Li 			 *
2782*05b00f60SXin Li 			 * XXX - can we get the channel width
2783*05b00f60SXin Li 			 * from XChannel and the guard interval
2784*05b00f60SXin Li 			 * information from Flags, at least on
2785*05b00f60SXin Li 			 * FreeBSD?
2786*05b00f60SXin Li 			 */
2787*05b00f60SXin Li 			ND_PRINT("MCS %u ", rate & 0x7f);
2788*05b00f60SXin Li 		} else
2789*05b00f60SXin Li 			ND_PRINT("%2.1f Mb/s ", .5 * rate);
2790*05b00f60SXin Li 		break;
2791*05b00f60SXin Li 		}
2792*05b00f60SXin Li 
2793*05b00f60SXin Li 	case IEEE80211_RADIOTAP_CHANNEL: {
2794*05b00f60SXin Li 		uint16_t frequency;
2795*05b00f60SXin Li 		uint16_t flags;
2796*05b00f60SXin Li 
2797*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &frequency);
2798*05b00f60SXin Li 		if (rc != 0)
2799*05b00f60SXin Li 			goto trunc;
2800*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &flags);
2801*05b00f60SXin Li 		if (rc != 0)
2802*05b00f60SXin Li 			goto trunc;
2803*05b00f60SXin Li 		/*
2804*05b00f60SXin Li 		 * If CHANNEL and XCHANNEL are both present, skip
2805*05b00f60SXin Li 		 * CHANNEL.
2806*05b00f60SXin Li 		 */
2807*05b00f60SXin Li 		if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL))
2808*05b00f60SXin Li 			break;
2809*05b00f60SXin Li 		print_chaninfo(ndo, frequency, flags, presentflags);
2810*05b00f60SXin Li 		break;
2811*05b00f60SXin Li 		}
2812*05b00f60SXin Li 
2813*05b00f60SXin Li 	case IEEE80211_RADIOTAP_FHSS: {
2814*05b00f60SXin Li 		uint8_t hopset;
2815*05b00f60SXin Li 		uint8_t hoppat;
2816*05b00f60SXin Li 
2817*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &hopset);
2818*05b00f60SXin Li 		if (rc != 0)
2819*05b00f60SXin Li 			goto trunc;
2820*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &hoppat);
2821*05b00f60SXin Li 		if (rc != 0)
2822*05b00f60SXin Li 			goto trunc;
2823*05b00f60SXin Li 		ND_PRINT("fhset %u fhpat %u ", hopset, hoppat);
2824*05b00f60SXin Li 		break;
2825*05b00f60SXin Li 		}
2826*05b00f60SXin Li 
2827*05b00f60SXin Li 	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: {
2828*05b00f60SXin Li 		int8_t dbm_antsignal;
2829*05b00f60SXin Li 
2830*05b00f60SXin Li 		rc = nd_cpack_int8(ndo, s, &dbm_antsignal);
2831*05b00f60SXin Li 		if (rc != 0)
2832*05b00f60SXin Li 			goto trunc;
2833*05b00f60SXin Li 		ND_PRINT("%ddBm signal ", dbm_antsignal);
2834*05b00f60SXin Li 		break;
2835*05b00f60SXin Li 		}
2836*05b00f60SXin Li 
2837*05b00f60SXin Li 	case IEEE80211_RADIOTAP_DBM_ANTNOISE: {
2838*05b00f60SXin Li 		int8_t dbm_antnoise;
2839*05b00f60SXin Li 
2840*05b00f60SXin Li 		rc = nd_cpack_int8(ndo, s, &dbm_antnoise);
2841*05b00f60SXin Li 		if (rc != 0)
2842*05b00f60SXin Li 			goto trunc;
2843*05b00f60SXin Li 		ND_PRINT("%ddBm noise ", dbm_antnoise);
2844*05b00f60SXin Li 		break;
2845*05b00f60SXin Li 		}
2846*05b00f60SXin Li 
2847*05b00f60SXin Li 	case IEEE80211_RADIOTAP_LOCK_QUALITY: {
2848*05b00f60SXin Li 		uint16_t lock_quality;
2849*05b00f60SXin Li 
2850*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &lock_quality);
2851*05b00f60SXin Li 		if (rc != 0)
2852*05b00f60SXin Li 			goto trunc;
2853*05b00f60SXin Li 		ND_PRINT("%u sq ", lock_quality);
2854*05b00f60SXin Li 		break;
2855*05b00f60SXin Li 		}
2856*05b00f60SXin Li 
2857*05b00f60SXin Li 	case IEEE80211_RADIOTAP_TX_ATTENUATION: {
2858*05b00f60SXin Li 		int16_t tx_attenuation;
2859*05b00f60SXin Li 
2860*05b00f60SXin Li 		rc = nd_cpack_int16(ndo, s, &tx_attenuation);
2861*05b00f60SXin Li 		if (rc != 0)
2862*05b00f60SXin Li 			goto trunc;
2863*05b00f60SXin Li 		ND_PRINT("%d tx power ", -tx_attenuation);
2864*05b00f60SXin Li 		break;
2865*05b00f60SXin Li 		}
2866*05b00f60SXin Li 
2867*05b00f60SXin Li 	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: {
2868*05b00f60SXin Li 		int8_t db_tx_attenuation;
2869*05b00f60SXin Li 
2870*05b00f60SXin Li 		rc = nd_cpack_int8(ndo, s, &db_tx_attenuation);
2871*05b00f60SXin Li 		if (rc != 0)
2872*05b00f60SXin Li 			goto trunc;
2873*05b00f60SXin Li 		ND_PRINT("%ddB tx attenuation ", -db_tx_attenuation);
2874*05b00f60SXin Li 		break;
2875*05b00f60SXin Li 		}
2876*05b00f60SXin Li 
2877*05b00f60SXin Li 	case IEEE80211_RADIOTAP_DBM_TX_POWER: {
2878*05b00f60SXin Li 		int8_t dbm_tx_power;
2879*05b00f60SXin Li 
2880*05b00f60SXin Li 		rc = nd_cpack_int8(ndo, s, &dbm_tx_power);
2881*05b00f60SXin Li 		if (rc != 0)
2882*05b00f60SXin Li 			goto trunc;
2883*05b00f60SXin Li 		ND_PRINT("%ddBm tx power ", dbm_tx_power);
2884*05b00f60SXin Li 		break;
2885*05b00f60SXin Li 		}
2886*05b00f60SXin Li 
2887*05b00f60SXin Li 	case IEEE80211_RADIOTAP_ANTENNA: {
2888*05b00f60SXin Li 		uint8_t antenna;
2889*05b00f60SXin Li 
2890*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &antenna);
2891*05b00f60SXin Li 		if (rc != 0)
2892*05b00f60SXin Li 			goto trunc;
2893*05b00f60SXin Li 		ND_PRINT("antenna %u ", antenna);
2894*05b00f60SXin Li 		break;
2895*05b00f60SXin Li 		}
2896*05b00f60SXin Li 
2897*05b00f60SXin Li 	case IEEE80211_RADIOTAP_DB_ANTSIGNAL: {
2898*05b00f60SXin Li 		uint8_t db_antsignal;
2899*05b00f60SXin Li 
2900*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &db_antsignal);
2901*05b00f60SXin Li 		if (rc != 0)
2902*05b00f60SXin Li 			goto trunc;
2903*05b00f60SXin Li 		ND_PRINT("%udB signal ", db_antsignal);
2904*05b00f60SXin Li 		break;
2905*05b00f60SXin Li 		}
2906*05b00f60SXin Li 
2907*05b00f60SXin Li 	case IEEE80211_RADIOTAP_DB_ANTNOISE: {
2908*05b00f60SXin Li 		uint8_t db_antnoise;
2909*05b00f60SXin Li 
2910*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &db_antnoise);
2911*05b00f60SXin Li 		if (rc != 0)
2912*05b00f60SXin Li 			goto trunc;
2913*05b00f60SXin Li 		ND_PRINT("%udB noise ", db_antnoise);
2914*05b00f60SXin Li 		break;
2915*05b00f60SXin Li 		}
2916*05b00f60SXin Li 
2917*05b00f60SXin Li 	case IEEE80211_RADIOTAP_RX_FLAGS: {
2918*05b00f60SXin Li 		uint16_t rx_flags;
2919*05b00f60SXin Li 
2920*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &rx_flags);
2921*05b00f60SXin Li 		if (rc != 0)
2922*05b00f60SXin Li 			goto trunc;
2923*05b00f60SXin Li 		/* Do nothing for now */
2924*05b00f60SXin Li 		break;
2925*05b00f60SXin Li 		}
2926*05b00f60SXin Li 
2927*05b00f60SXin Li 	case IEEE80211_RADIOTAP_XCHANNEL: {
2928*05b00f60SXin Li 		uint32_t flags;
2929*05b00f60SXin Li 		uint16_t frequency;
2930*05b00f60SXin Li 		uint8_t channel;
2931*05b00f60SXin Li 		uint8_t maxpower;
2932*05b00f60SXin Li 
2933*05b00f60SXin Li 		rc = nd_cpack_uint32(ndo, s, &flags);
2934*05b00f60SXin Li 		if (rc != 0)
2935*05b00f60SXin Li 			goto trunc;
2936*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &frequency);
2937*05b00f60SXin Li 		if (rc != 0)
2938*05b00f60SXin Li 			goto trunc;
2939*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &channel);
2940*05b00f60SXin Li 		if (rc != 0)
2941*05b00f60SXin Li 			goto trunc;
2942*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &maxpower);
2943*05b00f60SXin Li 		if (rc != 0)
2944*05b00f60SXin Li 			goto trunc;
2945*05b00f60SXin Li 		print_chaninfo(ndo, frequency, flags, presentflags);
2946*05b00f60SXin Li 		break;
2947*05b00f60SXin Li 		}
2948*05b00f60SXin Li 
2949*05b00f60SXin Li 	case IEEE80211_RADIOTAP_MCS: {
2950*05b00f60SXin Li 		uint8_t known;
2951*05b00f60SXin Li 		uint8_t flags;
2952*05b00f60SXin Li 		uint8_t mcs_index;
2953*05b00f60SXin Li 		static const char *ht_bandwidth[4] = {
2954*05b00f60SXin Li 			"20 MHz",
2955*05b00f60SXin Li 			"40 MHz",
2956*05b00f60SXin Li 			"20 MHz (L)",
2957*05b00f60SXin Li 			"20 MHz (U)"
2958*05b00f60SXin Li 		};
2959*05b00f60SXin Li 		float htrate;
2960*05b00f60SXin Li 
2961*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &known);
2962*05b00f60SXin Li 		if (rc != 0)
2963*05b00f60SXin Li 			goto trunc;
2964*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &flags);
2965*05b00f60SXin Li 		if (rc != 0)
2966*05b00f60SXin Li 			goto trunc;
2967*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &mcs_index);
2968*05b00f60SXin Li 		if (rc != 0)
2969*05b00f60SXin Li 			goto trunc;
2970*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) {
2971*05b00f60SXin Li 			/*
2972*05b00f60SXin Li 			 * We know the MCS index.
2973*05b00f60SXin Li 			 */
2974*05b00f60SXin Li 			if (mcs_index <= MAX_MCS_INDEX) {
2975*05b00f60SXin Li 				/*
2976*05b00f60SXin Li 				 * And it's in-range.
2977*05b00f60SXin Li 				 */
2978*05b00f60SXin Li 				if (known & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) {
2979*05b00f60SXin Li 					/*
2980*05b00f60SXin Li 					 * And we know both the bandwidth and
2981*05b00f60SXin Li 					 * the guard interval, so we can look
2982*05b00f60SXin Li 					 * up the rate.
2983*05b00f60SXin Li 					 */
2984*05b00f60SXin Li 					htrate =
2985*05b00f60SXin Li 						ieee80211_float_htrates
2986*05b00f60SXin Li 							[mcs_index]
2987*05b00f60SXin Li 							[((flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)]
2988*05b00f60SXin Li 							[((flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)];
2989*05b00f60SXin Li 				} else {
2990*05b00f60SXin Li 					/*
2991*05b00f60SXin Li 					 * We don't know both the bandwidth
2992*05b00f60SXin Li 					 * and the guard interval, so we can
2993*05b00f60SXin Li 					 * only report the MCS index.
2994*05b00f60SXin Li 					 */
2995*05b00f60SXin Li 					htrate = 0.0;
2996*05b00f60SXin Li 				}
2997*05b00f60SXin Li 			} else {
2998*05b00f60SXin Li 				/*
2999*05b00f60SXin Li 				 * The MCS value is out of range.
3000*05b00f60SXin Li 				 */
3001*05b00f60SXin Li 				htrate = 0.0;
3002*05b00f60SXin Li 			}
3003*05b00f60SXin Li 			if (htrate != 0.0) {
3004*05b00f60SXin Li 				/*
3005*05b00f60SXin Li 				 * We have the rate.
3006*05b00f60SXin Li 				 * Print it.
3007*05b00f60SXin Li 				 */
3008*05b00f60SXin Li 				ND_PRINT("%.1f Mb/s MCS %u ", htrate, mcs_index);
3009*05b00f60SXin Li 			} else {
3010*05b00f60SXin Li 				/*
3011*05b00f60SXin Li 				 * We at least have the MCS index.
3012*05b00f60SXin Li 				 * Print it.
3013*05b00f60SXin Li 				 */
3014*05b00f60SXin Li 				ND_PRINT("MCS %u ", mcs_index);
3015*05b00f60SXin Li 			}
3016*05b00f60SXin Li 		}
3017*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) {
3018*05b00f60SXin Li 			ND_PRINT("%s ",
3019*05b00f60SXin Li 				ht_bandwidth[flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK]);
3020*05b00f60SXin Li 		}
3021*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) {
3022*05b00f60SXin Li 			ND_PRINT("%s GI ",
3023*05b00f60SXin Li 				(flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ?
3024*05b00f60SXin Li 				"short" : "long");
3025*05b00f60SXin Li 		}
3026*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) {
3027*05b00f60SXin Li 			ND_PRINT("%s ",
3028*05b00f60SXin Li 				(flags & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ?
3029*05b00f60SXin Li 				"greenfield" : "mixed");
3030*05b00f60SXin Li 		}
3031*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) {
3032*05b00f60SXin Li 			ND_PRINT("%s FEC ",
3033*05b00f60SXin Li 				(flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ?
3034*05b00f60SXin Li 				"LDPC" : "BCC");
3035*05b00f60SXin Li 		}
3036*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) {
3037*05b00f60SXin Li 			ND_PRINT("RX-STBC%u ",
3038*05b00f60SXin Li 				(flags & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT);
3039*05b00f60SXin Li 		}
3040*05b00f60SXin Li 		break;
3041*05b00f60SXin Li 		}
3042*05b00f60SXin Li 
3043*05b00f60SXin Li 	case IEEE80211_RADIOTAP_AMPDU_STATUS: {
3044*05b00f60SXin Li 		uint32_t reference_num;
3045*05b00f60SXin Li 		uint16_t flags;
3046*05b00f60SXin Li 		uint8_t delim_crc;
3047*05b00f60SXin Li 		uint8_t reserved;
3048*05b00f60SXin Li 
3049*05b00f60SXin Li 		rc = nd_cpack_uint32(ndo, s, &reference_num);
3050*05b00f60SXin Li 		if (rc != 0)
3051*05b00f60SXin Li 			goto trunc;
3052*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &flags);
3053*05b00f60SXin Li 		if (rc != 0)
3054*05b00f60SXin Li 			goto trunc;
3055*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &delim_crc);
3056*05b00f60SXin Li 		if (rc != 0)
3057*05b00f60SXin Li 			goto trunc;
3058*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &reserved);
3059*05b00f60SXin Li 		if (rc != 0)
3060*05b00f60SXin Li 			goto trunc;
3061*05b00f60SXin Li 		/* Do nothing for now */
3062*05b00f60SXin Li 		break;
3063*05b00f60SXin Li 		}
3064*05b00f60SXin Li 
3065*05b00f60SXin Li 	case IEEE80211_RADIOTAP_VHT: {
3066*05b00f60SXin Li 		uint16_t known;
3067*05b00f60SXin Li 		uint8_t flags;
3068*05b00f60SXin Li 		uint8_t bandwidth;
3069*05b00f60SXin Li 		uint8_t mcs_nss[4];
3070*05b00f60SXin Li 		uint8_t coding;
3071*05b00f60SXin Li 		uint8_t group_id;
3072*05b00f60SXin Li 		uint16_t partial_aid;
3073*05b00f60SXin Li 		static const char *vht_bandwidth[32] = {
3074*05b00f60SXin Li 			"20 MHz",
3075*05b00f60SXin Li 			"40 MHz",
3076*05b00f60SXin Li 			"20 MHz (L)",
3077*05b00f60SXin Li 			"20 MHz (U)",
3078*05b00f60SXin Li 			"80 MHz",
3079*05b00f60SXin Li 			"80 MHz (L)",
3080*05b00f60SXin Li 			"80 MHz (U)",
3081*05b00f60SXin Li 			"80 MHz (LL)",
3082*05b00f60SXin Li 			"80 MHz (LU)",
3083*05b00f60SXin Li 			"80 MHz (UL)",
3084*05b00f60SXin Li 			"80 MHz (UU)",
3085*05b00f60SXin Li 			"160 MHz",
3086*05b00f60SXin Li 			"160 MHz (L)",
3087*05b00f60SXin Li 			"160 MHz (U)",
3088*05b00f60SXin Li 			"160 MHz (LL)",
3089*05b00f60SXin Li 			"160 MHz (LU)",
3090*05b00f60SXin Li 			"160 MHz (UL)",
3091*05b00f60SXin Li 			"160 MHz (UU)",
3092*05b00f60SXin Li 			"160 MHz (LLL)",
3093*05b00f60SXin Li 			"160 MHz (LLU)",
3094*05b00f60SXin Li 			"160 MHz (LUL)",
3095*05b00f60SXin Li 			"160 MHz (UUU)",
3096*05b00f60SXin Li 			"160 MHz (ULL)",
3097*05b00f60SXin Li 			"160 MHz (ULU)",
3098*05b00f60SXin Li 			"160 MHz (UUL)",
3099*05b00f60SXin Li 			"160 MHz (UUU)",
3100*05b00f60SXin Li 			"unknown (26)",
3101*05b00f60SXin Li 			"unknown (27)",
3102*05b00f60SXin Li 			"unknown (28)",
3103*05b00f60SXin Li 			"unknown (29)",
3104*05b00f60SXin Li 			"unknown (30)",
3105*05b00f60SXin Li 			"unknown (31)"
3106*05b00f60SXin Li 		};
3107*05b00f60SXin Li 
3108*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &known);
3109*05b00f60SXin Li 		if (rc != 0)
3110*05b00f60SXin Li 			goto trunc;
3111*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &flags);
3112*05b00f60SXin Li 		if (rc != 0)
3113*05b00f60SXin Li 			goto trunc;
3114*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &bandwidth);
3115*05b00f60SXin Li 		if (rc != 0)
3116*05b00f60SXin Li 			goto trunc;
3117*05b00f60SXin Li 		for (i = 0; i < 4; i++) {
3118*05b00f60SXin Li 			rc = nd_cpack_uint8(ndo, s, &mcs_nss[i]);
3119*05b00f60SXin Li 			if (rc != 0)
3120*05b00f60SXin Li 				goto trunc;
3121*05b00f60SXin Li 		}
3122*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &coding);
3123*05b00f60SXin Li 		if (rc != 0)
3124*05b00f60SXin Li 			goto trunc;
3125*05b00f60SXin Li 		rc = nd_cpack_uint8(ndo, s, &group_id);
3126*05b00f60SXin Li 		if (rc != 0)
3127*05b00f60SXin Li 			goto trunc;
3128*05b00f60SXin Li 		rc = nd_cpack_uint16(ndo, s, &partial_aid);
3129*05b00f60SXin Li 		if (rc != 0)
3130*05b00f60SXin Li 			goto trunc;
3131*05b00f60SXin Li 		for (i = 0; i < 4; i++) {
3132*05b00f60SXin Li 			u_int nss, mcs;
3133*05b00f60SXin Li 			nss = mcs_nss[i] & IEEE80211_RADIOTAP_VHT_NSS_MASK;
3134*05b00f60SXin Li 			mcs = (mcs_nss[i] & IEEE80211_RADIOTAP_VHT_MCS_MASK) >> IEEE80211_RADIOTAP_VHT_MCS_SHIFT;
3135*05b00f60SXin Li 
3136*05b00f60SXin Li 			if (nss == 0)
3137*05b00f60SXin Li 				continue;
3138*05b00f60SXin Li 
3139*05b00f60SXin Li 			ND_PRINT("User %u MCS %u ", i, mcs);
3140*05b00f60SXin Li 			ND_PRINT("%s FEC ",
3141*05b00f60SXin Li 				(coding & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ?
3142*05b00f60SXin Li 				"LDPC" : "BCC");
3143*05b00f60SXin Li 		}
3144*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) {
3145*05b00f60SXin Li 			ND_PRINT("%s ",
3146*05b00f60SXin Li 				vht_bandwidth[bandwidth & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK]);
3147*05b00f60SXin Li 		}
3148*05b00f60SXin Li 		if (known & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) {
3149*05b00f60SXin Li 			ND_PRINT("%s GI ",
3150*05b00f60SXin Li 				(flags & IEEE80211_RADIOTAP_VHT_SHORT_GI) ?
3151*05b00f60SXin Li 				"short" : "long");
3152*05b00f60SXin Li 		}
3153*05b00f60SXin Li 		break;
3154*05b00f60SXin Li 		}
3155*05b00f60SXin Li 
3156*05b00f60SXin Li 	default:
3157*05b00f60SXin Li 		/* this bit indicates a field whose
3158*05b00f60SXin Li 		 * size we do not know, so we cannot
3159*05b00f60SXin Li 		 * proceed.  Just print the bit number.
3160*05b00f60SXin Li 		 */
3161*05b00f60SXin Li 		ND_PRINT("[bit %u] ", bit);
3162*05b00f60SXin Li 		return -1;
3163*05b00f60SXin Li 	}
3164*05b00f60SXin Li 
3165*05b00f60SXin Li 	return 0;
3166*05b00f60SXin Li 
3167*05b00f60SXin Li trunc:
3168*05b00f60SXin Li 	nd_print_trunc(ndo);
3169*05b00f60SXin Li 	return rc;
3170*05b00f60SXin Li }
3171*05b00f60SXin Li 
3172*05b00f60SXin Li 
3173*05b00f60SXin Li static int
print_in_radiotap_namespace(netdissect_options * ndo,struct cpack_state * s,uint8_t * flags,uint32_t presentflags,int bit0)3174*05b00f60SXin Li print_in_radiotap_namespace(netdissect_options *ndo,
3175*05b00f60SXin Li 			    struct cpack_state *s, uint8_t *flags,
3176*05b00f60SXin Li 			    uint32_t presentflags, int bit0)
3177*05b00f60SXin Li {
3178*05b00f60SXin Li #define	BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
3179*05b00f60SXin Li #define	BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
3180*05b00f60SXin Li #define	BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
3181*05b00f60SXin Li #define	BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
3182*05b00f60SXin Li #define	BITNO_2(x) (((x) & 2) ? 1 : 0)
3183*05b00f60SXin Li 	uint32_t present, next_present;
3184*05b00f60SXin Li 	int bitno;
3185*05b00f60SXin Li 	enum ieee80211_radiotap_type bit;
3186*05b00f60SXin Li 	int rc;
3187*05b00f60SXin Li 
3188*05b00f60SXin Li 	for (present = presentflags; present; present = next_present) {
3189*05b00f60SXin Li 		/*
3190*05b00f60SXin Li 		 * Clear the least significant bit that is set.
3191*05b00f60SXin Li 		 */
3192*05b00f60SXin Li 		next_present = present & (present - 1);
3193*05b00f60SXin Li 
3194*05b00f60SXin Li 		/*
3195*05b00f60SXin Li 		 * Get the bit number, within this presence word,
3196*05b00f60SXin Li 		 * of the remaining least significant bit that
3197*05b00f60SXin Li 		 * is set.
3198*05b00f60SXin Li 		 */
3199*05b00f60SXin Li 		bitno = BITNO_32(present ^ next_present);
3200*05b00f60SXin Li 
3201*05b00f60SXin Li 		/*
3202*05b00f60SXin Li 		 * Stop if this is one of the "same meaning
3203*05b00f60SXin Li 		 * in all presence flags" bits.
3204*05b00f60SXin Li 		 */
3205*05b00f60SXin Li 		if (bitno >= IEEE80211_RADIOTAP_NAMESPACE)
3206*05b00f60SXin Li 			break;
3207*05b00f60SXin Li 
3208*05b00f60SXin Li 		/*
3209*05b00f60SXin Li 		 * Get the radiotap bit number of that bit.
3210*05b00f60SXin Li 		 */
3211*05b00f60SXin Li 		bit = (enum ieee80211_radiotap_type)(bit0 + bitno);
3212*05b00f60SXin Li 
3213*05b00f60SXin Li 		rc = print_radiotap_field(ndo, s, bit, flags, presentflags);
3214*05b00f60SXin Li 		if (rc != 0)
3215*05b00f60SXin Li 			return rc;
3216*05b00f60SXin Li 	}
3217*05b00f60SXin Li 
3218*05b00f60SXin Li 	return 0;
3219*05b00f60SXin Li }
3220*05b00f60SXin Li 
3221*05b00f60SXin Li u_int
ieee802_11_radio_print(netdissect_options * ndo,const u_char * p,u_int length,u_int caplen)3222*05b00f60SXin Li ieee802_11_radio_print(netdissect_options *ndo,
3223*05b00f60SXin Li 		       const u_char *p, u_int length, u_int caplen)
3224*05b00f60SXin Li {
3225*05b00f60SXin Li #define	BIT(n)	(1U << n)
3226*05b00f60SXin Li #define	IS_EXTENDED(__p)	\
3227*05b00f60SXin Li 	    (GET_LE_U_4(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
3228*05b00f60SXin Li 
3229*05b00f60SXin Li 	struct cpack_state cpacker;
3230*05b00f60SXin Li 	const struct ieee80211_radiotap_header *hdr;
3231*05b00f60SXin Li 	uint32_t presentflags;
3232*05b00f60SXin Li 	const nd_uint32_t *presentp, *last_presentp;
3233*05b00f60SXin Li 	int vendor_namespace;
3234*05b00f60SXin Li 	uint8_t vendor_oui[3];
3235*05b00f60SXin Li 	uint8_t vendor_subnamespace;
3236*05b00f60SXin Li 	uint16_t skip_length;
3237*05b00f60SXin Li 	int bit0;
3238*05b00f60SXin Li 	u_int len;
3239*05b00f60SXin Li 	uint8_t flags;
3240*05b00f60SXin Li 	int pad;
3241*05b00f60SXin Li 	u_int fcslen;
3242*05b00f60SXin Li 
3243*05b00f60SXin Li 	ndo->ndo_protocol = "802.11_radio";
3244*05b00f60SXin Li 	if (caplen < sizeof(*hdr)) {
3245*05b00f60SXin Li 		nd_print_trunc(ndo);
3246*05b00f60SXin Li 		return caplen;
3247*05b00f60SXin Li 	}
3248*05b00f60SXin Li 
3249*05b00f60SXin Li 	hdr = (const struct ieee80211_radiotap_header *)p;
3250*05b00f60SXin Li 
3251*05b00f60SXin Li 	len = GET_LE_U_2(hdr->it_len);
3252*05b00f60SXin Li 	if (len < sizeof(*hdr)) {
3253*05b00f60SXin Li 		/*
3254*05b00f60SXin Li 		 * The length is the length of the entire header, so
3255*05b00f60SXin Li 		 * it must be as large as the fixed-length part of
3256*05b00f60SXin Li 		 * the header.
3257*05b00f60SXin Li 		 */
3258*05b00f60SXin Li 		nd_print_trunc(ndo);
3259*05b00f60SXin Li 		return caplen;
3260*05b00f60SXin Li 	}
3261*05b00f60SXin Li 
3262*05b00f60SXin Li 	/*
3263*05b00f60SXin Li 	 * If we don't have the entire radiotap header, just give up.
3264*05b00f60SXin Li 	 */
3265*05b00f60SXin Li 	if (caplen < len) {
3266*05b00f60SXin Li 		nd_print_trunc(ndo);
3267*05b00f60SXin Li 		return caplen;
3268*05b00f60SXin Li 	}
3269*05b00f60SXin Li 	nd_cpack_init(&cpacker, (const uint8_t *)hdr, len); /* align against header start */
3270*05b00f60SXin Li 	nd_cpack_advance(&cpacker, sizeof(*hdr)); /* includes the 1st bitmap */
3271*05b00f60SXin Li 	for (last_presentp = &hdr->it_present;
3272*05b00f60SXin Li 	     (const u_char*)(last_presentp + 1) <= p + len &&
3273*05b00f60SXin Li 	     IS_EXTENDED(last_presentp);
3274*05b00f60SXin Li 	     last_presentp++)
3275*05b00f60SXin Li 	  nd_cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */
3276*05b00f60SXin Li 
3277*05b00f60SXin Li 	/* are there more bitmap extensions than bytes in header? */
3278*05b00f60SXin Li 	if ((const u_char*)(last_presentp + 1) > p + len) {
3279*05b00f60SXin Li 		nd_print_trunc(ndo);
3280*05b00f60SXin Li 		return caplen;
3281*05b00f60SXin Li 	}
3282*05b00f60SXin Li 
3283*05b00f60SXin Li 	/*
3284*05b00f60SXin Li 	 * Start out at the beginning of the default radiotap namespace.
3285*05b00f60SXin Li 	 */
3286*05b00f60SXin Li 	bit0 = 0;
3287*05b00f60SXin Li 	vendor_namespace = 0;
3288*05b00f60SXin Li 	memset(vendor_oui, 0, 3);
3289*05b00f60SXin Li 	vendor_subnamespace = 0;
3290*05b00f60SXin Li 	skip_length = 0;
3291*05b00f60SXin Li 	/* Assume no flags */
3292*05b00f60SXin Li 	flags = 0;
3293*05b00f60SXin Li 	/* Assume no Atheros padding between 802.11 header and body */
3294*05b00f60SXin Li 	pad = 0;
3295*05b00f60SXin Li 	/* Assume no FCS at end of frame */
3296*05b00f60SXin Li 	fcslen = 0;
3297*05b00f60SXin Li 	for (presentp = &hdr->it_present; presentp <= last_presentp;
3298*05b00f60SXin Li 	    presentp++) {
3299*05b00f60SXin Li 		presentflags = GET_LE_U_4(presentp);
3300*05b00f60SXin Li 
3301*05b00f60SXin Li 		/*
3302*05b00f60SXin Li 		 * If this is a vendor namespace, we don't handle it.
3303*05b00f60SXin Li 		 */
3304*05b00f60SXin Li 		if (vendor_namespace) {
3305*05b00f60SXin Li 			/*
3306*05b00f60SXin Li 			 * Skip past the stuff we don't understand.
3307*05b00f60SXin Li 			 * If we add support for any vendor namespaces,
3308*05b00f60SXin Li 			 * it'd be added here; use vendor_oui and
3309*05b00f60SXin Li 			 * vendor_subnamespace to interpret the fields.
3310*05b00f60SXin Li 			 */
3311*05b00f60SXin Li 			if (nd_cpack_advance(&cpacker, skip_length) != 0) {
3312*05b00f60SXin Li 				/*
3313*05b00f60SXin Li 				 * Ran out of space in the packet.
3314*05b00f60SXin Li 				 */
3315*05b00f60SXin Li 				break;
3316*05b00f60SXin Li 			}
3317*05b00f60SXin Li 
3318*05b00f60SXin Li 			/*
3319*05b00f60SXin Li 			 * We've skipped it all; nothing more to
3320*05b00f60SXin Li 			 * skip.
3321*05b00f60SXin Li 			 */
3322*05b00f60SXin Li 			skip_length = 0;
3323*05b00f60SXin Li 		} else {
3324*05b00f60SXin Li 			if (print_in_radiotap_namespace(ndo, &cpacker,
3325*05b00f60SXin Li 			    &flags, presentflags, bit0) != 0) {
3326*05b00f60SXin Li 				/*
3327*05b00f60SXin Li 				 * Fatal error - can't process anything
3328*05b00f60SXin Li 				 * more in the radiotap header.
3329*05b00f60SXin Li 				 */
3330*05b00f60SXin Li 				break;
3331*05b00f60SXin Li 			}
3332*05b00f60SXin Li 		}
3333*05b00f60SXin Li 
3334*05b00f60SXin Li 		/*
3335*05b00f60SXin Li 		 * Handle the namespace switch bits; we've already handled
3336*05b00f60SXin Li 		 * the extension bit in all but the last word above.
3337*05b00f60SXin Li 		 */
3338*05b00f60SXin Li 		switch (presentflags &
3339*05b00f60SXin Li 		    (BIT(IEEE80211_RADIOTAP_NAMESPACE)|BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE))) {
3340*05b00f60SXin Li 
3341*05b00f60SXin Li 		case 0:
3342*05b00f60SXin Li 			/*
3343*05b00f60SXin Li 			 * We're not changing namespaces.
3344*05b00f60SXin Li 			 * advance to the next 32 bits in the current
3345*05b00f60SXin Li 			 * namespace.
3346*05b00f60SXin Li 			 */
3347*05b00f60SXin Li 			bit0 += 32;
3348*05b00f60SXin Li 			break;
3349*05b00f60SXin Li 
3350*05b00f60SXin Li 		case BIT(IEEE80211_RADIOTAP_NAMESPACE):
3351*05b00f60SXin Li 			/*
3352*05b00f60SXin Li 			 * We're switching to the radiotap namespace.
3353*05b00f60SXin Li 			 * Reset the presence-bitmap index to 0, and
3354*05b00f60SXin Li 			 * reset the namespace to the default radiotap
3355*05b00f60SXin Li 			 * namespace.
3356*05b00f60SXin Li 			 */
3357*05b00f60SXin Li 			bit0 = 0;
3358*05b00f60SXin Li 			vendor_namespace = 0;
3359*05b00f60SXin Li 			memset(vendor_oui, 0, 3);
3360*05b00f60SXin Li 			vendor_subnamespace = 0;
3361*05b00f60SXin Li 			skip_length = 0;
3362*05b00f60SXin Li 			break;
3363*05b00f60SXin Li 
3364*05b00f60SXin Li 		case BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE):
3365*05b00f60SXin Li 			/*
3366*05b00f60SXin Li 			 * We're switching to a vendor namespace.
3367*05b00f60SXin Li 			 * Reset the presence-bitmap index to 0,
3368*05b00f60SXin Li 			 * note that we're in a vendor namespace,
3369*05b00f60SXin Li 			 * and fetch the fields of the Vendor Namespace
3370*05b00f60SXin Li 			 * item.
3371*05b00f60SXin Li 			 */
3372*05b00f60SXin Li 			bit0 = 0;
3373*05b00f60SXin Li 			vendor_namespace = 1;
3374*05b00f60SXin Li 			if ((nd_cpack_align_and_reserve(&cpacker, 2)) == NULL) {
3375*05b00f60SXin Li 				nd_print_trunc(ndo);
3376*05b00f60SXin Li 				break;
3377*05b00f60SXin Li 			}
3378*05b00f60SXin Li 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[0]) != 0) {
3379*05b00f60SXin Li 				nd_print_trunc(ndo);
3380*05b00f60SXin Li 				break;
3381*05b00f60SXin Li 			}
3382*05b00f60SXin Li 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[1]) != 0) {
3383*05b00f60SXin Li 				nd_print_trunc(ndo);
3384*05b00f60SXin Li 				break;
3385*05b00f60SXin Li 			}
3386*05b00f60SXin Li 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[2]) != 0) {
3387*05b00f60SXin Li 				nd_print_trunc(ndo);
3388*05b00f60SXin Li 				break;
3389*05b00f60SXin Li 			}
3390*05b00f60SXin Li 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_subnamespace) != 0) {
3391*05b00f60SXin Li 				nd_print_trunc(ndo);
3392*05b00f60SXin Li 				break;
3393*05b00f60SXin Li 			}
3394*05b00f60SXin Li 			if (nd_cpack_uint16(ndo, &cpacker, &skip_length) != 0) {
3395*05b00f60SXin Li 				nd_print_trunc(ndo);
3396*05b00f60SXin Li 				break;
3397*05b00f60SXin Li 			}
3398*05b00f60SXin Li 			break;
3399*05b00f60SXin Li 
3400*05b00f60SXin Li 		default:
3401*05b00f60SXin Li 			/*
3402*05b00f60SXin Li 			 * Illegal combination.  The behavior in this
3403*05b00f60SXin Li 			 * case is undefined by the radiotap spec; we
3404*05b00f60SXin Li 			 * just ignore both bits.
3405*05b00f60SXin Li 			 */
3406*05b00f60SXin Li 			break;
3407*05b00f60SXin Li 		}
3408*05b00f60SXin Li 	}
3409*05b00f60SXin Li 
3410*05b00f60SXin Li 	if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
3411*05b00f60SXin Li 		pad = 1;	/* Atheros padding */
3412*05b00f60SXin Li 	if (flags & IEEE80211_RADIOTAP_F_FCS)
3413*05b00f60SXin Li 		fcslen = 4;	/* FCS at end of packet */
3414*05b00f60SXin Li 	return len + ieee802_11_print(ndo, p + len, length - len, caplen - len, pad,
3415*05b00f60SXin Li 	    fcslen);
3416*05b00f60SXin Li #undef BITNO_32
3417*05b00f60SXin Li #undef BITNO_16
3418*05b00f60SXin Li #undef BITNO_8
3419*05b00f60SXin Li #undef BITNO_4
3420*05b00f60SXin Li #undef BITNO_2
3421*05b00f60SXin Li #undef BIT
3422*05b00f60SXin Li }
3423*05b00f60SXin Li 
3424*05b00f60SXin Li static u_int
ieee802_11_radio_avs_print(netdissect_options * ndo,const u_char * p,u_int length,u_int caplen)3425*05b00f60SXin Li ieee802_11_radio_avs_print(netdissect_options *ndo,
3426*05b00f60SXin Li 			   const u_char *p, u_int length, u_int caplen)
3427*05b00f60SXin Li {
3428*05b00f60SXin Li 	uint32_t caphdr_len;
3429*05b00f60SXin Li 
3430*05b00f60SXin Li 	ndo->ndo_protocol = "802.11_radio_avs";
3431*05b00f60SXin Li 	if (caplen < 8) {
3432*05b00f60SXin Li 		nd_print_trunc(ndo);
3433*05b00f60SXin Li 		return caplen;
3434*05b00f60SXin Li 	}
3435*05b00f60SXin Li 
3436*05b00f60SXin Li 	caphdr_len = GET_BE_U_4(p + 4);
3437*05b00f60SXin Li 	if (caphdr_len < 8) {
3438*05b00f60SXin Li 		/*
3439*05b00f60SXin Li 		 * Yow!  The capture header length is claimed not
3440*05b00f60SXin Li 		 * to be large enough to include even the version
3441*05b00f60SXin Li 		 * cookie or capture header length!
3442*05b00f60SXin Li 		 */
3443*05b00f60SXin Li 		nd_print_trunc(ndo);
3444*05b00f60SXin Li 		return caplen;
3445*05b00f60SXin Li 	}
3446*05b00f60SXin Li 
3447*05b00f60SXin Li 	if (caplen < caphdr_len) {
3448*05b00f60SXin Li 		nd_print_trunc(ndo);
3449*05b00f60SXin Li 		return caplen;
3450*05b00f60SXin Li 	}
3451*05b00f60SXin Li 
3452*05b00f60SXin Li 	return caphdr_len + ieee802_11_print(ndo, p + caphdr_len,
3453*05b00f60SXin Li 	    length - caphdr_len, caplen - caphdr_len, 0, 0);
3454*05b00f60SXin Li }
3455*05b00f60SXin Li 
3456*05b00f60SXin Li #define PRISM_HDR_LEN		144
3457*05b00f60SXin Li 
3458*05b00f60SXin Li #define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
3459*05b00f60SXin Li #define WLANCAP_MAGIC_COOKIE_V1	0x80211001
3460*05b00f60SXin Li #define WLANCAP_MAGIC_COOKIE_V2	0x80211002
3461*05b00f60SXin Li 
3462*05b00f60SXin Li /*
3463*05b00f60SXin Li  * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
3464*05b00f60SXin Li  * containing information such as radio information, which we
3465*05b00f60SXin Li  * currently ignore.
3466*05b00f60SXin Li  *
3467*05b00f60SXin Li  * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or
3468*05b00f60SXin Li  * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS
3469*05b00f60SXin Li  * (currently, on Linux, there's no ARPHRD_ type for
3470*05b00f60SXin Li  * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM
3471*05b00f60SXin Li  * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for
3472*05b00f60SXin Li  * the AVS header, and the first 4 bytes of the header are used to
3473*05b00f60SXin Li  * indicate whether it's a Prism header or an AVS header).
3474*05b00f60SXin Li  */
3475*05b00f60SXin Li void
prism_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h,const u_char * p)3476*05b00f60SXin Li prism_if_print(netdissect_options *ndo,
3477*05b00f60SXin Li 	       const struct pcap_pkthdr *h, const u_char *p)
3478*05b00f60SXin Li {
3479*05b00f60SXin Li 	u_int caplen = h->caplen;
3480*05b00f60SXin Li 	u_int length = h->len;
3481*05b00f60SXin Li 	uint32_t msgcode;
3482*05b00f60SXin Li 
3483*05b00f60SXin Li 	ndo->ndo_protocol = "prism";
3484*05b00f60SXin Li 	if (caplen < 4) {
3485*05b00f60SXin Li 		nd_print_trunc(ndo);
3486*05b00f60SXin Li 		ndo->ndo_ll_hdr_len += caplen;
3487*05b00f60SXin Li 		return;
3488*05b00f60SXin Li 	}
3489*05b00f60SXin Li 
3490*05b00f60SXin Li 	msgcode = GET_BE_U_4(p);
3491*05b00f60SXin Li 	if (msgcode == WLANCAP_MAGIC_COOKIE_V1 ||
3492*05b00f60SXin Li 	    msgcode == WLANCAP_MAGIC_COOKIE_V2) {
3493*05b00f60SXin Li 		ndo->ndo_ll_hdr_len += ieee802_11_radio_avs_print(ndo, p, length, caplen);
3494*05b00f60SXin Li 		return;
3495*05b00f60SXin Li 	}
3496*05b00f60SXin Li 
3497*05b00f60SXin Li 	if (caplen < PRISM_HDR_LEN) {
3498*05b00f60SXin Li 		nd_print_trunc(ndo);
3499*05b00f60SXin Li 		ndo->ndo_ll_hdr_len += caplen;
3500*05b00f60SXin Li 		return;
3501*05b00f60SXin Li 	}
3502*05b00f60SXin Li 
3503*05b00f60SXin Li 	p += PRISM_HDR_LEN;
3504*05b00f60SXin Li 	length -= PRISM_HDR_LEN;
3505*05b00f60SXin Li 	caplen -= PRISM_HDR_LEN;
3506*05b00f60SXin Li 	ndo->ndo_ll_hdr_len += PRISM_HDR_LEN;
3507*05b00f60SXin Li 	ndo->ndo_ll_hdr_len += ieee802_11_print(ndo, p, length, caplen, 0, 0);
3508*05b00f60SXin Li }
3509*05b00f60SXin Li 
3510*05b00f60SXin Li /*
3511*05b00f60SXin Li  * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra
3512*05b00f60SXin Li  * header, containing information such as radio information.
3513*05b00f60SXin Li  */
3514*05b00f60SXin Li void
ieee802_11_radio_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h,const u_char * p)3515*05b00f60SXin Li ieee802_11_radio_if_print(netdissect_options *ndo,
3516*05b00f60SXin Li 			  const struct pcap_pkthdr *h, const u_char *p)
3517*05b00f60SXin Li {
3518*05b00f60SXin Li 	ndo->ndo_protocol = "802.11_radio";
3519*05b00f60SXin Li 	ndo->ndo_ll_hdr_len += ieee802_11_radio_print(ndo, p, h->len, h->caplen);
3520*05b00f60SXin Li }
3521*05b00f60SXin Li 
3522*05b00f60SXin Li /*
3523*05b00f60SXin Li  * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an
3524*05b00f60SXin Li  * extra header, containing information such as radio information,
3525*05b00f60SXin Li  * which we currently ignore.
3526*05b00f60SXin Li  */
3527*05b00f60SXin Li void
ieee802_11_radio_avs_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h,const u_char * p)3528*05b00f60SXin Li ieee802_11_radio_avs_if_print(netdissect_options *ndo,
3529*05b00f60SXin Li 			      const struct pcap_pkthdr *h, const u_char *p)
3530*05b00f60SXin Li {
3531*05b00f60SXin Li 	ndo->ndo_protocol = "802.11_radio_avs";
3532*05b00f60SXin Li 	ndo->ndo_ll_hdr_len += ieee802_11_radio_avs_print(ndo, p, h->len, h->caplen);
3533*05b00f60SXin Li }
3534