xref: /netbsd-src/external/bsd/tcpdump/dist/print-802_11.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 2001
30f74e101Schristos  *	Fortress Technologies, Inc.  All rights reserved.
40f74e101Schristos  *      Charlie Lenahan (clenahan@fortresstech.com)
50f74e101Schristos  *
60f74e101Schristos  * Redistribution and use in source and binary forms, with or without
70f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
80f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
90f74e101Schristos  * distributions including binary code include the above copyright notice and
100f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
110f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
120f74e101Schristos  * features or use of this software display the following acknowledgement:
130f74e101Schristos  * ``This product includes software developed by the University of California,
140f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
150f74e101Schristos  * the University nor the names of its contributors may be used to endorse
160f74e101Schristos  * or promote products derived from this software without specific prior
170f74e101Schristos  * written permission.
180f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
190f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
200f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
210f74e101Schristos  */
220f74e101Schristos 
2311b3aaa1Schristos #include <sys/cdefs.h>
240f74e101Schristos #ifndef lint
25*26ba0b50Schristos __RCSID("$NetBSD: print-802_11.c,v 1.11 2024/09/02 16:15:30 christos Exp $");
260f74e101Schristos #endif
270f74e101Schristos 
28dc860a36Sspz /* \summary: IEEE 802.11 printer */
29dc860a36Sspz 
30c74ad251Schristos #include <config.h>
310f74e101Schristos 
32c74ad251Schristos #include "netdissect-stdinc.h"
330f74e101Schristos 
340f74e101Schristos #include <string.h>
350f74e101Schristos 
36fdccd7e4Schristos #include "netdissect.h"
370f74e101Schristos #include "addrtoname.h"
380f74e101Schristos 
390f74e101Schristos #include "extract.h"
400f74e101Schristos 
410f74e101Schristos #include "cpack.h"
420f74e101Schristos 
43b3a00663Schristos 
44b3a00663Schristos /* Lengths of 802.11 header components. */
45b3a00663Schristos #define	IEEE802_11_FC_LEN		2
46b3a00663Schristos #define	IEEE802_11_DUR_LEN		2
47b3a00663Schristos #define	IEEE802_11_DA_LEN		6
48b3a00663Schristos #define	IEEE802_11_SA_LEN		6
49b3a00663Schristos #define	IEEE802_11_BSSID_LEN		6
50b3a00663Schristos #define	IEEE802_11_RA_LEN		6
51b3a00663Schristos #define	IEEE802_11_TA_LEN		6
52fdccd7e4Schristos #define	IEEE802_11_ADDR1_LEN		6
53b3a00663Schristos #define	IEEE802_11_SEQ_LEN		2
54b3a00663Schristos #define	IEEE802_11_CTL_LEN		2
55fdccd7e4Schristos #define	IEEE802_11_CARRIED_FC_LEN	2
56fdccd7e4Schristos #define	IEEE802_11_HT_CONTROL_LEN	4
57b3a00663Schristos #define	IEEE802_11_IV_LEN		3
58b3a00663Schristos #define	IEEE802_11_KID_LEN		1
59b3a00663Schristos 
60b3a00663Schristos /* Frame check sequence length. */
61b3a00663Schristos #define	IEEE802_11_FCS_LEN		4
62b3a00663Schristos 
63b3a00663Schristos /* Lengths of beacon components. */
64b3a00663Schristos #define	IEEE802_11_TSTAMP_LEN		8
65b3a00663Schristos #define	IEEE802_11_BCNINT_LEN		2
66b3a00663Schristos #define	IEEE802_11_CAPINFO_LEN		2
67b3a00663Schristos #define	IEEE802_11_LISTENINT_LEN	2
68b3a00663Schristos 
69b3a00663Schristos #define	IEEE802_11_AID_LEN		2
70b3a00663Schristos #define	IEEE802_11_STATUS_LEN		2
71b3a00663Schristos #define	IEEE802_11_REASON_LEN		2
72b3a00663Schristos 
73*26ba0b50Schristos /* Length of previous AP in reassociation frame */
74b3a00663Schristos #define	IEEE802_11_AP_LEN		6
75b3a00663Schristos 
76b3a00663Schristos #define	T_MGMT 0x0  /* management */
77b3a00663Schristos #define	T_CTRL 0x1  /* control */
78b3a00663Schristos #define	T_DATA 0x2 /* data */
79b3a00663Schristos #define	T_RESV 0x3  /* reserved */
80b3a00663Schristos 
81b3a00663Schristos #define	ST_ASSOC_REQUEST	0x0
82b3a00663Schristos #define	ST_ASSOC_RESPONSE	0x1
83b3a00663Schristos #define	ST_REASSOC_REQUEST	0x2
84b3a00663Schristos #define	ST_REASSOC_RESPONSE	0x3
85b3a00663Schristos #define	ST_PROBE_REQUEST	0x4
86b3a00663Schristos #define	ST_PROBE_RESPONSE	0x5
87b3a00663Schristos /* RESERVED			0x6  */
88b3a00663Schristos /* RESERVED			0x7  */
89b3a00663Schristos #define	ST_BEACON		0x8
90b3a00663Schristos #define	ST_ATIM			0x9
91b3a00663Schristos #define	ST_DISASSOC		0xA
92b3a00663Schristos #define	ST_AUTH			0xB
93b3a00663Schristos #define	ST_DEAUTH		0xC
94b3a00663Schristos #define	ST_ACTION		0xD
95b3a00663Schristos /* RESERVED			0xE  */
96b3a00663Schristos /* RESERVED			0xF  */
97b3a00663Schristos 
98b3a00663Schristos static const struct tok st_str[] = {
99b3a00663Schristos 	{ ST_ASSOC_REQUEST,    "Assoc Request"    },
100b3a00663Schristos 	{ ST_ASSOC_RESPONSE,   "Assoc Response"   },
101b3a00663Schristos 	{ ST_REASSOC_REQUEST,  "ReAssoc Request"  },
102b3a00663Schristos 	{ ST_REASSOC_RESPONSE, "ReAssoc Response" },
103b3a00663Schristos 	{ ST_PROBE_REQUEST,    "Probe Request"    },
104b3a00663Schristos 	{ ST_PROBE_RESPONSE,   "Probe Response"   },
105b3a00663Schristos 	{ ST_BEACON,           "Beacon"           },
106b3a00663Schristos 	{ ST_ATIM,             "ATIM"             },
107b3a00663Schristos 	{ ST_DISASSOC,         "Disassociation"   },
108b3a00663Schristos 	{ ST_AUTH,             "Authentication"   },
109b3a00663Schristos 	{ ST_DEAUTH,           "DeAuthentication" },
110b3a00663Schristos 	{ ST_ACTION,           "Action"           },
111b3a00663Schristos 	{ 0, NULL }
112b3a00663Schristos };
113b3a00663Schristos 
114b3a00663Schristos #define CTRL_CONTROL_WRAPPER	0x7
115b3a00663Schristos #define	CTRL_BAR	0x8
116b3a00663Schristos #define	CTRL_BA		0x9
117b3a00663Schristos #define	CTRL_PS_POLL	0xA
118b3a00663Schristos #define	CTRL_RTS	0xB
119b3a00663Schristos #define	CTRL_CTS	0xC
120b3a00663Schristos #define	CTRL_ACK	0xD
121b3a00663Schristos #define	CTRL_CF_END	0xE
122b3a00663Schristos #define	CTRL_END_ACK	0xF
123b3a00663Schristos 
124b3a00663Schristos static const struct tok ctrl_str[] = {
125b3a00663Schristos 	{ CTRL_CONTROL_WRAPPER, "Control Wrapper" },
126b3a00663Schristos 	{ CTRL_BAR,             "BAR"             },
127b3a00663Schristos 	{ CTRL_BA,              "BA"              },
128b3a00663Schristos 	{ CTRL_PS_POLL,         "Power Save-Poll" },
129b3a00663Schristos 	{ CTRL_RTS,             "Request-To-Send" },
130b3a00663Schristos 	{ CTRL_CTS,             "Clear-To-Send"   },
131b3a00663Schristos 	{ CTRL_ACK,             "Acknowledgment"  },
132b3a00663Schristos 	{ CTRL_CF_END,          "CF-End"          },
133b3a00663Schristos 	{ CTRL_END_ACK,         "CF-End+CF-Ack"   },
134b3a00663Schristos 	{ 0, NULL }
135b3a00663Schristos };
136b3a00663Schristos 
137b3a00663Schristos #define	DATA_DATA			0x0
138b3a00663Schristos #define	DATA_DATA_CF_ACK		0x1
139b3a00663Schristos #define	DATA_DATA_CF_POLL		0x2
140b3a00663Schristos #define	DATA_DATA_CF_ACK_POLL		0x3
141b3a00663Schristos #define	DATA_NODATA			0x4
142b3a00663Schristos #define	DATA_NODATA_CF_ACK		0x5
143b3a00663Schristos #define	DATA_NODATA_CF_POLL		0x6
144b3a00663Schristos #define	DATA_NODATA_CF_ACK_POLL		0x7
145b3a00663Schristos 
146b3a00663Schristos #define DATA_QOS_DATA			0x8
147b3a00663Schristos #define DATA_QOS_DATA_CF_ACK		0x9
148b3a00663Schristos #define DATA_QOS_DATA_CF_POLL		0xA
149b3a00663Schristos #define DATA_QOS_DATA_CF_ACK_POLL	0xB
150b3a00663Schristos #define DATA_QOS_NODATA			0xC
151b3a00663Schristos #define DATA_QOS_CF_POLL_NODATA		0xE
152b3a00663Schristos #define DATA_QOS_CF_ACK_POLL_NODATA	0xF
153b3a00663Schristos 
154b3a00663Schristos /*
155b3a00663Schristos  * The subtype field of a data frame is, in effect, composed of 4 flag
156b3a00663Schristos  * bits - CF-Ack, CF-Poll, Null (means the frame doesn't actually have
157b3a00663Schristos  * any data), and QoS.
158b3a00663Schristos  */
159b3a00663Schristos #define DATA_FRAME_IS_CF_ACK(x)		((x) & 0x01)
160b3a00663Schristos #define DATA_FRAME_IS_CF_POLL(x)	((x) & 0x02)
161b3a00663Schristos #define DATA_FRAME_IS_NULL(x)		((x) & 0x04)
162b3a00663Schristos #define DATA_FRAME_IS_QOS(x)		((x) & 0x08)
163b3a00663Schristos 
164b3a00663Schristos /*
165b3a00663Schristos  * Bits in the frame control field.
166b3a00663Schristos  */
167b3a00663Schristos #define	FC_VERSION(fc)		((fc) & 0x3)
168b3a00663Schristos #define	FC_TYPE(fc)		(((fc) >> 2) & 0x3)
169b3a00663Schristos #define	FC_SUBTYPE(fc)		(((fc) >> 4) & 0xF)
170b3a00663Schristos #define	FC_TO_DS(fc)		((fc) & 0x0100)
171b3a00663Schristos #define	FC_FROM_DS(fc)		((fc) & 0x0200)
172b3a00663Schristos #define	FC_MORE_FLAG(fc)	((fc) & 0x0400)
173b3a00663Schristos #define	FC_RETRY(fc)		((fc) & 0x0800)
174b3a00663Schristos #define	FC_POWER_MGMT(fc)	((fc) & 0x1000)
175b3a00663Schristos #define	FC_MORE_DATA(fc)	((fc) & 0x2000)
176fdccd7e4Schristos #define	FC_PROTECTED(fc)	((fc) & 0x4000)
177b3a00663Schristos #define	FC_ORDER(fc)		((fc) & 0x8000)
178b3a00663Schristos 
179b3a00663Schristos struct mgmt_header_t {
180c74ad251Schristos 	nd_uint16_t	fc;
181c74ad251Schristos 	nd_uint16_t	duration;
182c74ad251Schristos 	nd_mac_addr	da;
183c74ad251Schristos 	nd_mac_addr	sa;
184c74ad251Schristos 	nd_mac_addr	bssid;
185c74ad251Schristos 	nd_uint16_t	seq_ctrl;
186b3a00663Schristos };
187b3a00663Schristos 
188b3a00663Schristos #define	MGMT_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
189b3a00663Schristos 			 IEEE802_11_DA_LEN+IEEE802_11_SA_LEN+\
190b3a00663Schristos 			 IEEE802_11_BSSID_LEN+IEEE802_11_SEQ_LEN)
191b3a00663Schristos 
192b3a00663Schristos #define	CAPABILITY_ESS(cap)	((cap) & 0x0001)
193b3a00663Schristos #define	CAPABILITY_IBSS(cap)	((cap) & 0x0002)
194b3a00663Schristos #define	CAPABILITY_CFP(cap)	((cap) & 0x0004)
195b3a00663Schristos #define	CAPABILITY_CFP_REQ(cap)	((cap) & 0x0008)
196b3a00663Schristos #define	CAPABILITY_PRIVACY(cap)	((cap) & 0x0010)
197b3a00663Schristos 
198b3a00663Schristos struct ssid_t {
199*26ba0b50Schristos 	u_int		length;
200b3a00663Schristos 	u_char		ssid[33];  /* 32 + 1 for null */
201b3a00663Schristos };
202b3a00663Schristos 
203b3a00663Schristos struct rates_t {
204*26ba0b50Schristos 	u_int		length;
205b3a00663Schristos 	uint8_t		rate[16];
206b3a00663Schristos };
207b3a00663Schristos 
208b3a00663Schristos struct challenge_t {
209*26ba0b50Schristos 	u_int		length;
210b3a00663Schristos 	uint8_t		text[254]; /* 1-253 + 1 for null */
211b3a00663Schristos };
212b3a00663Schristos 
213b3a00663Schristos struct fh_t {
214*26ba0b50Schristos 	u_int		length;
215b3a00663Schristos 	uint16_t	dwell_time;
216b3a00663Schristos 	uint8_t		hop_set;
217b3a00663Schristos 	uint8_t	hop_pattern;
218b3a00663Schristos 	uint8_t		hop_index;
219b3a00663Schristos };
220b3a00663Schristos 
221b3a00663Schristos struct ds_t {
222*26ba0b50Schristos 	u_int		length;
223b3a00663Schristos 	uint8_t		channel;
224b3a00663Schristos };
225b3a00663Schristos 
226b3a00663Schristos struct cf_t {
227*26ba0b50Schristos 	u_int		length;
228b3a00663Schristos 	uint8_t		count;
229b3a00663Schristos 	uint8_t		period;
230b3a00663Schristos 	uint16_t	max_duration;
231c74ad251Schristos 	uint16_t	dur_remaining;
232b3a00663Schristos };
233b3a00663Schristos 
234b3a00663Schristos struct tim_t {
235*26ba0b50Schristos 	u_int		length;
236b3a00663Schristos 	uint8_t		count;
237b3a00663Schristos 	uint8_t		period;
238b3a00663Schristos 	uint8_t		bitmap_control;
239b3a00663Schristos 	uint8_t		bitmap[251];
240b3a00663Schristos };
241b3a00663Schristos 
242b3a00663Schristos #define	E_SSID		0
243b3a00663Schristos #define	E_RATES	1
244b3a00663Schristos #define	E_FH		2
245b3a00663Schristos #define	E_DS		3
246b3a00663Schristos #define	E_CF		4
247b3a00663Schristos #define	E_TIM		5
248b3a00663Schristos #define	E_IBSS		6
249b3a00663Schristos /* reserved		7 */
250b3a00663Schristos /* reserved		8 */
251b3a00663Schristos /* reserved		9 */
252b3a00663Schristos /* reserved		10 */
253b3a00663Schristos /* reserved		11 */
254b3a00663Schristos /* reserved		12 */
255b3a00663Schristos /* reserved		13 */
256b3a00663Schristos /* reserved		14 */
257b3a00663Schristos /* reserved		15 */
258b3a00663Schristos /* reserved		16 */
259b3a00663Schristos 
260b3a00663Schristos #define	E_CHALLENGE	16
261b3a00663Schristos /* reserved		17 */
262b3a00663Schristos /* reserved		18 */
263b3a00663Schristos /* reserved		19 */
264b3a00663Schristos /* reserved		16 */
265b3a00663Schristos /* reserved		16 */
266b3a00663Schristos 
267b3a00663Schristos 
268b3a00663Schristos struct mgmt_body_t {
269b3a00663Schristos 	uint8_t		timestamp[IEEE802_11_TSTAMP_LEN];
270b3a00663Schristos 	uint16_t	beacon_interval;
271b3a00663Schristos 	uint16_t	listen_interval;
272b3a00663Schristos 	uint16_t	status_code;
273b3a00663Schristos 	uint16_t	aid;
274b3a00663Schristos 	u_char		ap[IEEE802_11_AP_LEN];
275b3a00663Schristos 	uint16_t	reason_code;
276b3a00663Schristos 	uint16_t	auth_alg;
277b3a00663Schristos 	uint16_t	auth_trans_seq_num;
278b3a00663Schristos 	int		challenge_present;
279b3a00663Schristos 	struct challenge_t  challenge;
280b3a00663Schristos 	uint16_t	capability_info;
281b3a00663Schristos 	int		ssid_present;
282b3a00663Schristos 	struct ssid_t	ssid;
283b3a00663Schristos 	int		rates_present;
284b3a00663Schristos 	struct rates_t	rates;
285b3a00663Schristos 	int		ds_present;
286b3a00663Schristos 	struct ds_t	ds;
287b3a00663Schristos 	int		cf_present;
288b3a00663Schristos 	struct cf_t	cf;
289b3a00663Schristos 	int		fh_present;
290b3a00663Schristos 	struct fh_t	fh;
291b3a00663Schristos 	int		tim_present;
292b3a00663Schristos 	struct tim_t	tim;
293b3a00663Schristos };
294b3a00663Schristos 
295fdccd7e4Schristos struct ctrl_control_wrapper_hdr_t {
296c74ad251Schristos 	nd_uint16_t	fc;
297c74ad251Schristos 	nd_uint16_t	duration;
298c74ad251Schristos 	nd_mac_addr	addr1;
299c74ad251Schristos 	nd_uint16_t	carried_fc[IEEE802_11_CARRIED_FC_LEN];
300c74ad251Schristos 	nd_uint16_t	ht_control[IEEE802_11_HT_CONTROL_LEN];
301fdccd7e4Schristos };
302fdccd7e4Schristos 
303fdccd7e4Schristos #define	CTRL_CONTROL_WRAPPER_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
304fdccd7e4Schristos 					 IEEE802_11_ADDR1_LEN+\
305fdccd7e4Schristos 					 IEEE802_11_CARRIED_FC_LEN+\
306fdccd7e4Schristos 					 IEEE802_11_HT_CONTROL_LEN)
307fdccd7e4Schristos 
308fdccd7e4Schristos struct ctrl_rts_hdr_t {
309c74ad251Schristos 	nd_uint16_t	fc;
310c74ad251Schristos 	nd_uint16_t	duration;
311c74ad251Schristos 	nd_mac_addr	ra;
312c74ad251Schristos 	nd_mac_addr	ta;
313b3a00663Schristos };
314b3a00663Schristos 
315b3a00663Schristos #define	CTRL_RTS_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
316b3a00663Schristos 			 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN)
317b3a00663Schristos 
318fdccd7e4Schristos struct ctrl_cts_hdr_t {
319c74ad251Schristos 	nd_uint16_t	fc;
320c74ad251Schristos 	nd_uint16_t	duration;
321c74ad251Schristos 	nd_mac_addr	ra;
322b3a00663Schristos };
323b3a00663Schristos 
324b3a00663Schristos #define	CTRL_CTS_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
325b3a00663Schristos 
326fdccd7e4Schristos struct ctrl_ack_hdr_t {
327c74ad251Schristos 	nd_uint16_t	fc;
328c74ad251Schristos 	nd_uint16_t	duration;
329c74ad251Schristos 	nd_mac_addr	ra;
330b3a00663Schristos };
331b3a00663Schristos 
332b3a00663Schristos #define	CTRL_ACK_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
333b3a00663Schristos 
334fdccd7e4Schristos struct ctrl_ps_poll_hdr_t {
335c74ad251Schristos 	nd_uint16_t	fc;
336c74ad251Schristos 	nd_uint16_t	aid;
337c74ad251Schristos 	nd_mac_addr	bssid;
338c74ad251Schristos 	nd_mac_addr	ta;
339b3a00663Schristos };
340b3a00663Schristos 
341b3a00663Schristos #define	CTRL_PS_POLL_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_AID_LEN+\
342b3a00663Schristos 				 IEEE802_11_BSSID_LEN+IEEE802_11_TA_LEN)
343b3a00663Schristos 
344fdccd7e4Schristos struct ctrl_end_hdr_t {
345c74ad251Schristos 	nd_uint16_t	fc;
346c74ad251Schristos 	nd_uint16_t	duration;
347c74ad251Schristos 	nd_mac_addr	ra;
348c74ad251Schristos 	nd_mac_addr	bssid;
349b3a00663Schristos };
350b3a00663Schristos 
351b3a00663Schristos #define	CTRL_END_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
352b3a00663Schristos 			 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
353b3a00663Schristos 
354fdccd7e4Schristos struct ctrl_end_ack_hdr_t {
355c74ad251Schristos 	nd_uint16_t	fc;
356c74ad251Schristos 	nd_uint16_t	duration;
357c74ad251Schristos 	nd_mac_addr	ra;
358c74ad251Schristos 	nd_mac_addr	bssid;
359b3a00663Schristos };
360b3a00663Schristos 
361b3a00663Schristos #define	CTRL_END_ACK_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
362b3a00663Schristos 				 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
363b3a00663Schristos 
364fdccd7e4Schristos struct ctrl_ba_hdr_t {
365c74ad251Schristos 	nd_uint16_t	fc;
366c74ad251Schristos 	nd_uint16_t	duration;
367c74ad251Schristos 	nd_mac_addr	ra;
368*26ba0b50Schristos 	nd_mac_addr	ta;
369b3a00663Schristos };
370b3a00663Schristos 
371*26ba0b50Schristos #define	CTRL_BA_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
372*26ba0b50Schristos 			 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN)
373b3a00663Schristos 
374fdccd7e4Schristos struct ctrl_bar_hdr_t {
375c74ad251Schristos 	nd_uint16_t	fc;
376c74ad251Schristos 	nd_uint16_t	dur;
377c74ad251Schristos 	nd_mac_addr	ra;
378c74ad251Schristos 	nd_mac_addr	ta;
379c74ad251Schristos 	nd_uint16_t	ctl;
380c74ad251Schristos 	nd_uint16_t	seq;
381b3a00663Schristos };
382b3a00663Schristos 
383b3a00663Schristos #define	CTRL_BAR_HDRLEN		(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
384b3a00663Schristos 				 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN+\
385b3a00663Schristos 				 IEEE802_11_CTL_LEN+IEEE802_11_SEQ_LEN)
386b3a00663Schristos 
387b3a00663Schristos struct meshcntl_t {
388c74ad251Schristos 	nd_uint8_t	flags;
389c74ad251Schristos 	nd_uint8_t	ttl;
390c74ad251Schristos 	nd_uint32_t	seq;
391c74ad251Schristos 	nd_mac_addr	addr4;
392c74ad251Schristos 	nd_mac_addr	addr5;
393c74ad251Schristos 	nd_mac_addr	addr6;
394b3a00663Schristos };
395b3a00663Schristos 
396b3a00663Schristos #define	IV_IV(iv)	((iv) & 0xFFFFFF)
397b3a00663Schristos #define	IV_PAD(iv)	(((iv) >> 24) & 0x3F)
398b3a00663Schristos #define	IV_KEYID(iv)	(((iv) >> 30) & 0x03)
399b3a00663Schristos 
4000f74e101Schristos #define PRINT_SSID(p) \
4010f74e101Schristos 	if (p.ssid_present) { \
402c74ad251Schristos 		ND_PRINT(" ("); \
403c74ad251Schristos 		fn_print_str(ndo, p.ssid.ssid); \
404c74ad251Schristos 		ND_PRINT(")"); \
4050f74e101Schristos 	}
4060f74e101Schristos 
4070f74e101Schristos #define PRINT_RATE(_sep, _r, _suf) \
408c74ad251Schristos 	ND_PRINT("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
4090f74e101Schristos #define PRINT_RATES(p) \
4100f74e101Schristos 	if (p.rates_present) { \
4110f74e101Schristos 		const char *sep = " ["; \
412*26ba0b50Schristos 		if (p.rates.length != 0) { \
413*26ba0b50Schristos 			for (u_int z = 0; z < p.rates.length ; z++) { \
4140f74e101Schristos 				PRINT_RATE(sep, p.rates.rate[z], \
4150f74e101Schristos 					(p.rates.rate[z] & 0x80 ? "*" : "")); \
4160f74e101Schristos 				sep = " "; \
4170f74e101Schristos 			} \
418c74ad251Schristos 			ND_PRINT(" Mbit]"); \
419*26ba0b50Schristos 		} \
4200f74e101Schristos 	}
4210f74e101Schristos 
4220f74e101Schristos #define PRINT_DS_CHANNEL(p) \
4230f74e101Schristos 	if (p.ds_present) \
424c74ad251Schristos 		ND_PRINT(" CH: %u", p.ds.channel); \
425c74ad251Schristos 	ND_PRINT("%s", \
426c74ad251Schristos 	    CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "");
4270f74e101Schristos 
4280e9868baSchristos #define MAX_MCS_INDEX	76
4290e9868baSchristos 
4300e9868baSchristos /*
4310e9868baSchristos  * Indices are:
4320e9868baSchristos  *
4330e9868baSchristos  *	the MCS index (0-76);
4340e9868baSchristos  *
4350e9868baSchristos  *	0 for 20 MHz, 1 for 40 MHz;
4360e9868baSchristos  *
4370e9868baSchristos  *	0 for a long guard interval, 1 for a short guard interval.
4380e9868baSchristos  */
4390e9868baSchristos static const float ieee80211_float_htrates[MAX_MCS_INDEX+1][2][2] = {
4400e9868baSchristos 	/* MCS  0  */
441c74ad251Schristos 	{	/* 20 Mhz */ {    6.5f,		/* SGI */    7.2f, },
442c74ad251Schristos 		/* 40 Mhz */ {   13.5f,		/* SGI */   15.0f, },
4430e9868baSchristos 	},
4440e9868baSchristos 
4450e9868baSchristos 	/* MCS  1  */
446c74ad251Schristos 	{	/* 20 Mhz */ {   13.0f,		/* SGI */   14.4f, },
447c74ad251Schristos 		/* 40 Mhz */ {   27.0f,		/* SGI */   30.0f, },
4480e9868baSchristos 	},
4490e9868baSchristos 
4500e9868baSchristos 	/* MCS  2  */
451c74ad251Schristos 	{	/* 20 Mhz */ {   19.5f,		/* SGI */   21.7f, },
452c74ad251Schristos 		/* 40 Mhz */ {   40.5f,		/* SGI */   45.0f, },
4530e9868baSchristos 	},
4540e9868baSchristos 
4550e9868baSchristos 	/* MCS  3  */
456c74ad251Schristos 	{	/* 20 Mhz */ {   26.0f,		/* SGI */   28.9f, },
457c74ad251Schristos 		/* 40 Mhz */ {   54.0f,		/* SGI */   60.0f, },
4580e9868baSchristos 	},
4590e9868baSchristos 
4600e9868baSchristos 	/* MCS  4  */
461c74ad251Schristos 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
462c74ad251Schristos 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
4630e9868baSchristos 	},
4640e9868baSchristos 
4650e9868baSchristos 	/* MCS  5  */
466c74ad251Schristos 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
467c74ad251Schristos 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
4680e9868baSchristos 	},
4690e9868baSchristos 
4700e9868baSchristos 	/* MCS  6  */
471c74ad251Schristos 	{	/* 20 Mhz */ {   58.5f,		/* SGI */   65.0f, },
472c74ad251Schristos 		/* 40 Mhz */ {  121.5f,		/* SGI */  135.0f, },
4730e9868baSchristos 	},
4740e9868baSchristos 
4750e9868baSchristos 	/* MCS  7  */
476c74ad251Schristos 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
477c74ad251Schristos 		/* 40 Mhz */ {   135.0f,	/* SGI */  150.0f, },
4780e9868baSchristos 	},
4790e9868baSchristos 
4800e9868baSchristos 	/* MCS  8  */
481c74ad251Schristos 	{	/* 20 Mhz */ {   13.0f,		/* SGI */   14.4f, },
482c74ad251Schristos 		/* 40 Mhz */ {   27.0f,		/* SGI */   30.0f, },
4830e9868baSchristos 	},
4840e9868baSchristos 
4850e9868baSchristos 	/* MCS  9  */
486c74ad251Schristos 	{	/* 20 Mhz */ {   26.0f,		/* SGI */   28.9f, },
487c74ad251Schristos 		/* 40 Mhz */ {   54.0f,		/* SGI */   60.0f, },
4880e9868baSchristos 	},
4890e9868baSchristos 
4900e9868baSchristos 	/* MCS 10  */
491c74ad251Schristos 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
492c74ad251Schristos 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
4930e9868baSchristos 	},
4940e9868baSchristos 
4950e9868baSchristos 	/* MCS 11  */
496c74ad251Schristos 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
497c74ad251Schristos 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
4980e9868baSchristos 	},
4990e9868baSchristos 
5000e9868baSchristos 	/* MCS 12  */
501c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
502c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
5030e9868baSchristos 	},
5040e9868baSchristos 
5050e9868baSchristos 	/* MCS 13  */
506c74ad251Schristos 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
507c74ad251Schristos 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
5080e9868baSchristos 	},
5090e9868baSchristos 
5100e9868baSchristos 	/* MCS 14  */
511c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
512c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
5130e9868baSchristos 	},
5140e9868baSchristos 
5150e9868baSchristos 	/* MCS 15  */
516c74ad251Schristos 	{	/* 20 Mhz */ {  130.0f,		/* SGI */  144.4f, },
517c74ad251Schristos 		/* 40 Mhz */ {  270.0f,		/* SGI */  300.0f, },
5180e9868baSchristos 	},
5190e9868baSchristos 
5200e9868baSchristos 	/* MCS 16  */
521c74ad251Schristos 	{	/* 20 Mhz */ {   19.5f,		/* SGI */   21.7f, },
522c74ad251Schristos 		/* 40 Mhz */ {   40.5f,		/* SGI */   45.0f, },
5230e9868baSchristos 	},
5240e9868baSchristos 
5250e9868baSchristos 	/* MCS 17  */
526c74ad251Schristos 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
527c74ad251Schristos 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
5280e9868baSchristos 	},
5290e9868baSchristos 
5300e9868baSchristos 	/* MCS 18  */
531c74ad251Schristos 	{	/* 20 Mhz */ {   58.5f,		/* SGI */   65.0f, },
532c74ad251Schristos 		/* 40 Mhz */ {  121.5f,		/* SGI */  135.0f, },
5330e9868baSchristos 	},
5340e9868baSchristos 
5350e9868baSchristos 	/* MCS 19  */
536c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
537c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
5380e9868baSchristos 	},
5390e9868baSchristos 
5400e9868baSchristos 	/* MCS 20  */
541c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
542c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
5430e9868baSchristos 	},
5440e9868baSchristos 
5450e9868baSchristos 	/* MCS 21  */
546c74ad251Schristos 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
547c74ad251Schristos 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
5480e9868baSchristos 	},
5490e9868baSchristos 
5500e9868baSchristos 	/* MCS 22  */
551c74ad251Schristos 	{	/* 20 Mhz */ {  175.5f,		/* SGI */  195.0f, },
552c74ad251Schristos 		/* 40 Mhz */ {  364.5f,		/* SGI */  405.0f, },
5530e9868baSchristos 	},
5540e9868baSchristos 
5550e9868baSchristos 	/* MCS 23  */
556c74ad251Schristos 	{	/* 20 Mhz */ {  195.0f,		/* SGI */  216.7f, },
557c74ad251Schristos 		/* 40 Mhz */ {  405.0f,		/* SGI */  450.0f, },
5580e9868baSchristos 	},
5590e9868baSchristos 
5600e9868baSchristos 	/* MCS 24  */
561c74ad251Schristos 	{	/* 20 Mhz */ {   26.0f,		/* SGI */   28.9f, },
562c74ad251Schristos 		/* 40 Mhz */ {   54.0f,		/* SGI */   60.0f, },
5630e9868baSchristos 	},
5640e9868baSchristos 
5650e9868baSchristos 	/* MCS 25  */
566c74ad251Schristos 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
567c74ad251Schristos 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
5680e9868baSchristos 	},
5690e9868baSchristos 
5700e9868baSchristos 	/* MCS 26  */
571c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
572c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
5730e9868baSchristos 	},
5740e9868baSchristos 
5750e9868baSchristos 	/* MCS 27  */
576c74ad251Schristos 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
577c74ad251Schristos 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
5780e9868baSchristos 	},
5790e9868baSchristos 
5800e9868baSchristos 	/* MCS 28  */
581c74ad251Schristos 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
582c74ad251Schristos 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
5830e9868baSchristos 	},
5840e9868baSchristos 
5850e9868baSchristos 	/* MCS 29  */
586c74ad251Schristos 	{	/* 20 Mhz */ {  208.0f,		/* SGI */  231.1f, },
587c74ad251Schristos 		/* 40 Mhz */ {  432.0f,		/* SGI */  480.0f, },
5880e9868baSchristos 	},
5890e9868baSchristos 
5900e9868baSchristos 	/* MCS 30  */
591c74ad251Schristos 	{	/* 20 Mhz */ {  234.0f,		/* SGI */  260.0f, },
592c74ad251Schristos 		/* 40 Mhz */ {  486.0f,		/* SGI */  540.0f, },
5930e9868baSchristos 	},
5940e9868baSchristos 
5950e9868baSchristos 	/* MCS 31  */
596c74ad251Schristos 	{	/* 20 Mhz */ {  260.0f,		/* SGI */  288.9f, },
597c74ad251Schristos 		/* 40 Mhz */ {  540.0f,		/* SGI */  600.0f, },
5980e9868baSchristos 	},
5990e9868baSchristos 
6000e9868baSchristos 	/* MCS 32  */
601c74ad251Schristos 	{	/* 20 Mhz */ {    0.0f,		/* SGI */    0.0f, }, /* not valid */
602c74ad251Schristos 		/* 40 Mhz */ {    6.0f,		/* SGI */    6.7f, },
6030e9868baSchristos 	},
6040e9868baSchristos 
6050e9868baSchristos 	/* MCS 33  */
606c74ad251Schristos 	{	/* 20 Mhz */ {   39.0f,		/* SGI */   43.3f, },
607c74ad251Schristos 		/* 40 Mhz */ {   81.0f,		/* SGI */   90.0f, },
6080e9868baSchristos 	},
6090e9868baSchristos 
6100e9868baSchristos 	/* MCS 34  */
611c74ad251Schristos 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
612c74ad251Schristos 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
6130e9868baSchristos 	},
6140e9868baSchristos 
6150e9868baSchristos 	/* MCS 35  */
616c74ad251Schristos 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
617c74ad251Schristos 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
6180e9868baSchristos 	},
6190e9868baSchristos 
6200e9868baSchristos 	/* MCS 36  */
621c74ad251Schristos 	{	/* 20 Mhz */ {   58.5f,		/* SGI */   65.0f, },
622c74ad251Schristos 		/* 40 Mhz */ {  121.5f,		/* SGI */  135.0f, },
6230e9868baSchristos 	},
6240e9868baSchristos 
6250e9868baSchristos 	/* MCS 37  */
626c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
627c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
6280e9868baSchristos 	},
6290e9868baSchristos 
6300e9868baSchristos 	/* MCS 38  */
631c74ad251Schristos 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
632c74ad251Schristos 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
6330e9868baSchristos 	},
6340e9868baSchristos 
6350e9868baSchristos 	/* MCS 39  */
636c74ad251Schristos 	{	/* 20 Mhz */ {   52.0f,		/* SGI */   57.8f, },
637c74ad251Schristos 		/* 40 Mhz */ {  108.0f,		/* SGI */  120.0f, },
6380e9868baSchristos 	},
6390e9868baSchristos 
6400e9868baSchristos 	/* MCS 40  */
641c74ad251Schristos 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
642c74ad251Schristos 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
6430e9868baSchristos 	},
6440e9868baSchristos 
6450e9868baSchristos 	/* MCS 41  */
646c74ad251Schristos 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
647c74ad251Schristos 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
6480e9868baSchristos 	},
6490e9868baSchristos 
6500e9868baSchristos 	/* MCS 42  */
651c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
652c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
6530e9868baSchristos 	},
6540e9868baSchristos 
6550e9868baSchristos 	/* MCS 43  */
656c74ad251Schristos 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
657c74ad251Schristos 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
6580e9868baSchristos 	},
6590e9868baSchristos 
6600e9868baSchristos 	/* MCS 44  */
661c74ad251Schristos 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
662c74ad251Schristos 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
6630e9868baSchristos 	},
6640e9868baSchristos 
6650e9868baSchristos 	/* MCS 45  */
666c74ad251Schristos 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
667c74ad251Schristos 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
6680e9868baSchristos 	},
6690e9868baSchristos 
6700e9868baSchristos 	/* MCS 46  */
671c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
672c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
6730e9868baSchristos 	},
6740e9868baSchristos 
6750e9868baSchristos 	/* MCS 47  */
676c74ad251Schristos 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
677c74ad251Schristos 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
6780e9868baSchristos 	},
6790e9868baSchristos 
6800e9868baSchristos 	/* MCS 48  */
681c74ad251Schristos 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
682c74ad251Schristos 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
6830e9868baSchristos 	},
6840e9868baSchristos 
6850e9868baSchristos 	/* MCS 49  */
686c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
687c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
6880e9868baSchristos 	},
6890e9868baSchristos 
6900e9868baSchristos 	/* MCS 50  */
691c74ad251Schristos 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
692c74ad251Schristos 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
6930e9868baSchristos 	},
6940e9868baSchristos 
6950e9868baSchristos 	/* MCS 51  */
696c74ad251Schristos 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
697c74ad251Schristos 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
6980e9868baSchristos 	},
6990e9868baSchristos 
7000e9868baSchristos 	/* MCS 52  */
701c74ad251Schristos 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
702c74ad251Schristos 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
7030e9868baSchristos 	},
7040e9868baSchristos 
7050e9868baSchristos 	/* MCS 53  */
706c74ad251Schristos 	{	/* 20 Mhz */ {   65.0f,		/* SGI */   72.2f, },
707c74ad251Schristos 		/* 40 Mhz */ {  135.0f,		/* SGI */  150.0f, },
7080e9868baSchristos 	},
7090e9868baSchristos 
7100e9868baSchristos 	/* MCS 54  */
711c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
712c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
7130e9868baSchristos 	},
7140e9868baSchristos 
7150e9868baSchristos 	/* MCS 55  */
716c74ad251Schristos 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
717c74ad251Schristos 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
7180e9868baSchristos 	},
7190e9868baSchristos 
7200e9868baSchristos 	/* MCS 56  */
721c74ad251Schristos 	{	/* 20 Mhz */ {   78.0f,		/* SGI */   86.7f, },
722c74ad251Schristos 		/* 40 Mhz */ {  162.0f,		/* SGI */  180.0f, },
7230e9868baSchristos 	},
7240e9868baSchristos 
7250e9868baSchristos 	/* MCS 57  */
726c74ad251Schristos 	{	/* 20 Mhz */ {   91.0f,		/* SGI */  101.1f, },
727c74ad251Schristos 		/* 40 Mhz */ {  189.0f,		/* SGI */  210.0f, },
7280e9868baSchristos 	},
7290e9868baSchristos 
7300e9868baSchristos 	/* MCS 58  */
731c74ad251Schristos 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
732c74ad251Schristos 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
7330e9868baSchristos 	},
7340e9868baSchristos 
7350e9868baSchristos 	/* MCS 59  */
736c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
737c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
7380e9868baSchristos 	},
7390e9868baSchristos 
7400e9868baSchristos 	/* MCS 60  */
741c74ad251Schristos 	{	/* 20 Mhz */ {  104.0f,		/* SGI */  115.6f, },
742c74ad251Schristos 		/* 40 Mhz */ {  216.0f,		/* SGI */  240.0f, },
7430e9868baSchristos 	},
7440e9868baSchristos 
7450e9868baSchristos 	/* MCS 61  */
746c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
747c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
7480e9868baSchristos 	},
7490e9868baSchristos 
7500e9868baSchristos 	/* MCS 62  */
751c74ad251Schristos 	{	/* 20 Mhz */ {  130.0f,		/* SGI */  144.4f, },
752c74ad251Schristos 		/* 40 Mhz */ {  270.0f,		/* SGI */  300.0f, },
7530e9868baSchristos 	},
7540e9868baSchristos 
7550e9868baSchristos 	/* MCS 63  */
756c74ad251Schristos 	{	/* 20 Mhz */ {  130.0f,		/* SGI */  144.4f, },
757c74ad251Schristos 		/* 40 Mhz */ {  270.0f,		/* SGI */  300.0f, },
7580e9868baSchristos 	},
7590e9868baSchristos 
7600e9868baSchristos 	/* MCS 64  */
761c74ad251Schristos 	{	/* 20 Mhz */ {  143.0f,		/* SGI */  158.9f, },
762c74ad251Schristos 		/* 40 Mhz */ {  297.0f,		/* SGI */  330.0f, },
7630e9868baSchristos 	},
7640e9868baSchristos 
7650e9868baSchristos 	/* MCS 65  */
766c74ad251Schristos 	{	/* 20 Mhz */ {   97.5f,		/* SGI */  108.3f, },
767c74ad251Schristos 		/* 40 Mhz */ {  202.5f,		/* SGI */  225.0f, },
7680e9868baSchristos 	},
7690e9868baSchristos 
7700e9868baSchristos 	/* MCS 66  */
771c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
772c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
7730e9868baSchristos 	},
7740e9868baSchristos 
7750e9868baSchristos 	/* MCS 67  */
776c74ad251Schristos 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
777c74ad251Schristos 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
7780e9868baSchristos 	},
7790e9868baSchristos 
7800e9868baSchristos 	/* MCS 68  */
781c74ad251Schristos 	{	/* 20 Mhz */ {  117.0f,		/* SGI */  130.0f, },
782c74ad251Schristos 		/* 40 Mhz */ {  243.0f,		/* SGI */  270.0f, },
7830e9868baSchristos 	},
7840e9868baSchristos 
7850e9868baSchristos 	/* MCS 69  */
786c74ad251Schristos 	{	/* 20 Mhz */ {  136.5f,		/* SGI */  151.7f, },
787c74ad251Schristos 		/* 40 Mhz */ {  283.5f,		/* SGI */  315.0f, },
7880e9868baSchristos 	},
7890e9868baSchristos 
7900e9868baSchristos 	/* MCS 70  */
791c74ad251Schristos 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
792c74ad251Schristos 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
7930e9868baSchristos 	},
7940e9868baSchristos 
7950e9868baSchristos 	/* MCS 71  */
796c74ad251Schristos 	{	/* 20 Mhz */ {  175.5f,		/* SGI */  195.0f, },
797c74ad251Schristos 		/* 40 Mhz */ {  364.5f,		/* SGI */  405.0f, },
7980e9868baSchristos 	},
7990e9868baSchristos 
8000e9868baSchristos 	/* MCS 72  */
801c74ad251Schristos 	{	/* 20 Mhz */ {  156.0f,		/* SGI */  173.3f, },
802c74ad251Schristos 		/* 40 Mhz */ {  324.0f,		/* SGI */  360.0f, },
8030e9868baSchristos 	},
8040e9868baSchristos 
8050e9868baSchristos 	/* MCS 73  */
806c74ad251Schristos 	{	/* 20 Mhz */ {  175.5f,		/* SGI */  195.0f, },
807c74ad251Schristos 		/* 40 Mhz */ {  364.5f,		/* SGI */  405.0f, },
8080e9868baSchristos 	},
8090e9868baSchristos 
8100e9868baSchristos 	/* MCS 74  */
811c74ad251Schristos 	{	/* 20 Mhz */ {  195.0f,		/* SGI */  216.7f, },
812c74ad251Schristos 		/* 40 Mhz */ {  405.0f,		/* SGI */  450.0f, },
8130e9868baSchristos 	},
8140e9868baSchristos 
8150e9868baSchristos 	/* MCS 75  */
816c74ad251Schristos 	{	/* 20 Mhz */ {  195.0f,		/* SGI */  216.7f, },
817c74ad251Schristos 		/* 40 Mhz */ {  405.0f,		/* SGI */  450.0f, },
8180e9868baSchristos 	},
8190e9868baSchristos 
8200e9868baSchristos 	/* MCS 76  */
821c74ad251Schristos 	{	/* 20 Mhz */ {  214.5f,		/* SGI */  238.3f, },
822c74ad251Schristos 		/* 40 Mhz */ {  445.5f,		/* SGI */  495.0f, },
8230e9868baSchristos 	},
8240f74e101Schristos };
8250f74e101Schristos 
8260f74e101Schristos static const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
827c74ad251Schristos #define NUM_AUTH_ALGS	(sizeof(auth_alg_text) / sizeof(auth_alg_text[0]))
8280f74e101Schristos 
8290f74e101Schristos static const char *status_text[] = {
8300e9868baSchristos 	"Successful",						/*  0 */
8310f74e101Schristos 	"Unspecified failure",					/*  1 */
832c74ad251Schristos 	"TDLS wakeup schedule rejected but alternative schedule "
833c74ad251Schristos 	  "provided",					/*  2 */
834c74ad251Schristos 	"TDLS wakeup schedule rejected",/*  3 */
8350f74e101Schristos 	"Reserved",						/*  4 */
836c74ad251Schristos 	"Security disabled",			/*  5 */
837c74ad251Schristos 	"Unacceptable lifetime",		/*  6 */
838c74ad251Schristos 	"Not in same BSS",				/*  7 */
8390f74e101Schristos 	"Reserved",						/*  8 */
8400f74e101Schristos 	"Reserved",						/*  9 */
8410f74e101Schristos 	"Cannot Support all requested capabilities in the Capability "
8420f74e101Schristos 	  "Information field",					/* 10 */
8430f74e101Schristos 	"Reassociation denied due to inability to confirm that association "
8440f74e101Schristos 	  "exists",						/* 11 */
845c74ad251Schristos 	"Association denied due to reason outside the scope of this "
8460f74e101Schristos 	  "standard",						/* 12 */
847c74ad251Schristos 	"Responding STA does not support the specified authentication "
8480f74e101Schristos 	  "algorithm",						/* 13 */
8490f74e101Schristos 	"Received an Authentication frame with authentication transaction "
8500f74e101Schristos 	  "sequence number out of expected sequence",		/* 14 */
8510f74e101Schristos 	"Authentication rejected because of challenge failure",	/* 15 */
8520f74e101Schristos 	"Authentication rejected due to timeout waiting for next frame in "
8530f74e101Schristos 	  "sequence",						/* 16 */
854c74ad251Schristos 	"Association denied because AP is unable to handle "
855c74ad251Schristos 	  "additional associated STAs",				/* 17 */
856c74ad251Schristos 	"Association denied due to requesting STA not supporting "
857c74ad251Schristos 	  "all of the data rates in the BSSBasicRateSet parameter, "
858c74ad251Schristos 	  "the Basic HT-MCS Set field of the HT Operation "
859c74ad251Schristos 	  "parameter, or the Basic VHT-MCS and NSS Set field in "
860c74ad251Schristos 	  "the VHT Operation parameter",	/* 18 */
861c74ad251Schristos 	"Association denied due to requesting STA not supporting "
862c74ad251Schristos 	  "the short preamble option",				/* 19 */
863c74ad251Schristos 	"Reserved",					/* 20 */
864c74ad251Schristos 	"Reserved",					/* 21 */
8650f74e101Schristos 	"Association request rejected because Spectrum Management "
8660f74e101Schristos 	  "capability is required",				/* 22 */
8670f74e101Schristos 	"Association request rejected because the information in the "
8680f74e101Schristos 	  "Power Capability element is unacceptable",		/* 23 */
8690f74e101Schristos 	"Association request rejected because the information in the "
8700f74e101Schristos 	  "Supported Channels element is unacceptable",		/* 24 */
871c74ad251Schristos 	"Association denied due to requesting STA not supporting "
872c74ad251Schristos 	  "the Short Slot Time option",				/* 25 */
873c74ad251Schristos 	"Reserved",				/* 26 */
8740f74e101Schristos 	"Association denied because the requested STA does not support HT "
8750f74e101Schristos 	  "features",						/* 27 */
876c74ad251Schristos 	"R0KH unreachable",					/* 28 */
877c74ad251Schristos 	"Association denied because the requesting STA does not "
878c74ad251Schristos 	  "support the phased coexistence operation (PCO) "
879c74ad251Schristos 	  "transition time required by the AP",		/* 29 */
880c74ad251Schristos 	"Association request rejected temporarily; try again "
881c74ad251Schristos 	  "later",							/* 30 */
882c74ad251Schristos 	"Robust management frame policy violation",	/* 31 */
8830f74e101Schristos 	"Unspecified, QoS-related failure",			/* 32 */
884c74ad251Schristos 	"Association denied because QoS AP or PCP has "
885c74ad251Schristos 	  "insufficient bandwidth to handle another QoS "
886c74ad251Schristos 	  "STA",									/* 33 */
8870f74e101Schristos 	"Association denied due to excessive frame loss rates and/or "
8880f74e101Schristos 	  "poor conditions on current operating channel",	/* 34 */
889c74ad251Schristos 	"Association (with QoS BSS) denied because the requesting STA "
890c74ad251Schristos 	  "does not support the QoS facility",			/* 35 */
891c74ad251Schristos 	"Reserved",									/* 36 */
8920f74e101Schristos 	"The request has been declined",			/* 37 */
8930f74e101Schristos 	"The request has not been successful as one or more parameters "
8940f74e101Schristos 	  "have invalid values",				/* 38 */
895c74ad251Schristos 	"The allocation or TS has not been created because the request "
896c74ad251Schristos 	  "cannot be honored; however, a suggested TSPEC/DMG TSPEC is "
897c74ad251Schristos 	  "provided so that the initiating STA can attempt to set "
898c74ad251Schristos 	  "another allocation or TS with the suggested changes to the "
899c74ad251Schristos 	  "TSPEC/DMG TSPEC",					/* 39 */
900c74ad251Schristos 	"Invalid element, i.e., an element defined in this standard "
901c74ad251Schristos 	  "for which the content does not meet the specifications in "
902c74ad251Schristos 	  "Clause 9",								/* 40 */
903c74ad251Schristos 	"Invalid group cipher",						/* 41 */
904c74ad251Schristos 	"Invalid pairwise cipher",					/* 42 */
905c74ad251Schristos 	"Invalid AKMP",								/* 43 */
906c74ad251Schristos 	"Unsupported RSNE version",					/* 44 */
907c74ad251Schristos 	"Invalid RSNE capabilities",				/* 45 */
908c74ad251Schristos 	"Cipher suite rejected because of security policy",		/* 46 */
909c74ad251Schristos 	"The TS or allocation has not been created; however, the "
910c74ad251Schristos 	  "HC or PCP might be capable of creating a TS or "
911c74ad251Schristos 	  "allocation, in response to a request, after the time "
912c74ad251Schristos 	  "indicated in the TS Delay element",		/* 47 */
9130f74e101Schristos 	"Direct Link is not allowed in the BSS by policy",	/* 48 */
914c74ad251Schristos 	"The Destination STA is not present within this BSS",	/* 49 */
915c74ad251Schristos 	"The Destination STA is not a QoS STA",		/* 50 */
9160f74e101Schristos 
917c74ad251Schristos 	"Association denied because the listen interval is "
918c74ad251Schristos 	  "too large",								/* 51 */
919c74ad251Schristos 	"Invalid FT Action frame count",			/* 52 */
920c74ad251Schristos 	"Invalid pairwise master key identifier (PMKID)", /* 53 */
921c74ad251Schristos 	"Invalid MDE",								/* 54 */
922c74ad251Schristos 	"Invalid FTE",								/* 55 */
923c74ad251Schristos 	"Requested TCLAS processing is not supported by the AP "
924c74ad251Schristos 	  "or PCP",									/* 56 */
925c74ad251Schristos 	"The AP or PCP has insufficient TCLAS processing "
926c74ad251Schristos 	  "resources to satisfy the request",		/* 57 */
927c74ad251Schristos 	"The TS has not been created because the request "
928c74ad251Schristos 	  "cannot be honored; however, the HC or PCP suggests "
929c74ad251Schristos 	  "that the STA transition to a different BSS to set up "
930c74ad251Schristos 	  "the TS",									/* 58 */
931c74ad251Schristos 	"GAS Advertisement Protocol not supported",	/* 59 */
932c74ad251Schristos 	"No outstanding GAS request",				/* 60 */
933c74ad251Schristos 	"GAS Response not received from the Advertisement "
934c74ad251Schristos 	  "Server",									/* 61 */
935c74ad251Schristos 	"STA timed out waiting for GAS Query Response", /* 62 */
936c74ad251Schristos 	"LARGE GAS Response is larger than query response "
937c74ad251Schristos 	  "length limit",							/* 63 */
938c74ad251Schristos 	"Request refused because home network does not support "
939c74ad251Schristos 	  "request",								/* 64 */
940c74ad251Schristos 	"Advertisement Server in the network is not currently "
941c74ad251Schristos 	  "reachable",								/* 65 */
942c74ad251Schristos 	"Reserved",									/* 66 */
943c74ad251Schristos 	"Request refused due to permissions received via SSPN "
944c74ad251Schristos 	  "interface",								/* 67 */
945c74ad251Schristos 	"Request refused because the AP or PCP does not "
946c74ad251Schristos 	  "support unauthenticated access",			/* 68 */
947c74ad251Schristos 	"Reserved",									/* 69 */
948c74ad251Schristos 	"Reserved",									/* 70 */
949c74ad251Schristos 	"Reserved",									/* 71 */
950c74ad251Schristos 	"Invalid contents of RSNE",				/* 72 */
951c74ad251Schristos 	"U-APSD coexistence is not supported",		/* 73 */
952c74ad251Schristos 	"Requested U-APSD coexistence mode is not supported", /* 74 */
953c74ad251Schristos 	"Requested Interval/Duration value cannot be "
954c74ad251Schristos 	  "supported with U-APSD coexistence",		/* 75 */
955c74ad251Schristos 	"Authentication is rejected because an Anti-Clogging "
956c74ad251Schristos 	  "Token is required",						/* 76 */
957c74ad251Schristos 	"Authentication is rejected because the offered "
958c74ad251Schristos 	  "finite cyclic group is not supported",	/* 77 */
959c74ad251Schristos 	"The TBTT adjustment request has not been successful "
960c74ad251Schristos 	  "because the STA could not find an alternative TBTT", /* 78 */
961c74ad251Schristos 	"Transmission failure",						/* 79 */
962c74ad251Schristos 	"Requested TCLAS Not Supported",			/* 80 */
963c74ad251Schristos 	"TCLAS Resources Exhausted",				/* 81 */
964c74ad251Schristos 	"Rejected with Suggested BSS transition",	/* 82 */
965c74ad251Schristos 	"Reject with recommended schedule",			/* 83 */
966c74ad251Schristos 	"Reject because no wakeup schedule specified", /* 84 */
967c74ad251Schristos 	"Success, the destination STA is in power save mode", /* 85 */
968c74ad251Schristos 	"FST pending, in process of admitting FST session", /* 86 */
969c74ad251Schristos 	"Performing FST now",						/* 87 */
970c74ad251Schristos 	"FST pending, gap(s) in block ack window",	/* 88 */
971c74ad251Schristos 	"Reject because of U-PID setting",			/* 89 */
972c74ad251Schristos 	"Reserved",									/* 90 */
973c74ad251Schristos 	"Reserved",									/* 91 */
974c74ad251Schristos 	"(Re)Association refused for some external reason", /* 92 */
975c74ad251Schristos 	"(Re)Association refused because of memory limits "
976c74ad251Schristos 	  "at the AP",								/* 93 */
977c74ad251Schristos 	"(Re)Association refused because emergency services "
978c74ad251Schristos 	  "are not supported at the AP",			/* 94 */
979c74ad251Schristos 	"GAS query response not yet received",		/* 95 */
980c74ad251Schristos 	"Reject since the request is for transition to a "
981c74ad251Schristos 	  "frequency band subject to DSE procedures and "
982c74ad251Schristos 	  "FST Initiator is a dependent STA",		/* 96 */
983c74ad251Schristos 	"Requested TCLAS processing has been terminated by "
984c74ad251Schristos 	  "the AP",									/* 97 */
985c74ad251Schristos 	"The TS schedule conflicts with an existing "
986c74ad251Schristos 	  "schedule; an alternative schedule is provided", /* 98 */
987c74ad251Schristos 	"The association has been denied; however, one or "
988c74ad251Schristos 	  "more Multi-band elements are included that can "
989c74ad251Schristos 	  "be used by the receiving STA to join the BSS", /* 99 */
990c74ad251Schristos 	"The request failed due to a reservation conflict", /* 100 */
991c74ad251Schristos 	"The request failed due to exceeded MAF limit", /* 101 */
992c74ad251Schristos 	"The request failed due to exceeded MCCA track "
993c74ad251Schristos 	  "limit",									/* 102 */
994c74ad251Schristos 	"Association denied because the information in the"
995c74ad251Schristos 	  "Spectrum Management field is unacceptable", /* 103 */
996c74ad251Schristos 	"Association denied because the requesting STA "
997c74ad251Schristos 	  "does not support VHT features",			/* 104 */
998c74ad251Schristos 	"Enablement denied",						/* 105 */
999c74ad251Schristos 	"Enablement denied due to restriction from an "
1000c74ad251Schristos 	  "authorized GDB",							/* 106 */
1001c74ad251Schristos 	"Authorization deenabled",					/* 107 */
10020f74e101Schristos };
1003c74ad251Schristos #define NUM_STATUSES	(sizeof(status_text) / sizeof(status_text[0]))
10040f74e101Schristos 
10050f74e101Schristos static const char *reason_text[] = {
10060f74e101Schristos 	"Reserved",						/* 0 */
10070f74e101Schristos 	"Unspecified reason",					/* 1 */
10080f74e101Schristos 	"Previous authentication no longer valid",		/* 2 */
1009c74ad251Schristos 	"Deauthenticated because sending STA is leaving (or has left) "
10100f74e101Schristos 	  "IBSS or ESS",					/* 3 */
10110f74e101Schristos 	"Disassociated due to inactivity",			/* 4 */
10120f74e101Schristos 	"Disassociated because AP is unable to handle all currently "
1013c74ad251Schristos 	  " associated STAs",				/* 5 */
1014c74ad251Schristos 	"Class 2 frame received from nonauthenticated STA", /* 6 */
1015c74ad251Schristos 	"Class 3 frame received from nonassociated STA",	/* 7 */
1016c74ad251Schristos 	"Disassociated because sending STA is leaving "
10170f74e101Schristos 	  "(or has left) BSS",					/* 8 */
1018c74ad251Schristos 	"STA requesting (re)association is not authenticated with "
1019c74ad251Schristos 	  "responding STA",					/* 9 */
10200f74e101Schristos 	"Disassociated because the information in the Power Capability "
10210f74e101Schristos 	  "element is unacceptable",				/* 10 */
10220f74e101Schristos 	"Disassociated because the information in the Supported Channels "
10230f74e101Schristos 	  "element is unacceptable",				/* 11 */
1024c74ad251Schristos 	"Disassociated due to BSS transition management",	/* 12 */
1025c74ad251Schristos 	"Invalid element, i.e., an element defined in this standard for "
1026c74ad251Schristos 	  "which the content does not meet the specifications "
1027c74ad251Schristos 	  "in Clause 9",						/* 13 */
1028c74ad251Schristos 	"Message integrity code (MIC) failure",	/* 14 */
10290f74e101Schristos 	"4-Way Handshake timeout",				/* 15 */
1030c74ad251Schristos 	"Group key handshake timeout",			/* 16 */
10310f74e101Schristos 	"Information element in 4-Way Handshake different from (Re)Association"
1032c74ad251Schristos 	  "Request/Probe Response/Beacon frame",	/* 17 */
1033c74ad251Schristos 	"Invalid group cipher",					/* 18 */
1034c74ad251Schristos 	"Invalid pairwise cipher",				/* 19 */
1035c74ad251Schristos 	"Invalid AKMP",							/* 20 */
1036c74ad251Schristos 	"Unsupported RSNE version",				/* 21 */
1037c74ad251Schristos 	"Invalid RSNE capabilities",				/* 22 */
1038c74ad251Schristos 	"IEEE 802.1X authentication failed",			/* 23 */
1039c74ad251Schristos 	"Cipher suite rejected because of the security policy",		/* 24 */
1040c74ad251Schristos 	"TDLS direct-link teardown due to TDLS peer STA "
1041c74ad251Schristos 	  "unreachable via the TDLS direct link",				/* 25 */
1042c74ad251Schristos 	"TDLS direct-link teardown for unspecified reason",		/* 26 */
1043c74ad251Schristos 	"Disassociated because session terminated by SSP request",/* 27 */
1044c74ad251Schristos 	"Disassociated because of lack of SSP roaming agreement",/* 28 */
1045c74ad251Schristos 	"Requested service rejected because of SSP cipher suite or "
1046c74ad251Schristos 	  "AKM requirement",						/* 29 */
1047c74ad251Schristos 	"Requested service not authorized in this location",	/* 30 */
10480f74e101Schristos 	"TS deleted because QoS AP lacks sufficient bandwidth for this "
10490f74e101Schristos 	  "QoS STA due to a change in BSS service characteristics or "
10500f74e101Schristos 	  "operational mode (e.g. an HT BSS change from 40 MHz channel "
10510f74e101Schristos 	  "to 20 MHz channel)",					/* 31 */
10520f74e101Schristos 	"Disassociated for unspecified, QoS-related reason",	/* 32 */
10530f74e101Schristos 	"Disassociated because QoS AP lacks sufficient bandwidth for this "
10540f74e101Schristos 	  "QoS STA",						/* 33 */
10550f74e101Schristos 	"Disassociated because of excessive number of frames that need to be "
1056c74ad251Schristos 	  "acknowledged, but are not acknowledged due to AP transmissions "
10570f74e101Schristos 	  "and/or poor channel conditions",			/* 34 */
10580f74e101Schristos 	"Disassociated because STA is transmitting outside the limits "
10590f74e101Schristos 	  "of its TXOPs",					/* 35 */
10600f74e101Schristos 	"Requested from peer STA as the STA is leaving the BSS "
10610f74e101Schristos 	  "(or resetting)",					/* 36 */
10620f74e101Schristos 	"Requested from peer STA as it does not want to use the "
10630f74e101Schristos 	  "mechanism",						/* 37 */
10640f74e101Schristos 	"Requested from peer STA as the STA received frames using the "
10650f74e101Schristos 	  "mechanism for which a set up is required",		/* 38 */
10660f74e101Schristos 	"Requested from peer STA due to time out",		/* 39 */
10670f74e101Schristos 	"Reserved",						/* 40 */
10680f74e101Schristos 	"Reserved",						/* 41 */
10690f74e101Schristos 	"Reserved",						/* 42 */
10700f74e101Schristos 	"Reserved",						/* 43 */
10710f74e101Schristos 	"Reserved",						/* 44 */
10720f74e101Schristos 	"Peer STA does not support the requested cipher suite",	/* 45 */
1073c74ad251Schristos 	"In a DLS Teardown frame: The teardown was initiated by the "
1074c74ad251Schristos 	  "DLS peer. In a Disassociation frame: Disassociated because "
1075c74ad251Schristos 	  "authorized access limit reached",					/* 46 */
1076c74ad251Schristos 	"In a DLS Teardown frame: The teardown was initiated by the "
1077c74ad251Schristos 	  "AP. In a Disassociation frame: Disassociated due to external "
1078c74ad251Schristos 	  "service requirements",								/* 47 */
1079c74ad251Schristos 	"Invalid FT Action frame count",						/* 48 */
1080c74ad251Schristos 	"Invalid pairwise master key identifier (PMKID)",		/* 49 */
1081c74ad251Schristos 	"Invalid MDE",											/* 50 */
1082c74ad251Schristos 	"Invalid FTE",											/* 51 */
1083c74ad251Schristos 	"Mesh peering canceled for unknown reasons",			/* 52 */
1084c74ad251Schristos 	"The mesh STA has reached the supported maximum number of "
1085c74ad251Schristos 	  "peer mesh STAs",										/* 53 */
1086c74ad251Schristos 	"The received information violates the Mesh Configuration "
1087c74ad251Schristos 	  "policy configured in the mesh STA profile",			/* 54 */
1088c74ad251Schristos 	"The mesh STA has received a Mesh Peering Close frame "
1089c74ad251Schristos 	  "requesting to close the mesh peering",				/* 55 */
1090c74ad251Schristos 	"The mesh STA has resent dot11MeshMaxRetries Mesh "
1091c74ad251Schristos 	  "Peering Open frames, without receiving a Mesh Peering "
1092c74ad251Schristos 	  "Confirm frame",										/* 56 */
1093c74ad251Schristos 	"The confirmTimer for the mesh peering instance times out",	/* 57 */
1094c74ad251Schristos 	"The mesh STA fails to unwrap the GTK or the values in the "
1095c74ad251Schristos 	  "wrapped contents do not match",						/* 58 */
1096c74ad251Schristos 	"The mesh STA receives inconsistent information about the "
1097c74ad251Schristos 	  "mesh parameters between mesh peering Management frames",	/* 59 */
1098c74ad251Schristos 	"The mesh STA fails the authenticated mesh peering exchange "
1099c74ad251Schristos 	  "because due to failure in selecting either the pairwise "
1100c74ad251Schristos 	  "ciphersuite or group ciphersuite",					/* 60 */
1101c74ad251Schristos 	"The mesh STA does not have proxy information for this "
1102c74ad251Schristos 	  "external destination",								/* 61 */
1103c74ad251Schristos 	"The mesh STA does not have forwarding information for this "
1104c74ad251Schristos 	  "destination",										/* 62 */
1105c74ad251Schristos 	"The mesh STA determines that the link to the next hop of an "
1106c74ad251Schristos 	  "active path in its forwarding information is no longer "
1107c74ad251Schristos 	  "usable",												/* 63 */
1108c74ad251Schristos 	"The Deauthentication frame was sent because the MAC "
1109c74ad251Schristos 	  "address of the STA already exists in the mesh BSS",	/* 64 */
1110c74ad251Schristos 	"The mesh STA performs channel switch to meet regulatory "
1111c74ad251Schristos 	  "requirements",										/* 65 */
1112c74ad251Schristos 	"The mesh STA performs channel switching with unspecified "
1113c74ad251Schristos 	  "reason",												/* 66 */
11140f74e101Schristos };
1115c74ad251Schristos #define NUM_REASONS	(sizeof(reason_text) / sizeof(reason_text[0]))
11160f74e101Schristos 
11170f74e101Schristos static int
1118b3a00663Schristos wep_print(netdissect_options *ndo,
1119b3a00663Schristos 	  const u_char *p)
11200f74e101Schristos {
1121b3a00663Schristos 	uint32_t iv;
11220f74e101Schristos 
1123c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN);
1124c74ad251Schristos 	iv = GET_LE_U_4(p);
11250f74e101Schristos 
1126c74ad251Schristos 	ND_PRINT(" IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
1127c74ad251Schristos 	    IV_KEYID(iv));
11280f74e101Schristos 
11290f74e101Schristos 	return 1;
1130c74ad251Schristos trunc:
1131c74ad251Schristos 	return 0;
11320f74e101Schristos }
11330f74e101Schristos 
11340f74e101Schristos static int
1135b3a00663Schristos parse_elements(netdissect_options *ndo,
1136b3a00663Schristos 	       struct mgmt_body_t *pbody, const u_char *p, int offset,
11370f74e101Schristos 	       u_int length)
11380f74e101Schristos {
11390e9868baSchristos 	u_int elementlen;
11400f74e101Schristos 	struct ssid_t ssid;
11410f74e101Schristos 	struct challenge_t challenge;
11420f74e101Schristos 	struct rates_t rates;
11430f74e101Schristos 	struct ds_t ds;
11440f74e101Schristos 	struct cf_t cf;
11450f74e101Schristos 	struct tim_t tim;
11460f74e101Schristos 
11470f74e101Schristos 	/*
11480f74e101Schristos 	 * We haven't seen any elements yet.
11490f74e101Schristos 	 */
11500f74e101Schristos 	pbody->challenge_present = 0;
11510f74e101Schristos 	pbody->ssid_present = 0;
11520f74e101Schristos 	pbody->rates_present = 0;
11530f74e101Schristos 	pbody->ds_present = 0;
11540f74e101Schristos 	pbody->cf_present = 0;
11550f74e101Schristos 	pbody->tim_present = 0;
11560f74e101Schristos 
11570f74e101Schristos 	while (length != 0) {
1158b3a00663Schristos 		/* Make sure we at least have the element ID and length. */
1159c74ad251Schristos 		ND_TCHECK_2(p + offset);
11600f74e101Schristos 		if (length < 2)
1161c74ad251Schristos 			goto trunc;
1162c74ad251Schristos 		elementlen = GET_U_1(p + offset + 1);
1163b3a00663Schristos 
1164b3a00663Schristos 		/* Make sure we have the entire element. */
1165c74ad251Schristos 		ND_TCHECK_LEN(p + offset + 2, elementlen);
1166b3a00663Schristos 		if (length < elementlen + 2)
1167c74ad251Schristos 			goto trunc;
1168b3a00663Schristos 
1169c74ad251Schristos 		switch (GET_U_1(p + offset)) {
1170b3a00663Schristos 		case E_SSID:
1171*26ba0b50Schristos 			ssid.length = elementlen;
11720f74e101Schristos 			offset += 2;
11730f74e101Schristos 			length -= 2;
11740f74e101Schristos 			if (ssid.length != 0) {
11750f74e101Schristos 				if (ssid.length > sizeof(ssid.ssid) - 1)
11760f74e101Schristos 					return 0;
11770f74e101Schristos 				memcpy(&ssid.ssid, p + offset, ssid.length);
11780f74e101Schristos 				offset += ssid.length;
11790f74e101Schristos 				length -= ssid.length;
11800f74e101Schristos 			}
11810f74e101Schristos 			ssid.ssid[ssid.length] = '\0';
11820f74e101Schristos 			/*
11830f74e101Schristos 			 * Present and not truncated.
11840f74e101Schristos 			 *
11850f74e101Schristos 			 * If we haven't already seen an SSID IE,
11860f74e101Schristos 			 * copy this one, otherwise ignore this one,
11870f74e101Schristos 			 * so we later report the first one we saw.
11880f74e101Schristos 			 */
11890f74e101Schristos 			if (!pbody->ssid_present) {
11900f74e101Schristos 				pbody->ssid = ssid;
11910f74e101Schristos 				pbody->ssid_present = 1;
11920f74e101Schristos 			}
11930f74e101Schristos 			break;
11940f74e101Schristos 		case E_CHALLENGE:
1195*26ba0b50Schristos 			challenge.length = elementlen;
11960f74e101Schristos 			offset += 2;
11970f74e101Schristos 			length -= 2;
11980f74e101Schristos 			if (challenge.length != 0) {
11990f74e101Schristos 				if (challenge.length >
12000f74e101Schristos 				    sizeof(challenge.text) - 1)
12010f74e101Schristos 					return 0;
12020f74e101Schristos 				memcpy(&challenge.text, p + offset,
12030f74e101Schristos 				    challenge.length);
12040f74e101Schristos 				offset += challenge.length;
12050f74e101Schristos 				length -= challenge.length;
12060f74e101Schristos 			}
12070f74e101Schristos 			challenge.text[challenge.length] = '\0';
12080f74e101Schristos 			/*
12090f74e101Schristos 			 * Present and not truncated.
12100f74e101Schristos 			 *
12110f74e101Schristos 			 * If we haven't already seen a challenge IE,
12120f74e101Schristos 			 * copy this one, otherwise ignore this one,
12130f74e101Schristos 			 * so we later report the first one we saw.
12140f74e101Schristos 			 */
12150f74e101Schristos 			if (!pbody->challenge_present) {
12160f74e101Schristos 				pbody->challenge = challenge;
12170f74e101Schristos 				pbody->challenge_present = 1;
12180f74e101Schristos 			}
12190f74e101Schristos 			break;
12200f74e101Schristos 		case E_RATES:
1221*26ba0b50Schristos 			rates.length = elementlen;
12220f74e101Schristos 			offset += 2;
12230f74e101Schristos 			length -= 2;
12240f74e101Schristos 			if (rates.length != 0) {
1225c74ad251Schristos 				if (rates.length > sizeof(rates.rate))
12260f74e101Schristos 					return 0;
12270f74e101Schristos 				memcpy(&rates.rate, p + offset, rates.length);
12280f74e101Schristos 				offset += rates.length;
12290f74e101Schristos 				length -= rates.length;
12300f74e101Schristos 			}
12310f74e101Schristos 			/*
12320f74e101Schristos 			 * Present and not truncated.
12330f74e101Schristos 			 *
12340f74e101Schristos 			 * If we haven't already seen a rates IE,
12350f74e101Schristos 			 * copy this one if it's not zero-length,
12360f74e101Schristos 			 * otherwise ignore this one, so we later
12370f74e101Schristos 			 * report the first one we saw.
12380f74e101Schristos 			 *
12390f74e101Schristos 			 * We ignore zero-length rates IEs as some
12400f74e101Schristos 			 * devices seem to put a zero-length rates
12410f74e101Schristos 			 * IE, followed by an SSID IE, followed by
12420f74e101Schristos 			 * a non-zero-length rates IE into frames,
12430f74e101Schristos 			 * even though IEEE Std 802.11-2007 doesn't
12440f74e101Schristos 			 * seem to indicate that a zero-length rates
12450f74e101Schristos 			 * IE is valid.
12460f74e101Schristos 			 */
12470f74e101Schristos 			if (!pbody->rates_present && rates.length != 0) {
12480f74e101Schristos 				pbody->rates = rates;
12490f74e101Schristos 				pbody->rates_present = 1;
12500f74e101Schristos 			}
12510f74e101Schristos 			break;
12520f74e101Schristos 		case E_DS:
1253*26ba0b50Schristos 			ds.length = elementlen;
1254b3a00663Schristos 			offset += 2;
1255b3a00663Schristos 			length -= 2;
1256b3a00663Schristos 			if (ds.length != 1) {
1257b3a00663Schristos 				offset += ds.length;
1258b3a00663Schristos 				length -= ds.length;
1259b3a00663Schristos 				break;
1260b3a00663Schristos 			}
1261c74ad251Schristos 			ds.channel = GET_U_1(p + offset);
1262b3a00663Schristos 			offset += 1;
1263b3a00663Schristos 			length -= 1;
12640f74e101Schristos 			/*
12650f74e101Schristos 			 * Present and not truncated.
12660f74e101Schristos 			 *
12670f74e101Schristos 			 * If we haven't already seen a DS IE,
12680f74e101Schristos 			 * copy this one, otherwise ignore this one,
12690f74e101Schristos 			 * so we later report the first one we saw.
12700f74e101Schristos 			 */
12710f74e101Schristos 			if (!pbody->ds_present) {
12720f74e101Schristos 				pbody->ds = ds;
12730f74e101Schristos 				pbody->ds_present = 1;
12740f74e101Schristos 			}
12750f74e101Schristos 			break;
12760f74e101Schristos 		case E_CF:
1277*26ba0b50Schristos 			cf.length = elementlen;
1278b3a00663Schristos 			offset += 2;
1279b3a00663Schristos 			length -= 2;
1280b3a00663Schristos 			if (cf.length != 6) {
1281b3a00663Schristos 				offset += cf.length;
1282b3a00663Schristos 				length -= cf.length;
1283b3a00663Schristos 				break;
1284b3a00663Schristos 			}
1285c74ad251Schristos 			cf.count = GET_U_1(p + offset);
1286c74ad251Schristos 			offset += 1;
1287c74ad251Schristos 			length -= 1;
1288c74ad251Schristos 			cf.period = GET_U_1(p + offset);
1289c74ad251Schristos 			offset += 1;
1290c74ad251Schristos 			length -= 1;
1291c74ad251Schristos 			cf.max_duration = GET_LE_U_2(p + offset);
1292c74ad251Schristos 			offset += 2;
1293c74ad251Schristos 			length -= 2;
1294c74ad251Schristos 			cf.dur_remaining = GET_LE_U_2(p + offset);
1295c74ad251Schristos 			offset += 2;
1296c74ad251Schristos 			length -= 2;
12970f74e101Schristos 			/*
12980f74e101Schristos 			 * Present and not truncated.
12990f74e101Schristos 			 *
13000f74e101Schristos 			 * If we haven't already seen a CF IE,
13010f74e101Schristos 			 * copy this one, otherwise ignore this one,
13020f74e101Schristos 			 * so we later report the first one we saw.
13030f74e101Schristos 			 */
13040f74e101Schristos 			if (!pbody->cf_present) {
13050f74e101Schristos 				pbody->cf = cf;
13060f74e101Schristos 				pbody->cf_present = 1;
13070f74e101Schristos 			}
13080f74e101Schristos 			break;
13090f74e101Schristos 		case E_TIM:
1310*26ba0b50Schristos 			tim.length = elementlen;
13110f74e101Schristos 			offset += 2;
13120f74e101Schristos 			length -= 2;
1313c74ad251Schristos 			if (tim.length <= 3U) {
1314b3a00663Schristos 				offset += tim.length;
1315b3a00663Schristos 				length -= tim.length;
1316b3a00663Schristos 				break;
1317b3a00663Schristos 			}
1318c74ad251Schristos 			if (tim.length - 3U > sizeof(tim.bitmap))
13190f74e101Schristos 				return 0;
1320c74ad251Schristos 			tim.count = GET_U_1(p + offset);
1321c74ad251Schristos 			offset += 1;
1322c74ad251Schristos 			length -= 1;
1323c74ad251Schristos 			tim.period = GET_U_1(p + offset);
1324c74ad251Schristos 			offset += 1;
1325c74ad251Schristos 			length -= 1;
1326c74ad251Schristos 			tim.bitmap_control = GET_U_1(p + offset);
1327c74ad251Schristos 			offset += 1;
1328c74ad251Schristos 			length -= 1;
132972c96ff3Schristos 			memcpy(tim.bitmap, p + offset, tim.length - 3);
13300f74e101Schristos 			offset += tim.length - 3;
13310f74e101Schristos 			length -= tim.length - 3;
13320f74e101Schristos 			/*
13330f74e101Schristos 			 * Present and not truncated.
13340f74e101Schristos 			 *
13350f74e101Schristos 			 * If we haven't already seen a TIM IE,
13360f74e101Schristos 			 * copy this one, otherwise ignore this one,
13370f74e101Schristos 			 * so we later report the first one we saw.
13380f74e101Schristos 			 */
13390f74e101Schristos 			if (!pbody->tim_present) {
13400f74e101Schristos 				pbody->tim = tim;
13410f74e101Schristos 				pbody->tim_present = 1;
13420f74e101Schristos 			}
13430f74e101Schristos 			break;
13440f74e101Schristos 		default:
13450f74e101Schristos #if 0
1346c74ad251Schristos 			ND_PRINT("(1) unhandled element_id (%u)  ",
1347c74ad251Schristos 			    GET_U_1(p + offset));
13480f74e101Schristos #endif
1349b3a00663Schristos 			offset += 2 + elementlen;
1350b3a00663Schristos 			length -= 2 + elementlen;
13510f74e101Schristos 			break;
13520f74e101Schristos 		}
13530f74e101Schristos 	}
13540f74e101Schristos 
13550f74e101Schristos 	/* No problems found. */
13560f74e101Schristos 	return 1;
1357c74ad251Schristos trunc:
1358c74ad251Schristos 	return 0;
13590f74e101Schristos }
13600f74e101Schristos 
13610f74e101Schristos /*********************************************************************************
13620f74e101Schristos  * Print Handle functions for the management frame types
13630f74e101Schristos  *********************************************************************************/
13640f74e101Schristos 
13650f74e101Schristos static int
1366b3a00663Schristos handle_beacon(netdissect_options *ndo,
1367b3a00663Schristos 	      const u_char *p, u_int length)
13680f74e101Schristos {
13690f74e101Schristos 	struct mgmt_body_t pbody;
13700f74e101Schristos 	int offset = 0;
13710f74e101Schristos 	int ret;
13720f74e101Schristos 
13730f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
13740f74e101Schristos 
1375c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1376c74ad251Schristos 		      IEEE802_11_CAPINFO_LEN);
13770f74e101Schristos 	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
13780f74e101Schristos 	    IEEE802_11_CAPINFO_LEN)
1379c74ad251Schristos 		goto trunc;
13800f74e101Schristos 	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
13810f74e101Schristos 	offset += IEEE802_11_TSTAMP_LEN;
13820f74e101Schristos 	length -= IEEE802_11_TSTAMP_LEN;
1383c74ad251Schristos 	pbody.beacon_interval = GET_LE_U_2(p + offset);
13840f74e101Schristos 	offset += IEEE802_11_BCNINT_LEN;
13850f74e101Schristos 	length -= IEEE802_11_BCNINT_LEN;
1386c74ad251Schristos 	pbody.capability_info = GET_LE_U_2(p + offset);
13870f74e101Schristos 	offset += IEEE802_11_CAPINFO_LEN;
13880f74e101Schristos 	length -= IEEE802_11_CAPINFO_LEN;
13890f74e101Schristos 
1390b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
13910f74e101Schristos 
13920f74e101Schristos 	PRINT_SSID(pbody);
13930f74e101Schristos 	PRINT_RATES(pbody);
1394c74ad251Schristos 	ND_PRINT(" %s",
1395c74ad251Schristos 	    CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
13960f74e101Schristos 	PRINT_DS_CHANNEL(pbody);
13970f74e101Schristos 
13980f74e101Schristos 	return ret;
1399c74ad251Schristos trunc:
1400c74ad251Schristos 	return 0;
14010f74e101Schristos }
14020f74e101Schristos 
14030f74e101Schristos static int
1404b3a00663Schristos handle_assoc_request(netdissect_options *ndo,
1405b3a00663Schristos 		     const u_char *p, u_int length)
14060f74e101Schristos {
14070f74e101Schristos 	struct mgmt_body_t pbody;
14080f74e101Schristos 	int offset = 0;
14090f74e101Schristos 	int ret;
14100f74e101Schristos 
14110f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
14120f74e101Schristos 
1413c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN);
14140f74e101Schristos 	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
1415c74ad251Schristos 		goto trunc;
1416c74ad251Schristos 	pbody.capability_info = GET_LE_U_2(p);
14170f74e101Schristos 	offset += IEEE802_11_CAPINFO_LEN;
14180f74e101Schristos 	length -= IEEE802_11_CAPINFO_LEN;
1419c74ad251Schristos 	pbody.listen_interval = GET_LE_U_2(p + offset);
14200f74e101Schristos 	offset += IEEE802_11_LISTENINT_LEN;
14210f74e101Schristos 	length -= IEEE802_11_LISTENINT_LEN;
14220f74e101Schristos 
1423b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
14240f74e101Schristos 
14250f74e101Schristos 	PRINT_SSID(pbody);
14260f74e101Schristos 	PRINT_RATES(pbody);
14270f74e101Schristos 	return ret;
1428c74ad251Schristos trunc:
1429c74ad251Schristos 	return 0;
14300f74e101Schristos }
14310f74e101Schristos 
14320f74e101Schristos static int
1433b3a00663Schristos handle_assoc_response(netdissect_options *ndo,
1434b3a00663Schristos 		      const u_char *p, u_int length)
14350f74e101Schristos {
14360f74e101Schristos 	struct mgmt_body_t pbody;
14370f74e101Schristos 	int offset = 0;
14380f74e101Schristos 	int ret;
14390f74e101Schristos 
14400f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
14410f74e101Schristos 
1442c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1443c74ad251Schristos 		      IEEE802_11_AID_LEN);
14440f74e101Schristos 	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
14450f74e101Schristos 	    IEEE802_11_AID_LEN)
1446c74ad251Schristos 		goto trunc;
1447c74ad251Schristos 	pbody.capability_info = GET_LE_U_2(p);
14480f74e101Schristos 	offset += IEEE802_11_CAPINFO_LEN;
14490f74e101Schristos 	length -= IEEE802_11_CAPINFO_LEN;
1450c74ad251Schristos 	pbody.status_code = GET_LE_U_2(p + offset);
14510f74e101Schristos 	offset += IEEE802_11_STATUS_LEN;
14520f74e101Schristos 	length -= IEEE802_11_STATUS_LEN;
1453c74ad251Schristos 	pbody.aid = GET_LE_U_2(p + offset);
14540f74e101Schristos 	offset += IEEE802_11_AID_LEN;
14550f74e101Schristos 	length -= IEEE802_11_AID_LEN;
14560f74e101Schristos 
1457b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
14580f74e101Schristos 
1459c74ad251Schristos 	ND_PRINT(" AID(%x) :%s: %s", ((uint16_t)(pbody.aid << 2 )) >> 2 ,
14600f74e101Schristos 	    CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
14610f74e101Schristos 	    (pbody.status_code < NUM_STATUSES
14620f74e101Schristos 		? status_text[pbody.status_code]
1463c74ad251Schristos 		: "n/a"));
14640f74e101Schristos 
14650f74e101Schristos 	return ret;
1466c74ad251Schristos trunc:
1467c74ad251Schristos 	return 0;
14680f74e101Schristos }
14690f74e101Schristos 
14700f74e101Schristos static int
1471b3a00663Schristos handle_reassoc_request(netdissect_options *ndo,
1472b3a00663Schristos 		       const u_char *p, u_int length)
14730f74e101Schristos {
14740f74e101Schristos 	struct mgmt_body_t pbody;
14750f74e101Schristos 	int offset = 0;
14760f74e101Schristos 	int ret;
14770f74e101Schristos 
14780f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
14790f74e101Schristos 
1480c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1481c74ad251Schristos 		      IEEE802_11_AP_LEN);
14820f74e101Schristos 	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
14830f74e101Schristos 	    IEEE802_11_AP_LEN)
1484c74ad251Schristos 		goto trunc;
1485c74ad251Schristos 	pbody.capability_info = GET_LE_U_2(p);
14860f74e101Schristos 	offset += IEEE802_11_CAPINFO_LEN;
14870f74e101Schristos 	length -= IEEE802_11_CAPINFO_LEN;
1488c74ad251Schristos 	pbody.listen_interval = GET_LE_U_2(p + offset);
14890f74e101Schristos 	offset += IEEE802_11_LISTENINT_LEN;
14900f74e101Schristos 	length -= IEEE802_11_LISTENINT_LEN;
14910f74e101Schristos 	memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
14920f74e101Schristos 	offset += IEEE802_11_AP_LEN;
14930f74e101Schristos 	length -= IEEE802_11_AP_LEN;
14940f74e101Schristos 
1495b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
14960f74e101Schristos 
14970f74e101Schristos 	PRINT_SSID(pbody);
1498c74ad251Schristos 	ND_PRINT(" AP : %s", etheraddr_string(ndo,  pbody.ap ));
14990f74e101Schristos 
15000f74e101Schristos 	return ret;
1501c74ad251Schristos trunc:
1502c74ad251Schristos 	return 0;
15030f74e101Schristos }
15040f74e101Schristos 
15050f74e101Schristos static int
1506b3a00663Schristos handle_reassoc_response(netdissect_options *ndo,
1507b3a00663Schristos 			const u_char *p, u_int length)
15080f74e101Schristos {
1509c74ad251Schristos 	/* Same as a Association Response */
1510b3a00663Schristos 	return handle_assoc_response(ndo, p, length);
15110f74e101Schristos }
15120f74e101Schristos 
15130f74e101Schristos static int
1514b3a00663Schristos handle_probe_request(netdissect_options *ndo,
1515b3a00663Schristos 		     const u_char *p, u_int length)
15160f74e101Schristos {
15170f74e101Schristos 	struct mgmt_body_t  pbody;
15180f74e101Schristos 	int offset = 0;
15190f74e101Schristos 	int ret;
15200f74e101Schristos 
15210f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
15220f74e101Schristos 
1523b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
15240f74e101Schristos 
15250f74e101Schristos 	PRINT_SSID(pbody);
15260f74e101Schristos 	PRINT_RATES(pbody);
15270f74e101Schristos 
15280f74e101Schristos 	return ret;
15290f74e101Schristos }
15300f74e101Schristos 
15310f74e101Schristos static int
1532b3a00663Schristos handle_probe_response(netdissect_options *ndo,
1533b3a00663Schristos 		      const u_char *p, u_int length)
15340f74e101Schristos {
15350f74e101Schristos 	struct mgmt_body_t  pbody;
15360f74e101Schristos 	int offset = 0;
15370f74e101Schristos 	int ret;
15380f74e101Schristos 
15390f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
15400f74e101Schristos 
1541c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1542c74ad251Schristos 		      IEEE802_11_CAPINFO_LEN);
15430f74e101Schristos 	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
15440f74e101Schristos 	    IEEE802_11_CAPINFO_LEN)
1545c74ad251Schristos 		goto trunc;
15460f74e101Schristos 	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
15470f74e101Schristos 	offset += IEEE802_11_TSTAMP_LEN;
15480f74e101Schristos 	length -= IEEE802_11_TSTAMP_LEN;
1549c74ad251Schristos 	pbody.beacon_interval = GET_LE_U_2(p + offset);
15500f74e101Schristos 	offset += IEEE802_11_BCNINT_LEN;
15510f74e101Schristos 	length -= IEEE802_11_BCNINT_LEN;
1552c74ad251Schristos 	pbody.capability_info = GET_LE_U_2(p + offset);
15530f74e101Schristos 	offset += IEEE802_11_CAPINFO_LEN;
15540f74e101Schristos 	length -= IEEE802_11_CAPINFO_LEN;
15550f74e101Schristos 
1556b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
15570f74e101Schristos 
15580f74e101Schristos 	PRINT_SSID(pbody);
15590f74e101Schristos 	PRINT_RATES(pbody);
15600f74e101Schristos 	PRINT_DS_CHANNEL(pbody);
15610f74e101Schristos 
15620f74e101Schristos 	return ret;
1563c74ad251Schristos trunc:
1564c74ad251Schristos 	return 0;
15650f74e101Schristos }
15660f74e101Schristos 
15670f74e101Schristos static int
15680f74e101Schristos handle_atim(void)
15690f74e101Schristos {
15700f74e101Schristos 	/* the frame body for ATIM is null. */
15710f74e101Schristos 	return 1;
15720f74e101Schristos }
15730f74e101Schristos 
15740f74e101Schristos static int
1575b3a00663Schristos handle_disassoc(netdissect_options *ndo,
1576b3a00663Schristos 		const u_char *p, u_int length)
15770f74e101Schristos {
15780f74e101Schristos 	struct mgmt_body_t  pbody;
15790f74e101Schristos 
15800f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
15810f74e101Schristos 
1582c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_REASON_LEN);
15830f74e101Schristos 	if (length < IEEE802_11_REASON_LEN)
1584c74ad251Schristos 		goto trunc;
1585c74ad251Schristos 	pbody.reason_code = GET_LE_U_2(p);
15860f74e101Schristos 
1587c74ad251Schristos 	ND_PRINT(": %s",
15880f74e101Schristos 	    (pbody.reason_code < NUM_REASONS)
15890f74e101Schristos 		? reason_text[pbody.reason_code]
1590c74ad251Schristos 		: "Reserved");
15910f74e101Schristos 
15920f74e101Schristos 	return 1;
1593c74ad251Schristos trunc:
1594c74ad251Schristos 	return 0;
15950f74e101Schristos }
15960f74e101Schristos 
15970f74e101Schristos static int
1598b3a00663Schristos handle_auth(netdissect_options *ndo,
1599b3a00663Schristos 	    const u_char *p, u_int length)
16000f74e101Schristos {
16010f74e101Schristos 	struct mgmt_body_t  pbody;
16020f74e101Schristos 	int offset = 0;
16030f74e101Schristos 	int ret;
16040f74e101Schristos 
16050f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
16060f74e101Schristos 
1607c74ad251Schristos 	ND_TCHECK_6(p);
16080f74e101Schristos 	if (length < 6)
1609c74ad251Schristos 		goto trunc;
1610c74ad251Schristos 	pbody.auth_alg = GET_LE_U_2(p);
16110f74e101Schristos 	offset += 2;
16120f74e101Schristos 	length -= 2;
1613c74ad251Schristos 	pbody.auth_trans_seq_num = GET_LE_U_2(p + offset);
16140f74e101Schristos 	offset += 2;
16150f74e101Schristos 	length -= 2;
1616c74ad251Schristos 	pbody.status_code = GET_LE_U_2(p + offset);
16170f74e101Schristos 	offset += 2;
16180f74e101Schristos 	length -= 2;
16190f74e101Schristos 
1620b3a00663Schristos 	ret = parse_elements(ndo, &pbody, p, offset, length);
16210f74e101Schristos 
16220f74e101Schristos 	if ((pbody.auth_alg == 1) &&
16230f74e101Schristos 	    ((pbody.auth_trans_seq_num == 2) ||
16240f74e101Schristos 	     (pbody.auth_trans_seq_num == 3))) {
1625c74ad251Schristos 		ND_PRINT(" (%s)-%x [Challenge Text] %s",
16260f74e101Schristos 		    (pbody.auth_alg < NUM_AUTH_ALGS)
16270f74e101Schristos 			? auth_alg_text[pbody.auth_alg]
16280f74e101Schristos 			: "Reserved",
16290f74e101Schristos 		    pbody.auth_trans_seq_num,
16300f74e101Schristos 		    ((pbody.auth_trans_seq_num % 2)
16310f74e101Schristos 			? ((pbody.status_code < NUM_STATUSES)
16320f74e101Schristos 			       ? status_text[pbody.status_code]
1633c74ad251Schristos 			       : "n/a") : ""));
16340f74e101Schristos 		return ret;
16350f74e101Schristos 	}
1636c74ad251Schristos 	ND_PRINT(" (%s)-%x: %s",
16370f74e101Schristos 	    (pbody.auth_alg < NUM_AUTH_ALGS)
16380f74e101Schristos 		? auth_alg_text[pbody.auth_alg]
16390f74e101Schristos 		: "Reserved",
16400f74e101Schristos 	    pbody.auth_trans_seq_num,
16410f74e101Schristos 	    (pbody.auth_trans_seq_num % 2)
16420f74e101Schristos 		? ((pbody.status_code < NUM_STATUSES)
16430f74e101Schristos 		    ? status_text[pbody.status_code]
16440f74e101Schristos 		    : "n/a")
1645c74ad251Schristos 		: "");
16460f74e101Schristos 
16470f74e101Schristos 	return ret;
1648c74ad251Schristos trunc:
1649c74ad251Schristos 	return 0;
16500f74e101Schristos }
16510f74e101Schristos 
16520f74e101Schristos static int
1653b3a00663Schristos handle_deauth(netdissect_options *ndo,
1654fdccd7e4Schristos 	      const uint8_t *src, const u_char *p, u_int length)
16550f74e101Schristos {
16560f74e101Schristos 	struct mgmt_body_t  pbody;
16570f74e101Schristos 	const char *reason = NULL;
16580f74e101Schristos 
16590f74e101Schristos 	memset(&pbody, 0, sizeof(pbody));
16600f74e101Schristos 
1661c74ad251Schristos 	ND_TCHECK_LEN(p, IEEE802_11_REASON_LEN);
16620f74e101Schristos 	if (length < IEEE802_11_REASON_LEN)
1663c74ad251Schristos 		goto trunc;
1664c74ad251Schristos 	pbody.reason_code = GET_LE_U_2(p);
16650f74e101Schristos 
16660f74e101Schristos 	reason = (pbody.reason_code < NUM_REASONS)
16670f74e101Schristos 			? reason_text[pbody.reason_code]
16680f74e101Schristos 			: "Reserved";
16690f74e101Schristos 
1670b3a00663Schristos 	if (ndo->ndo_eflag) {
1671c74ad251Schristos 		ND_PRINT(": %s", reason);
16720f74e101Schristos 	} else {
1673c74ad251Schristos 		ND_PRINT(" (%s): %s", GET_ETHERADDR_STRING(src), reason);
16740f74e101Schristos 	}
16750f74e101Schristos 	return 1;
1676c74ad251Schristos trunc:
1677c74ad251Schristos 	return 0;
16780f74e101Schristos }
16790f74e101Schristos 
16800f74e101Schristos #define	PRINT_HT_ACTION(v) (\
1681c74ad251Schristos 	(v) == 0 ? ND_PRINT("TxChWidth"): \
1682c74ad251Schristos 	(v) == 1 ? ND_PRINT("MIMOPwrSave"): \
1683c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
16840f74e101Schristos #define	PRINT_BA_ACTION(v) (\
1685c74ad251Schristos 	(v) == 0 ? ND_PRINT("ADDBA Request"): \
1686c74ad251Schristos 	(v) == 1 ? ND_PRINT("ADDBA Response"): \
1687c74ad251Schristos 	(v) == 2 ? ND_PRINT("DELBA"): \
1688c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
16890f74e101Schristos #define	PRINT_MESHLINK_ACTION(v) (\
1690c74ad251Schristos 	(v) == 0 ? ND_PRINT("Request"): \
1691c74ad251Schristos 	(v) == 1 ? ND_PRINT("Report"): \
1692c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
16930f74e101Schristos #define	PRINT_MESHPEERING_ACTION(v) (\
1694c74ad251Schristos 	(v) == 0 ? ND_PRINT("Open"): \
1695c74ad251Schristos 	(v) == 1 ? ND_PRINT("Confirm"): \
1696c74ad251Schristos 	(v) == 2 ? ND_PRINT("Close"): \
1697c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
16980f74e101Schristos #define	PRINT_MESHPATH_ACTION(v) (\
1699c74ad251Schristos 	(v) == 0 ? ND_PRINT("Request"): \
1700c74ad251Schristos 	(v) == 1 ? ND_PRINT("Report"): \
1701c74ad251Schristos 	(v) == 2 ? ND_PRINT("Error"): \
1702c74ad251Schristos 	(v) == 3 ? ND_PRINT("RootAnnouncement"): \
1703c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
17040f74e101Schristos 
1705870189d2Schristos #define PRINT_MESH_ACTION(v) (\
1706c74ad251Schristos 	(v) == 0 ? ND_PRINT("MeshLink"): \
1707c74ad251Schristos 	(v) == 1 ? ND_PRINT("HWMP"): \
1708c74ad251Schristos 	(v) == 2 ? ND_PRINT("Gate Announcement"): \
1709c74ad251Schristos 	(v) == 3 ? ND_PRINT("Congestion Control"): \
1710c74ad251Schristos 	(v) == 4 ? ND_PRINT("MCCA Setup Request"): \
1711c74ad251Schristos 	(v) == 5 ? ND_PRINT("MCCA Setup Reply"): \
1712c74ad251Schristos 	(v) == 6 ? ND_PRINT("MCCA Advertisement Request"): \
1713c74ad251Schristos 	(v) == 7 ? ND_PRINT("MCCA Advertisement"): \
1714c74ad251Schristos 	(v) == 8 ? ND_PRINT("MCCA Teardown"): \
1715c74ad251Schristos 	(v) == 9 ? ND_PRINT("TBTT Adjustment Request"): \
1716c74ad251Schristos 	(v) == 10 ? ND_PRINT("TBTT Adjustment Response"): \
1717c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
1718870189d2Schristos #define PRINT_MULTIHOP_ACTION(v) (\
1719c74ad251Schristos 	(v) == 0 ? ND_PRINT("Proxy Update"): \
1720c74ad251Schristos 	(v) == 1 ? ND_PRINT("Proxy Update Confirmation"): \
1721c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
1722870189d2Schristos #define PRINT_SELFPROT_ACTION(v) (\
1723c74ad251Schristos 	(v) == 1 ? ND_PRINT("Peering Open"): \
1724c74ad251Schristos 	(v) == 2 ? ND_PRINT("Peering Confirm"): \
1725c74ad251Schristos 	(v) == 3 ? ND_PRINT("Peering Close"): \
1726c74ad251Schristos 	(v) == 4 ? ND_PRINT("Group Key Inform"): \
1727c74ad251Schristos 	(v) == 5 ? ND_PRINT("Group Key Acknowledge"): \
1728c74ad251Schristos 		   ND_PRINT("Act#%u", (v)))
1729870189d2Schristos 
17300f74e101Schristos static int
1731b3a00663Schristos handle_action(netdissect_options *ndo,
1732fdccd7e4Schristos 	      const uint8_t *src, const u_char *p, u_int length)
17330f74e101Schristos {
1734c74ad251Schristos 	ND_TCHECK_2(p);
17350f74e101Schristos 	if (length < 2)
1736c74ad251Schristos 		goto trunc;
1737b3a00663Schristos 	if (ndo->ndo_eflag) {
1738c74ad251Schristos 		ND_PRINT(": ");
17390f74e101Schristos 	} else {
1740c74ad251Schristos 		ND_PRINT(" (%s): ", GET_ETHERADDR_STRING(src));
17410f74e101Schristos 	}
1742c74ad251Schristos 	switch (GET_U_1(p)) {
1743c74ad251Schristos 	case 0: ND_PRINT("Spectrum Management Act#%u", GET_U_1(p + 1)); break;
1744c74ad251Schristos 	case 1: ND_PRINT("QoS Act#%u", GET_U_1(p + 1)); break;
1745c74ad251Schristos 	case 2: ND_PRINT("DLS Act#%u", GET_U_1(p + 1)); break;
1746c74ad251Schristos 	case 3: ND_PRINT("BA "); PRINT_BA_ACTION(GET_U_1(p + 1)); break;
1747c74ad251Schristos 	case 7: ND_PRINT("HT "); PRINT_HT_ACTION(GET_U_1(p + 1)); break;
1748c74ad251Schristos 	case 13: ND_PRINT("MeshAction "); PRINT_MESH_ACTION(GET_U_1(p + 1)); break;
1749870189d2Schristos 	case 14:
1750*26ba0b50Schristos 		ND_PRINT("MultihopAction");
1751c74ad251Schristos 		PRINT_MULTIHOP_ACTION(GET_U_1(p + 1)); break;
1752870189d2Schristos 	case 15:
1753c74ad251Schristos 		ND_PRINT("SelfprotectAction ");
1754c74ad251Schristos 		PRINT_SELFPROT_ACTION(GET_U_1(p + 1)); break;
1755c74ad251Schristos 	case 127: ND_PRINT("Vendor Act#%u", GET_U_1(p + 1)); break;
17560f74e101Schristos 	default:
1757c74ad251Schristos 		ND_PRINT("Reserved(%u) Act#%u", GET_U_1(p), GET_U_1(p + 1));
17580f74e101Schristos 		break;
17590f74e101Schristos 	}
17600f74e101Schristos 	return 1;
1761c74ad251Schristos trunc:
1762c74ad251Schristos 	return 0;
17630f74e101Schristos }
17640f74e101Schristos 
17650f74e101Schristos 
17660f74e101Schristos /*********************************************************************************
17670f74e101Schristos  * Print Body funcs
17680f74e101Schristos  *********************************************************************************/
17690f74e101Schristos 
17700f74e101Schristos 
17710f74e101Schristos static int
1772b3a00663Schristos mgmt_body_print(netdissect_options *ndo,
1773fdccd7e4Schristos 		uint16_t fc, const uint8_t *src, const u_char *p, u_int length)
17740f74e101Schristos {
1775c74ad251Schristos 	ND_PRINT("%s", tok2str(st_str, "Unhandled Management subtype(%x)", FC_SUBTYPE(fc)));
1776fdccd7e4Schristos 
1777fdccd7e4Schristos 	/* There may be a problem w/ AP not having this bit set */
1778fdccd7e4Schristos 	if (FC_PROTECTED(fc))
1779fdccd7e4Schristos 		return wep_print(ndo, p);
17800f74e101Schristos 	switch (FC_SUBTYPE(fc)) {
17810f74e101Schristos 	case ST_ASSOC_REQUEST:
1782b3a00663Schristos 		return handle_assoc_request(ndo, p, length);
17830f74e101Schristos 	case ST_ASSOC_RESPONSE:
1784b3a00663Schristos 		return handle_assoc_response(ndo, p, length);
17850f74e101Schristos 	case ST_REASSOC_REQUEST:
1786b3a00663Schristos 		return handle_reassoc_request(ndo, p, length);
17870f74e101Schristos 	case ST_REASSOC_RESPONSE:
1788b3a00663Schristos 		return handle_reassoc_response(ndo, p, length);
17890f74e101Schristos 	case ST_PROBE_REQUEST:
1790b3a00663Schristos 		return handle_probe_request(ndo, p, length);
17910f74e101Schristos 	case ST_PROBE_RESPONSE:
1792b3a00663Schristos 		return handle_probe_response(ndo, p, length);
17930f74e101Schristos 	case ST_BEACON:
1794b3a00663Schristos 		return handle_beacon(ndo, p, length);
17950f74e101Schristos 	case ST_ATIM:
17960f74e101Schristos 		return handle_atim();
17970f74e101Schristos 	case ST_DISASSOC:
1798b3a00663Schristos 		return handle_disassoc(ndo, p, length);
17990f74e101Schristos 	case ST_AUTH:
1800b3a00663Schristos 		return handle_auth(ndo, p, length);
18010f74e101Schristos 	case ST_DEAUTH:
1802fdccd7e4Schristos 		return handle_deauth(ndo, src, p, length);
18030f74e101Schristos 	case ST_ACTION:
1804fdccd7e4Schristos 		return handle_action(ndo, src, p, length);
18050f74e101Schristos 	default:
18060f74e101Schristos 		return 1;
18070f74e101Schristos 	}
18080f74e101Schristos }
18090f74e101Schristos 
18100f74e101Schristos 
18110f74e101Schristos /*********************************************************************************
18120f74e101Schristos  * Handles printing all the control frame types
18130f74e101Schristos  *********************************************************************************/
18140f74e101Schristos 
18150f74e101Schristos static int
1816b3a00663Schristos ctrl_body_print(netdissect_options *ndo,
1817b3a00663Schristos 		uint16_t fc, const u_char *p)
18180f74e101Schristos {
1819c74ad251Schristos 	ND_PRINT("%s", tok2str(ctrl_str, "Unknown Ctrl Subtype", FC_SUBTYPE(fc)));
18200f74e101Schristos 	switch (FC_SUBTYPE(fc)) {
18210f74e101Schristos 	case CTRL_CONTROL_WRAPPER:
18220f74e101Schristos 		/* XXX - requires special handling */
18230f74e101Schristos 		break;
18240f74e101Schristos 	case CTRL_BAR:
1825c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_BAR_HDRLEN);
1826b3a00663Schristos 		if (!ndo->ndo_eflag)
1827c74ad251Schristos 			ND_PRINT(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
1828c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ra),
1829c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ta),
1830c74ad251Schristos 			    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->ctl),
1831c74ad251Schristos 			    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->seq));
18320f74e101Schristos 		break;
18330f74e101Schristos 	case CTRL_BA:
1834c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_BA_HDRLEN);
1835b3a00663Schristos 		if (!ndo->ndo_eflag)
1836c74ad251Schristos 			ND_PRINT(" RA:%s ",
1837c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ra));
18380f74e101Schristos 		break;
18390f74e101Schristos 	case CTRL_PS_POLL:
1840c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_PS_POLL_HDRLEN);
1841c74ad251Schristos 		ND_PRINT(" AID(%x)",
1842c74ad251Schristos 		    GET_LE_U_2(((const struct ctrl_ps_poll_hdr_t *)p)->aid));
18430f74e101Schristos 		break;
18440f74e101Schristos 	case CTRL_RTS:
1845c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_RTS_HDRLEN);
1846b3a00663Schristos 		if (!ndo->ndo_eflag)
1847c74ad251Schristos 			ND_PRINT(" TA:%s ",
1848c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ta));
18490f74e101Schristos 		break;
18500f74e101Schristos 	case CTRL_CTS:
1851c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_CTS_HDRLEN);
1852b3a00663Schristos 		if (!ndo->ndo_eflag)
1853c74ad251Schristos 			ND_PRINT(" RA:%s ",
1854c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_cts_hdr_t *)p)->ra));
18550f74e101Schristos 		break;
18560f74e101Schristos 	case CTRL_ACK:
1857c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_ACK_HDRLEN);
1858b3a00663Schristos 		if (!ndo->ndo_eflag)
1859c74ad251Schristos 			ND_PRINT(" RA:%s ",
1860c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_ack_hdr_t *)p)->ra));
18610f74e101Schristos 		break;
18620f74e101Schristos 	case CTRL_CF_END:
1863c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_END_HDRLEN);
1864b3a00663Schristos 		if (!ndo->ndo_eflag)
1865c74ad251Schristos 			ND_PRINT(" RA:%s ",
1866c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->ra));
18670f74e101Schristos 		break;
18680f74e101Schristos 	case CTRL_END_ACK:
1869c74ad251Schristos 		ND_TCHECK_LEN(p, CTRL_END_ACK_HDRLEN);
1870b3a00663Schristos 		if (!ndo->ndo_eflag)
1871c74ad251Schristos 			ND_PRINT(" RA:%s ",
1872c74ad251Schristos 			    GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->ra));
18730f74e101Schristos 		break;
18740f74e101Schristos 	}
18750f74e101Schristos 	return 1;
1876c74ad251Schristos trunc:
1877c74ad251Schristos 	return 0;
18780f74e101Schristos }
18790f74e101Schristos 
18800f74e101Schristos /*
18810f74e101Schristos  *  Data Frame - Address field contents
18820f74e101Schristos  *
18830f74e101Schristos  *  To Ds  | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
18840f74e101Schristos  *    0    |  0      |  DA    | SA     | BSSID  | n/a
18850f74e101Schristos  *    0    |  1      |  DA    | BSSID  | SA     | n/a
18860f74e101Schristos  *    1    |  0      |  BSSID | SA     | DA     | n/a
18870f74e101Schristos  *    1    |  1      |  RA    | TA     | DA     | SA
18880f74e101Schristos  */
18890f74e101Schristos 
1890fdccd7e4Schristos /*
1891fdccd7e4Schristos  * Function to get source and destination MAC addresses for a data frame.
1892fdccd7e4Schristos  */
18930f74e101Schristos static void
1894fdccd7e4Schristos get_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp,
1895b3a00663Schristos 		     const uint8_t **dstp)
18960f74e101Schristos {
1897fdccd7e4Schristos #define ADDR1  (p + 4)
1898fdccd7e4Schristos #define ADDR2  (p + 10)
1899fdccd7e4Schristos #define ADDR3  (p + 16)
1900fdccd7e4Schristos #define ADDR4  (p + 24)
1901fdccd7e4Schristos 
1902fdccd7e4Schristos 	if (!FC_TO_DS(fc)) {
1903fdccd7e4Schristos 		if (!FC_FROM_DS(fc)) {
1904fdccd7e4Schristos 			/* not To DS and not From DS */
1905fdccd7e4Schristos 			*srcp = ADDR2;
1906fdccd7e4Schristos 			*dstp = ADDR1;
1907fdccd7e4Schristos 		} else {
1908fdccd7e4Schristos 			/* not To DS and From DS */
1909fdccd7e4Schristos 			*srcp = ADDR3;
1910fdccd7e4Schristos 			*dstp = ADDR1;
1911fdccd7e4Schristos 		}
1912fdccd7e4Schristos 	} else {
1913fdccd7e4Schristos 		if (!FC_FROM_DS(fc)) {
1914c74ad251Schristos 			/* To DS and not From DS */
1915fdccd7e4Schristos 			*srcp = ADDR2;
1916fdccd7e4Schristos 			*dstp = ADDR3;
1917fdccd7e4Schristos 		} else {
1918fdccd7e4Schristos 			/* To DS and From DS */
1919fdccd7e4Schristos 			*srcp = ADDR4;
1920fdccd7e4Schristos 			*dstp = ADDR3;
1921fdccd7e4Schristos 		}
1922fdccd7e4Schristos 	}
1923fdccd7e4Schristos 
1924fdccd7e4Schristos #undef ADDR1
1925fdccd7e4Schristos #undef ADDR2
1926fdccd7e4Schristos #undef ADDR3
1927fdccd7e4Schristos #undef ADDR4
1928fdccd7e4Schristos }
1929fdccd7e4Schristos 
1930fdccd7e4Schristos static void
1931fdccd7e4Schristos get_mgmt_src_dst_mac(const u_char *p, const uint8_t **srcp, const uint8_t **dstp)
1932fdccd7e4Schristos {
1933fdccd7e4Schristos 	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
1934fdccd7e4Schristos 
1935fdccd7e4Schristos 	if (srcp != NULL)
1936fdccd7e4Schristos 		*srcp = hp->sa;
1937fdccd7e4Schristos 	if (dstp != NULL)
1938fdccd7e4Schristos 		*dstp = hp->da;
1939fdccd7e4Schristos }
1940fdccd7e4Schristos 
1941fdccd7e4Schristos /*
1942fdccd7e4Schristos  * Print Header funcs
1943fdccd7e4Schristos  */
1944fdccd7e4Schristos 
1945fdccd7e4Schristos static void
1946fdccd7e4Schristos data_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
1947fdccd7e4Schristos {
19480f74e101Schristos 	u_int subtype = FC_SUBTYPE(fc);
19490f74e101Schristos 
19500f74e101Schristos 	if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) ||
19510f74e101Schristos 	    DATA_FRAME_IS_QOS(subtype)) {
1952c74ad251Schristos 		ND_PRINT("CF ");
19530f74e101Schristos 		if (DATA_FRAME_IS_CF_ACK(subtype)) {
19540f74e101Schristos 			if (DATA_FRAME_IS_CF_POLL(subtype))
1955c74ad251Schristos 				ND_PRINT("Ack/Poll");
19560f74e101Schristos 			else
1957c74ad251Schristos 				ND_PRINT("Ack");
19580f74e101Schristos 		} else {
19590f74e101Schristos 			if (DATA_FRAME_IS_CF_POLL(subtype))
1960c74ad251Schristos 				ND_PRINT("Poll");
19610f74e101Schristos 		}
19620f74e101Schristos 		if (DATA_FRAME_IS_QOS(subtype))
1963c74ad251Schristos 			ND_PRINT("+QoS");
1964c74ad251Schristos 		ND_PRINT(" ");
19650f74e101Schristos 	}
19660f74e101Schristos 
19670f74e101Schristos #define ADDR1  (p + 4)
19680f74e101Schristos #define ADDR2  (p + 10)
19690f74e101Schristos #define ADDR3  (p + 16)
19700f74e101Schristos #define ADDR4  (p + 24)
19710f74e101Schristos 
19720f74e101Schristos 	if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1973c74ad251Schristos 		ND_PRINT("DA:%s SA:%s BSSID:%s ",
1974c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1975c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR3));
19760f74e101Schristos 	} else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1977c74ad251Schristos 		ND_PRINT("DA:%s BSSID:%s SA:%s ",
1978c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1979c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR3));
19800f74e101Schristos 	} else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1981c74ad251Schristos 		ND_PRINT("BSSID:%s SA:%s DA:%s ",
1982c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1983c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR3));
19840f74e101Schristos 	} else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1985c74ad251Schristos 		ND_PRINT("RA:%s TA:%s DA:%s SA:%s ",
1986c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR1), GET_ETHERADDR_STRING(ADDR2),
1987c74ad251Schristos 		    GET_ETHERADDR_STRING(ADDR3), GET_ETHERADDR_STRING(ADDR4));
19880f74e101Schristos 	}
19890f74e101Schristos 
19900f74e101Schristos #undef ADDR1
19910f74e101Schristos #undef ADDR2
19920f74e101Schristos #undef ADDR3
19930f74e101Schristos #undef ADDR4
19940f74e101Schristos }
19950f74e101Schristos 
19960f74e101Schristos static void
1997fdccd7e4Schristos mgmt_header_print(netdissect_options *ndo, const u_char *p)
19980f74e101Schristos {
19990f74e101Schristos 	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
20000f74e101Schristos 
2001c74ad251Schristos 	ND_PRINT("BSSID:%s DA:%s SA:%s ",
2002c74ad251Schristos 	    GET_ETHERADDR_STRING((hp)->bssid), GET_ETHERADDR_STRING((hp)->da),
2003c74ad251Schristos 	    GET_ETHERADDR_STRING((hp)->sa));
20040f74e101Schristos }
20050f74e101Schristos 
20060f74e101Schristos static void
2007fdccd7e4Schristos ctrl_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
20080f74e101Schristos {
20090f74e101Schristos 	switch (FC_SUBTYPE(fc)) {
20100f74e101Schristos 	case CTRL_BAR:
2011c74ad251Schristos 		ND_PRINT(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
2012c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ra),
2013c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_bar_hdr_t *)p)->ta),
2014c74ad251Schristos 		    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->ctl),
2015c74ad251Schristos 		    GET_LE_U_2(((const struct ctrl_bar_hdr_t *)p)->seq));
20160f74e101Schristos 		break;
20170f74e101Schristos 	case CTRL_BA:
2018*26ba0b50Schristos 		ND_PRINT("RA:%s TA:%s ",
2019*26ba0b50Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ra),
2020*26ba0b50Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_ba_hdr_t *)p)->ta));
20210f74e101Schristos 		break;
20220f74e101Schristos 	case CTRL_PS_POLL:
2023c74ad251Schristos 		ND_PRINT("BSSID:%s TA:%s ",
2024c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_ps_poll_hdr_t *)p)->bssid),
2025c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_ps_poll_hdr_t *)p)->ta));
20260f74e101Schristos 		break;
20270f74e101Schristos 	case CTRL_RTS:
2028c74ad251Schristos 		ND_PRINT("RA:%s TA:%s ",
2029c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ra),
2030c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_rts_hdr_t *)p)->ta));
20310f74e101Schristos 		break;
20320f74e101Schristos 	case CTRL_CTS:
2033c74ad251Schristos 		ND_PRINT("RA:%s ",
2034c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_cts_hdr_t *)p)->ra));
20350f74e101Schristos 		break;
20360f74e101Schristos 	case CTRL_ACK:
2037c74ad251Schristos 		ND_PRINT("RA:%s ",
2038c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_ack_hdr_t *)p)->ra));
20390f74e101Schristos 		break;
20400f74e101Schristos 	case CTRL_CF_END:
2041c74ad251Schristos 		ND_PRINT("RA:%s BSSID:%s ",
2042c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->ra),
2043c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_end_hdr_t *)p)->bssid));
20440f74e101Schristos 		break;
20450f74e101Schristos 	case CTRL_END_ACK:
2046c74ad251Schristos 		ND_PRINT("RA:%s BSSID:%s ",
2047c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->ra),
2048c74ad251Schristos 		    GET_ETHERADDR_STRING(((const struct ctrl_end_ack_hdr_t *)p)->bssid));
20490f74e101Schristos 		break;
20500f74e101Schristos 	default:
2051fdccd7e4Schristos 		/* We shouldn't get here - we should already have quit */
20520f74e101Schristos 		break;
20530f74e101Schristos 	}
20540f74e101Schristos }
20550f74e101Schristos 
20560f74e101Schristos static int
2057b3a00663Schristos extract_header_length(netdissect_options *ndo,
2058b3a00663Schristos 		      uint16_t fc)
20590f74e101Schristos {
20600f74e101Schristos 	int len;
20610f74e101Schristos 
20620f74e101Schristos 	switch (FC_TYPE(fc)) {
20630f74e101Schristos 	case T_MGMT:
20640f74e101Schristos 		return MGMT_HDRLEN;
20650f74e101Schristos 	case T_CTRL:
20660f74e101Schristos 		switch (FC_SUBTYPE(fc)) {
2067fdccd7e4Schristos 		case CTRL_CONTROL_WRAPPER:
2068fdccd7e4Schristos 			return CTRL_CONTROL_WRAPPER_HDRLEN;
20690f74e101Schristos 		case CTRL_BAR:
20700f74e101Schristos 			return CTRL_BAR_HDRLEN;
2071fdccd7e4Schristos 		case CTRL_BA:
2072fdccd7e4Schristos 			return CTRL_BA_HDRLEN;
20730f74e101Schristos 		case CTRL_PS_POLL:
20740f74e101Schristos 			return CTRL_PS_POLL_HDRLEN;
20750f74e101Schristos 		case CTRL_RTS:
20760f74e101Schristos 			return CTRL_RTS_HDRLEN;
20770f74e101Schristos 		case CTRL_CTS:
20780f74e101Schristos 			return CTRL_CTS_HDRLEN;
20790f74e101Schristos 		case CTRL_ACK:
20800f74e101Schristos 			return CTRL_ACK_HDRLEN;
20810f74e101Schristos 		case CTRL_CF_END:
20820f74e101Schristos 			return CTRL_END_HDRLEN;
20830f74e101Schristos 		case CTRL_END_ACK:
20840f74e101Schristos 			return CTRL_END_ACK_HDRLEN;
20850f74e101Schristos 		default:
2086c74ad251Schristos 			ND_PRINT("unknown 802.11 ctrl frame subtype (%u)", FC_SUBTYPE(fc));
20870f74e101Schristos 			return 0;
20880f74e101Schristos 		}
20890f74e101Schristos 	case T_DATA:
20900f74e101Schristos 		len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
20910f74e101Schristos 		if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
20920f74e101Schristos 			len += 2;
20930f74e101Schristos 		return len;
20940f74e101Schristos 	default:
2095c74ad251Schristos 		ND_PRINT("unknown 802.11 frame type (%u)", FC_TYPE(fc));
20960f74e101Schristos 		return 0;
20970f74e101Schristos 	}
20980f74e101Schristos }
20990f74e101Schristos 
21000f74e101Schristos static int
2101c74ad251Schristos extract_mesh_header_length(netdissect_options *ndo, const u_char *p)
21020f74e101Schristos {
2103c74ad251Schristos 	return (GET_U_1(p) &~ 3) ? 0 : 6*(1 + (GET_U_1(p) & 3));
21040f74e101Schristos }
21050f74e101Schristos 
21060f74e101Schristos /*
2107fdccd7e4Schristos  * Print the 802.11 MAC header.
21080f74e101Schristos  */
21090f74e101Schristos static void
2110b3a00663Schristos ieee_802_11_hdr_print(netdissect_options *ndo,
2111b3a00663Schristos 		      uint16_t fc, const u_char *p, u_int hdrlen,
2112fdccd7e4Schristos 		      u_int meshdrlen)
21130f74e101Schristos {
2114b3a00663Schristos 	if (ndo->ndo_vflag) {
21150f74e101Schristos 		if (FC_MORE_DATA(fc))
2116c74ad251Schristos 			ND_PRINT("More Data ");
21170f74e101Schristos 		if (FC_MORE_FLAG(fc))
2118c74ad251Schristos 			ND_PRINT("More Fragments ");
21190f74e101Schristos 		if (FC_POWER_MGMT(fc))
2120c74ad251Schristos 			ND_PRINT("Pwr Mgmt ");
21210f74e101Schristos 		if (FC_RETRY(fc))
2122c74ad251Schristos 			ND_PRINT("Retry ");
21230f74e101Schristos 		if (FC_ORDER(fc))
2124c74ad251Schristos 			ND_PRINT("Strictly Ordered ");
2125fdccd7e4Schristos 		if (FC_PROTECTED(fc))
2126c74ad251Schristos 			ND_PRINT("Protected ");
21270f74e101Schristos 		if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL)
2128c74ad251Schristos 			ND_PRINT("%uus ",
2129c74ad251Schristos 			    GET_LE_U_2(((const struct mgmt_header_t *)p)->duration));
21300f74e101Schristos 	}
21310f74e101Schristos 	if (meshdrlen != 0) {
21320f74e101Schristos 		const struct meshcntl_t *mc =
2133c74ad251Schristos 		    (const struct meshcntl_t *)(p + hdrlen - meshdrlen);
2134c74ad251Schristos 		u_int ae = GET_U_1(mc->flags) & 3;
21350f74e101Schristos 
2136c74ad251Schristos 		ND_PRINT("MeshData (AE %u TTL %u seq %u", ae,
2137c74ad251Schristos 		    GET_U_1(mc->ttl), GET_LE_U_4(mc->seq));
21380f74e101Schristos 		if (ae > 0)
2139c74ad251Schristos 			ND_PRINT(" A4:%s", GET_ETHERADDR_STRING(mc->addr4));
21400f74e101Schristos 		if (ae > 1)
2141c74ad251Schristos 			ND_PRINT(" A5:%s", GET_ETHERADDR_STRING(mc->addr5));
21420f74e101Schristos 		if (ae > 2)
2143c74ad251Schristos 			ND_PRINT(" A6:%s", GET_ETHERADDR_STRING(mc->addr6));
2144c74ad251Schristos 		ND_PRINT(") ");
21450f74e101Schristos 	}
21460f74e101Schristos 
21470f74e101Schristos 	switch (FC_TYPE(fc)) {
21480f74e101Schristos 	case T_MGMT:
2149fdccd7e4Schristos 		mgmt_header_print(ndo, p);
21500f74e101Schristos 		break;
21510f74e101Schristos 	case T_CTRL:
2152fdccd7e4Schristos 		ctrl_header_print(ndo, fc, p);
21530f74e101Schristos 		break;
21540f74e101Schristos 	case T_DATA:
2155fdccd7e4Schristos 		data_header_print(ndo, fc, p);
21560f74e101Schristos 		break;
21570f74e101Schristos 	default:
21580f74e101Schristos 		break;
21590f74e101Schristos 	}
21600f74e101Schristos }
21610f74e101Schristos 
21620f74e101Schristos static u_int
2163b3a00663Schristos ieee802_11_print(netdissect_options *ndo,
2164b3a00663Schristos 		 const u_char *p, u_int length, u_int orig_caplen, int pad,
21650f74e101Schristos 		 u_int fcslen)
21660f74e101Schristos {
2167b3a00663Schristos 	uint16_t fc;
21680f74e101Schristos 	u_int caplen, hdrlen, meshdrlen;
2169dc860a36Sspz 	struct lladdr_info src, dst;
2170fdccd7e4Schristos 	int llc_hdrlen;
21710f74e101Schristos 
2172c74ad251Schristos 	ndo->ndo_protocol = "802.11";
21730f74e101Schristos 	caplen = orig_caplen;
21740f74e101Schristos 	/* Remove FCS, if present */
21750f74e101Schristos 	if (length < fcslen) {
2176c74ad251Schristos 		nd_print_trunc(ndo);
21770f74e101Schristos 		return caplen;
21780f74e101Schristos 	}
21790f74e101Schristos 	length -= fcslen;
21800f74e101Schristos 	if (caplen > length) {
21810f74e101Schristos 		/* Amount of FCS in actual packet data, if any */
21820f74e101Schristos 		fcslen = caplen - length;
21830f74e101Schristos 		caplen -= fcslen;
2184b3a00663Schristos 		ndo->ndo_snapend -= fcslen;
21850f74e101Schristos 	}
21860f74e101Schristos 
21870f74e101Schristos 	if (caplen < IEEE802_11_FC_LEN) {
2188c74ad251Schristos 		nd_print_trunc(ndo);
21890f74e101Schristos 		return orig_caplen;
21900f74e101Schristos 	}
21910f74e101Schristos 
2192c74ad251Schristos 	fc = GET_LE_U_2(p);
2193b3a00663Schristos 	hdrlen = extract_header_length(ndo, fc);
2194fdccd7e4Schristos 	if (hdrlen == 0) {
2195fdccd7e4Schristos 		/* Unknown frame type or control frame subtype; quit. */
2196fdccd7e4Schristos 		return (0);
2197fdccd7e4Schristos 	}
21980f74e101Schristos 	if (pad)
21990f74e101Schristos 		hdrlen = roundup2(hdrlen, 4);
2200b3a00663Schristos 	if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA &&
22010e9868baSchristos 	    DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
2202c74ad251Schristos 		if(!ND_TTEST_1(p + hdrlen)) {
2203c74ad251Schristos 			nd_print_trunc(ndo);
2204817e9a7eSchristos 			return hdrlen;
2205817e9a7eSchristos 		}
2206c74ad251Schristos 		meshdrlen = extract_mesh_header_length(ndo, p + hdrlen);
22070f74e101Schristos 		hdrlen += meshdrlen;
22080f74e101Schristos 	} else
22090f74e101Schristos 		meshdrlen = 0;
22100f74e101Schristos 
22110f74e101Schristos 	if (caplen < hdrlen) {
2212c74ad251Schristos 		nd_print_trunc(ndo);
22130f74e101Schristos 		return hdrlen;
22140f74e101Schristos 	}
22150f74e101Schristos 
2216fdccd7e4Schristos 	if (ndo->ndo_eflag)
2217fdccd7e4Schristos 		ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen);
22180f74e101Schristos 
22190f74e101Schristos 	/*
22200f74e101Schristos 	 * Go past the 802.11 header.
22210f74e101Schristos 	 */
22220f74e101Schristos 	length -= hdrlen;
22230f74e101Schristos 	caplen -= hdrlen;
22240f74e101Schristos 	p += hdrlen;
22250f74e101Schristos 
2226dc860a36Sspz 	src.addr_string = etheraddr_string;
2227dc860a36Sspz 	dst.addr_string = etheraddr_string;
22280f74e101Schristos 	switch (FC_TYPE(fc)) {
22290f74e101Schristos 	case T_MGMT:
2230dc860a36Sspz 		get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr);
2231dc860a36Sspz 		if (!mgmt_body_print(ndo, fc, src.addr, p, length)) {
2232c74ad251Schristos 			nd_print_trunc(ndo);
22330f74e101Schristos 			return hdrlen;
22340f74e101Schristos 		}
22350f74e101Schristos 		break;
22360f74e101Schristos 	case T_CTRL:
2237b3a00663Schristos 		if (!ctrl_body_print(ndo, fc, p - hdrlen)) {
2238c74ad251Schristos 			nd_print_trunc(ndo);
22390f74e101Schristos 			return hdrlen;
22400f74e101Schristos 		}
22410f74e101Schristos 		break;
22420f74e101Schristos 	case T_DATA:
22430f74e101Schristos 		if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
22440f74e101Schristos 			return hdrlen;	/* no-data frame */
22450f74e101Schristos 		/* There may be a problem w/ AP not having this bit set */
2246fdccd7e4Schristos 		if (FC_PROTECTED(fc)) {
2247c74ad251Schristos 			ND_PRINT("Data");
2248b3a00663Schristos 			if (!wep_print(ndo, p)) {
2249c74ad251Schristos 				nd_print_trunc(ndo);
22500f74e101Schristos 				return hdrlen;
22510f74e101Schristos 			}
2252fdccd7e4Schristos 		} else {
2253dc860a36Sspz 			get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr);
2254dc860a36Sspz 			llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
2255fdccd7e4Schristos 			if (llc_hdrlen < 0) {
22560f74e101Schristos 				/*
22570f74e101Schristos 				 * Some kinds of LLC packet we cannot
22580f74e101Schristos 				 * handle intelligently
22590f74e101Schristos 				 */
2260b3a00663Schristos 				if (!ndo->ndo_suppress_default_print)
2261b3a00663Schristos 					ND_DEFAULTPRINT(p, caplen);
2262fdccd7e4Schristos 				llc_hdrlen = -llc_hdrlen;
2263fdccd7e4Schristos 			}
2264fdccd7e4Schristos 			hdrlen += llc_hdrlen;
22650f74e101Schristos 		}
22660f74e101Schristos 		break;
22670f74e101Schristos 	default:
2268fdccd7e4Schristos 		/* We shouldn't get here - we should already have quit */
22690f74e101Schristos 		break;
22700f74e101Schristos 	}
22710f74e101Schristos 
22720f74e101Schristos 	return hdrlen;
22730f74e101Schristos }
22740f74e101Schristos 
22750f74e101Schristos /*
22760f74e101Schristos  * This is the top level routine of the printer.  'p' points
22770f74e101Schristos  * to the 802.11 header of the packet, 'h->ts' is the timestamp,
22780f74e101Schristos  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
22790f74e101Schristos  * is the number of bytes actually captured.
22800f74e101Schristos  */
2281c74ad251Schristos void
2282b3a00663Schristos ieee802_11_if_print(netdissect_options *ndo,
2283b3a00663Schristos 		    const struct pcap_pkthdr *h, const u_char *p)
22840f74e101Schristos {
2285c74ad251Schristos 	ndo->ndo_protocol = "802.11";
2286c74ad251Schristos 	ndo->ndo_ll_hdr_len += ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0);
22870f74e101Schristos }
22880f74e101Schristos 
2289fdccd7e4Schristos 
2290fdccd7e4Schristos /* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
2291fdccd7e4Schristos /* NetBSD: ieee802_11_radio.h,v 1.2 2006/02/26 03:04:03 dyoung Exp  */
2292fdccd7e4Schristos 
2293fdccd7e4Schristos /*-
2294fdccd7e4Schristos  * Copyright (c) 2003, 2004 David Young.  All rights reserved.
2295fdccd7e4Schristos  *
2296fdccd7e4Schristos  * Redistribution and use in source and binary forms, with or without
2297fdccd7e4Schristos  * modification, are permitted provided that the following conditions
2298fdccd7e4Schristos  * are met:
2299fdccd7e4Schristos  * 1. Redistributions of source code must retain the above copyright
2300fdccd7e4Schristos  *    notice, this list of conditions and the following disclaimer.
2301fdccd7e4Schristos  * 2. Redistributions in binary form must reproduce the above copyright
2302fdccd7e4Schristos  *    notice, this list of conditions and the following disclaimer in the
2303fdccd7e4Schristos  *    documentation and/or other materials provided with the distribution.
2304fdccd7e4Schristos  * 3. The name of David Young may not be used to endorse or promote
2305fdccd7e4Schristos  *    products derived from this software without specific prior
2306fdccd7e4Schristos  *    written permission.
2307fdccd7e4Schristos  *
2308fdccd7e4Schristos  * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
2309fdccd7e4Schristos  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2310fdccd7e4Schristos  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2311fdccd7e4Schristos  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
2312fdccd7e4Schristos  * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2313fdccd7e4Schristos  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2314fdccd7e4Schristos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315fdccd7e4Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2316fdccd7e4Schristos  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2317fdccd7e4Schristos  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2318fdccd7e4Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
2319fdccd7e4Schristos  * OF SUCH DAMAGE.
2320fdccd7e4Schristos  */
2321fdccd7e4Schristos 
2322fdccd7e4Schristos /* A generic radio capture format is desirable. It must be
2323fdccd7e4Schristos  * rigidly defined (e.g., units for fields should be given),
2324fdccd7e4Schristos  * and easily extensible.
2325fdccd7e4Schristos  *
2326fdccd7e4Schristos  * The following is an extensible radio capture format. It is
2327fdccd7e4Schristos  * based on a bitmap indicating which fields are present.
2328fdccd7e4Schristos  *
2329fdccd7e4Schristos  * I am trying to describe precisely what the application programmer
2330fdccd7e4Schristos  * should expect in the following, and for that reason I tell the
2331fdccd7e4Schristos  * units and origin of each measurement (where it applies), or else I
2332fdccd7e4Schristos  * use sufficiently weaselly language ("is a monotonically nondecreasing
2333fdccd7e4Schristos  * function of...") that I cannot set false expectations for lawyerly
2334fdccd7e4Schristos  * readers.
2335fdccd7e4Schristos  */
2336fdccd7e4Schristos 
2337fdccd7e4Schristos /*
2338fdccd7e4Schristos  * The radio capture header precedes the 802.11 header.
2339fdccd7e4Schristos  *
2340fdccd7e4Schristos  * Note well: all radiotap fields are little-endian.
2341fdccd7e4Schristos  */
2342fdccd7e4Schristos struct ieee80211_radiotap_header {
2343c74ad251Schristos 	nd_uint8_t	it_version;	/* Version 0. Only increases
2344fdccd7e4Schristos 					 * for drastic changes,
2345fdccd7e4Schristos 					 * introduction of compatible
2346fdccd7e4Schristos 					 * new fields does not count.
2347fdccd7e4Schristos 					 */
2348c74ad251Schristos 	nd_uint8_t	it_pad;
2349c74ad251Schristos 	nd_uint16_t	it_len;		/* length of the whole
2350fdccd7e4Schristos 					 * header in bytes, including
2351fdccd7e4Schristos 					 * it_version, it_pad,
2352fdccd7e4Schristos 					 * it_len, and data fields.
2353fdccd7e4Schristos 					 */
2354c74ad251Schristos 	nd_uint32_t	it_present;	/* A bitmap telling which
2355fdccd7e4Schristos 					 * fields are present. Set bit 31
2356fdccd7e4Schristos 					 * (0x80000000) to extend the
2357fdccd7e4Schristos 					 * bitmap by another 32 bits.
2358fdccd7e4Schristos 					 * Additional extensions are made
2359fdccd7e4Schristos 					 * by setting bit 31.
2360fdccd7e4Schristos 					 */
2361fdccd7e4Schristos };
2362fdccd7e4Schristos 
2363fdccd7e4Schristos /* Name                                 Data type       Units
2364fdccd7e4Schristos  * ----                                 ---------       -----
2365fdccd7e4Schristos  *
2366fdccd7e4Schristos  * IEEE80211_RADIOTAP_TSFT              uint64_t       microseconds
2367fdccd7e4Schristos  *
2368fdccd7e4Schristos  *      Value in microseconds of the MAC's 64-bit 802.11 Time
2369fdccd7e4Schristos  *      Synchronization Function timer when the first bit of the
2370fdccd7e4Schristos  *      MPDU arrived at the MAC. For received frames, only.
2371fdccd7e4Schristos  *
2372fdccd7e4Schristos  * IEEE80211_RADIOTAP_CHANNEL           2 x uint16_t   MHz, bitmap
2373fdccd7e4Schristos  *
2374fdccd7e4Schristos  *      Tx/Rx frequency in MHz, followed by flags (see below).
2375fdccd7e4Schristos  *	Note that IEEE80211_RADIOTAP_XCHANNEL must be used to
2376fdccd7e4Schristos  *	represent an HT channel as there is not enough room in
2377fdccd7e4Schristos  *	the flags word.
2378fdccd7e4Schristos  *
2379fdccd7e4Schristos  * IEEE80211_RADIOTAP_FHSS              uint16_t       see below
2380fdccd7e4Schristos  *
2381fdccd7e4Schristos  *      For frequency-hopping radios, the hop set (first byte)
2382fdccd7e4Schristos  *      and pattern (second byte).
2383fdccd7e4Schristos  *
2384fdccd7e4Schristos  * IEEE80211_RADIOTAP_RATE              uint8_t        500kb/s or index
2385fdccd7e4Schristos  *
2386fdccd7e4Schristos  *      Tx/Rx data rate.  If bit 0x80 is set then it represents an
2387fdccd7e4Schristos  *	an MCS index and not an IEEE rate.
2388fdccd7e4Schristos  *
2389fdccd7e4Schristos  * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     int8_t         decibels from
2390fdccd7e4Schristos  *                                                     one milliwatt (dBm)
2391fdccd7e4Schristos  *
2392fdccd7e4Schristos  *      RF signal power at the antenna, decibel difference from
2393fdccd7e4Schristos  *      one milliwatt.
2394fdccd7e4Schristos  *
2395fdccd7e4Schristos  * IEEE80211_RADIOTAP_DBM_ANTNOISE      int8_t         decibels from
2396fdccd7e4Schristos  *                                                     one milliwatt (dBm)
2397fdccd7e4Schristos  *
2398fdccd7e4Schristos  *      RF noise power at the antenna, decibel difference from one
2399fdccd7e4Schristos  *      milliwatt.
2400fdccd7e4Schristos  *
2401fdccd7e4Schristos  * IEEE80211_RADIOTAP_DB_ANTSIGNAL      uint8_t        decibel (dB)
2402fdccd7e4Schristos  *
2403fdccd7e4Schristos  *      RF signal power at the antenna, decibel difference from an
2404fdccd7e4Schristos  *      arbitrary, fixed reference.
2405fdccd7e4Schristos  *
2406fdccd7e4Schristos  * IEEE80211_RADIOTAP_DB_ANTNOISE       uint8_t        decibel (dB)
2407fdccd7e4Schristos  *
2408fdccd7e4Schristos  *      RF noise power at the antenna, decibel difference from an
2409fdccd7e4Schristos  *      arbitrary, fixed reference point.
2410fdccd7e4Schristos  *
2411fdccd7e4Schristos  * IEEE80211_RADIOTAP_LOCK_QUALITY      uint16_t       unitless
2412fdccd7e4Schristos  *
2413fdccd7e4Schristos  *      Quality of Barker code lock. Unitless. Monotonically
2414fdccd7e4Schristos  *      nondecreasing with "better" lock strength. Called "Signal
2415fdccd7e4Schristos  *      Quality" in datasheets.  (Is there a standard way to measure
2416fdccd7e4Schristos  *      this?)
2417fdccd7e4Schristos  *
2418fdccd7e4Schristos  * IEEE80211_RADIOTAP_TX_ATTENUATION    uint16_t       unitless
2419fdccd7e4Schristos  *
2420fdccd7e4Schristos  *      Transmit power expressed as unitless distance from max
2421fdccd7e4Schristos  *      power set at factory calibration.  0 is max power.
2422fdccd7e4Schristos  *      Monotonically nondecreasing with lower power levels.
2423fdccd7e4Schristos  *
2424fdccd7e4Schristos  * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t       decibels (dB)
2425fdccd7e4Schristos  *
2426fdccd7e4Schristos  *      Transmit power expressed as decibel distance from max power
2427fdccd7e4Schristos  *      set at factory calibration.  0 is max power.  Monotonically
2428fdccd7e4Schristos  *      nondecreasing with lower power levels.
2429fdccd7e4Schristos  *
2430fdccd7e4Schristos  * IEEE80211_RADIOTAP_DBM_TX_POWER      int8_t         decibels from
2431fdccd7e4Schristos  *                                                     one milliwatt (dBm)
2432fdccd7e4Schristos  *
2433fdccd7e4Schristos  *      Transmit power expressed as dBm (decibels from a 1 milliwatt
2434fdccd7e4Schristos  *      reference). This is the absolute power level measured at
2435fdccd7e4Schristos  *      the antenna port.
2436fdccd7e4Schristos  *
2437fdccd7e4Schristos  * IEEE80211_RADIOTAP_FLAGS             uint8_t        bitmap
2438fdccd7e4Schristos  *
2439fdccd7e4Schristos  *      Properties of transmitted and received frames. See flags
2440fdccd7e4Schristos  *      defined below.
2441fdccd7e4Schristos  *
2442fdccd7e4Schristos  * IEEE80211_RADIOTAP_ANTENNA           uint8_t        antenna index
2443fdccd7e4Schristos  *
2444fdccd7e4Schristos  *      Unitless indication of the Rx/Tx antenna for this packet.
2445fdccd7e4Schristos  *      The first antenna is antenna 0.
2446fdccd7e4Schristos  *
2447fdccd7e4Schristos  * IEEE80211_RADIOTAP_RX_FLAGS          uint16_t       bitmap
2448fdccd7e4Schristos  *
2449fdccd7e4Schristos  *     Properties of received frames. See flags defined below.
2450fdccd7e4Schristos  *
2451fdccd7e4Schristos  * IEEE80211_RADIOTAP_XCHANNEL          uint32_t       bitmap
2452fdccd7e4Schristos  *					uint16_t       MHz
2453fdccd7e4Schristos  *					uint8_t        channel number
2454fdccd7e4Schristos  *					uint8_t        .5 dBm
2455fdccd7e4Schristos  *
2456fdccd7e4Schristos  *	Extended channel specification: flags (see below) followed by
2457fdccd7e4Schristos  *	frequency in MHz, the corresponding IEEE channel number, and
2458fdccd7e4Schristos  *	finally the maximum regulatory transmit power cap in .5 dBm
2459fdccd7e4Schristos  *	units.  This property supersedes IEEE80211_RADIOTAP_CHANNEL
2460fdccd7e4Schristos  *	and only one of the two should be present.
2461fdccd7e4Schristos  *
2462fdccd7e4Schristos  * IEEE80211_RADIOTAP_MCS		uint8_t        known
2463fdccd7e4Schristos  *					uint8_t        flags
2464fdccd7e4Schristos  *					uint8_t        mcs
2465fdccd7e4Schristos  *
2466fdccd7e4Schristos  *	Bitset indicating which fields have known values, followed
2467fdccd7e4Schristos  *	by bitset of flag values, followed by the MCS rate index as
2468fdccd7e4Schristos  *	in IEEE 802.11n.
2469fdccd7e4Schristos  *
2470fdccd7e4Schristos  *
2471fdccd7e4Schristos  * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless
2472fdccd7e4Schristos  *
2473fdccd7e4Schristos  *	Contains the AMPDU information for the subframe.
2474fdccd7e4Schristos  *
2475fdccd7e4Schristos  * IEEE80211_RADIOTAP_VHT	u16, u8, u8, u8[4], u8, u8, u16
2476fdccd7e4Schristos  *
2477fdccd7e4Schristos  *	Contains VHT information about this frame.
2478fdccd7e4Schristos  *
2479fdccd7e4Schristos  * IEEE80211_RADIOTAP_VENDOR_NAMESPACE
2480fdccd7e4Schristos  *					uint8_t  OUI[3]
2481fdccd7e4Schristos  *                                      uint8_t        subspace
2482fdccd7e4Schristos  *                                      uint16_t       length
2483fdccd7e4Schristos  *
2484fdccd7e4Schristos  *     The Vendor Namespace Field contains three sub-fields. The first
2485fdccd7e4Schristos  *     sub-field is 3 bytes long. It contains the vendor's IEEE 802
2486fdccd7e4Schristos  *     Organizationally Unique Identifier (OUI). The fourth byte is a
2487fdccd7e4Schristos  *     vendor-specific "namespace selector."
2488fdccd7e4Schristos  *
2489fdccd7e4Schristos  */
2490fdccd7e4Schristos enum ieee80211_radiotap_type {
2491fdccd7e4Schristos 	IEEE80211_RADIOTAP_TSFT = 0,
2492fdccd7e4Schristos 	IEEE80211_RADIOTAP_FLAGS = 1,
2493fdccd7e4Schristos 	IEEE80211_RADIOTAP_RATE = 2,
2494fdccd7e4Schristos 	IEEE80211_RADIOTAP_CHANNEL = 3,
2495fdccd7e4Schristos 	IEEE80211_RADIOTAP_FHSS = 4,
2496fdccd7e4Schristos 	IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
2497fdccd7e4Schristos 	IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
2498fdccd7e4Schristos 	IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
2499fdccd7e4Schristos 	IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
2500fdccd7e4Schristos 	IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
2501fdccd7e4Schristos 	IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
2502fdccd7e4Schristos 	IEEE80211_RADIOTAP_ANTENNA = 11,
2503fdccd7e4Schristos 	IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
2504fdccd7e4Schristos 	IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
2505fdccd7e4Schristos 	IEEE80211_RADIOTAP_RX_FLAGS = 14,
2506fdccd7e4Schristos 	/* NB: gap for netbsd definitions */
2507fdccd7e4Schristos 	IEEE80211_RADIOTAP_XCHANNEL = 18,
2508fdccd7e4Schristos 	IEEE80211_RADIOTAP_MCS = 19,
2509fdccd7e4Schristos 	IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
2510fdccd7e4Schristos 	IEEE80211_RADIOTAP_VHT = 21,
2511fdccd7e4Schristos 	IEEE80211_RADIOTAP_NAMESPACE = 29,
2512fdccd7e4Schristos 	IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
2513fdccd7e4Schristos 	IEEE80211_RADIOTAP_EXT = 31
2514fdccd7e4Schristos };
2515fdccd7e4Schristos 
2516fdccd7e4Schristos /* channel attributes */
2517fdccd7e4Schristos #define	IEEE80211_CHAN_TURBO	0x00010	/* Turbo channel */
2518fdccd7e4Schristos #define	IEEE80211_CHAN_CCK	0x00020	/* CCK channel */
2519fdccd7e4Schristos #define	IEEE80211_CHAN_OFDM	0x00040	/* OFDM channel */
2520fdccd7e4Schristos #define	IEEE80211_CHAN_2GHZ	0x00080	/* 2 GHz spectrum channel. */
2521fdccd7e4Schristos #define	IEEE80211_CHAN_5GHZ	0x00100	/* 5 GHz spectrum channel */
2522fdccd7e4Schristos #define	IEEE80211_CHAN_PASSIVE	0x00200	/* Only passive scan allowed */
2523fdccd7e4Schristos #define	IEEE80211_CHAN_DYN	0x00400	/* Dynamic CCK-OFDM channel */
2524fdccd7e4Schristos #define	IEEE80211_CHAN_GFSK	0x00800	/* GFSK channel (FHSS PHY) */
2525fdccd7e4Schristos #define	IEEE80211_CHAN_GSM	0x01000	/* 900 MHz spectrum channel */
2526fdccd7e4Schristos #define	IEEE80211_CHAN_STURBO	0x02000	/* 11a static turbo channel only */
2527fdccd7e4Schristos #define	IEEE80211_CHAN_HALF	0x04000	/* Half rate channel */
2528fdccd7e4Schristos #define	IEEE80211_CHAN_QUARTER	0x08000	/* Quarter rate channel */
2529fdccd7e4Schristos #define	IEEE80211_CHAN_HT20	0x10000	/* HT 20 channel */
2530fdccd7e4Schristos #define	IEEE80211_CHAN_HT40U	0x20000	/* HT 40 channel w/ ext above */
2531fdccd7e4Schristos #define	IEEE80211_CHAN_HT40D	0x40000	/* HT 40 channel w/ ext below */
2532fdccd7e4Schristos 
2533fdccd7e4Schristos /* Useful combinations of channel characteristics, borrowed from Ethereal */
2534fdccd7e4Schristos #define IEEE80211_CHAN_A \
2535fdccd7e4Schristos 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
2536fdccd7e4Schristos #define IEEE80211_CHAN_B \
2537fdccd7e4Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
2538fdccd7e4Schristos #define IEEE80211_CHAN_G \
2539fdccd7e4Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2540fdccd7e4Schristos #define IEEE80211_CHAN_TA \
2541fdccd7e4Schristos 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
2542fdccd7e4Schristos #define IEEE80211_CHAN_TG \
2543fdccd7e4Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN  | IEEE80211_CHAN_TURBO)
2544fdccd7e4Schristos 
2545fdccd7e4Schristos 
2546fdccd7e4Schristos /* For IEEE80211_RADIOTAP_FLAGS */
2547fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
2548fdccd7e4Schristos 						 * during CFP
2549fdccd7e4Schristos 						 */
2550fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
2551fdccd7e4Schristos 						 * with short
2552fdccd7e4Schristos 						 * preamble
2553fdccd7e4Schristos 						 */
2554fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
2555fdccd7e4Schristos 						 * with WEP encryption
2556fdccd7e4Schristos 						 */
2557fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
2558fdccd7e4Schristos 						 * with fragmentation
2559fdccd7e4Schristos 						 */
2560fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
2561fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
2562fdccd7e4Schristos 						 * 802.11 header and payload
2563fdccd7e4Schristos 						 * (to 32-bit boundary)
2564fdccd7e4Schristos 						 */
2565fdccd7e4Schristos #define	IEEE80211_RADIOTAP_F_BADFCS	0x40	/* does not pass FCS check */
2566fdccd7e4Schristos 
2567fdccd7e4Schristos /* For IEEE80211_RADIOTAP_RX_FLAGS */
2568fdccd7e4Schristos #define IEEE80211_RADIOTAP_F_RX_BADFCS	0x0001	/* frame failed crc check */
2569fdccd7e4Schristos #define IEEE80211_RADIOTAP_F_RX_PLCP_CRC	0x0002	/* frame failed PLCP CRC check */
2570fdccd7e4Schristos 
2571fdccd7e4Schristos /* For IEEE80211_RADIOTAP_MCS known */
2572fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN		0x01
2573fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN		0x02	/* MCS index field */
2574fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN	0x04
2575fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN		0x08
2576fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN		0x10
2577fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_STBC_KNOWN		0x20
2578fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_NESS_KNOWN		0x40
2579fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_NESS_BIT_1		0x80
2580fdccd7e4Schristos 
2581fdccd7e4Schristos /* For IEEE80211_RADIOTAP_MCS flags */
2582fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK	0x03
2583fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20	0
2584fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_40	1
2585fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20L	2
2586fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20U	3
2587fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_SHORT_GI		0x04 /* short guard interval */
2588fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_HT_GREENFIELD	0x08
2589fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10
2590fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_STBC_MASK	0x60
2591fdccd7e4Schristos #define		IEEE80211_RADIOTAP_MCS_STBC_1	1
2592fdccd7e4Schristos #define		IEEE80211_RADIOTAP_MCS_STBC_2	2
2593fdccd7e4Schristos #define		IEEE80211_RADIOTAP_MCS_STBC_3	3
2594fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT	5
2595fdccd7e4Schristos #define IEEE80211_RADIOTAP_MCS_NESS_BIT_0	0x80
2596fdccd7e4Schristos 
2597fdccd7e4Schristos /* For IEEE80211_RADIOTAP_AMPDU_STATUS */
2598fdccd7e4Schristos #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN		0x0001
2599fdccd7e4Schristos #define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN		0x0002
2600fdccd7e4Schristos #define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN		0x0004
2601fdccd7e4Schristos #define IEEE80211_RADIOTAP_AMPDU_IS_LAST		0x0008
2602fdccd7e4Schristos #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR		0x0010
2603fdccd7e4Schristos #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN	0x0020
2604fdccd7e4Schristos 
2605fdccd7e4Schristos /* For IEEE80211_RADIOTAP_VHT known */
2606fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_STBC_KNOWN			0x0001
2607fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA_KNOWN			0x0002
2608fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN		0x0004
2609fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_SGI_NSYM_DIS_KNOWN		0x0008
2610fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM_KNOWN	0x0010
2611fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_BEAMFORMED_KNOWN			0x0020
2612fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN			0x0040
2613fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_GROUP_ID_KNOWN			0x0080
2614fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_PARTIAL_AID_KNOWN		0x0100
2615fdccd7e4Schristos 
2616fdccd7e4Schristos /* For IEEE80211_RADIOTAP_VHT flags */
2617fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_STBC			0x01
2618fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA		0x02
2619fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_SHORT_GI			0x04
2620fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_SGI_NSYM_M10_9		0x08
2621fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM	0x10
2622fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_BEAMFORMED		0x20
2623fdccd7e4Schristos 
2624fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK	0x1f
2625fdccd7e4Schristos 
2626fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_NSS_MASK		0x0f
2627fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_MCS_MASK		0xf0
2628fdccd7e4Schristos #define IEEE80211_RADIOTAP_VHT_MCS_SHIFT	4
2629fdccd7e4Schristos 
2630fdccd7e4Schristos #define IEEE80211_RADIOTAP_CODING_LDPC_USERn			0x01
2631fdccd7e4Schristos 
26320f74e101Schristos #define	IEEE80211_CHAN_FHSS \
26330f74e101Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
26340f74e101Schristos #define	IEEE80211_CHAN_A \
26350f74e101Schristos 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
26360f74e101Schristos #define	IEEE80211_CHAN_B \
26370f74e101Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
26380f74e101Schristos #define	IEEE80211_CHAN_PUREG \
26390f74e101Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
26400f74e101Schristos #define	IEEE80211_CHAN_G \
26410f74e101Schristos 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
26420f74e101Schristos 
26430f74e101Schristos #define	IS_CHAN_FHSS(flags) \
26440f74e101Schristos 	((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
26450f74e101Schristos #define	IS_CHAN_A(flags) \
26460f74e101Schristos 	((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
26470f74e101Schristos #define	IS_CHAN_B(flags) \
26480f74e101Schristos 	((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
26490f74e101Schristos #define	IS_CHAN_PUREG(flags) \
26500f74e101Schristos 	((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
26510f74e101Schristos #define	IS_CHAN_G(flags) \
26520f74e101Schristos 	((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
26530f74e101Schristos #define	IS_CHAN_ANYG(flags) \
26540f74e101Schristos 	(IS_CHAN_PUREG(flags) || IS_CHAN_G(flags))
26550f74e101Schristos 
26560f74e101Schristos static void
2657b3a00663Schristos print_chaninfo(netdissect_options *ndo,
2658c74ad251Schristos 	       uint16_t freq, uint32_t flags, uint32_t presentflags)
26590f74e101Schristos {
2660c74ad251Schristos 	ND_PRINT("%u MHz", freq);
2661fdccd7e4Schristos 	if (presentflags & (1 << IEEE80211_RADIOTAP_MCS)) {
2662fdccd7e4Schristos 		/*
2663fdccd7e4Schristos 		 * We have the MCS field, so this is 11n, regardless
2664fdccd7e4Schristos 		 * of what the channel flags say.
2665fdccd7e4Schristos 		 */
2666c74ad251Schristos 		ND_PRINT(" 11n");
2667fdccd7e4Schristos 	} else {
26680f74e101Schristos 		if (IS_CHAN_FHSS(flags))
2669c74ad251Schristos 			ND_PRINT(" FHSS");
26700f74e101Schristos 		if (IS_CHAN_A(flags)) {
26710f74e101Schristos 			if (flags & IEEE80211_CHAN_HALF)
2672c74ad251Schristos 				ND_PRINT(" 11a/10Mhz");
26730f74e101Schristos 			else if (flags & IEEE80211_CHAN_QUARTER)
2674c74ad251Schristos 				ND_PRINT(" 11a/5Mhz");
26750f74e101Schristos 			else
2676c74ad251Schristos 				ND_PRINT(" 11a");
26770f74e101Schristos 		}
26780f74e101Schristos 		if (IS_CHAN_ANYG(flags)) {
26790f74e101Schristos 			if (flags & IEEE80211_CHAN_HALF)
2680c74ad251Schristos 				ND_PRINT(" 11g/10Mhz");
26810f74e101Schristos 			else if (flags & IEEE80211_CHAN_QUARTER)
2682c74ad251Schristos 				ND_PRINT(" 11g/5Mhz");
26830f74e101Schristos 			else
2684c74ad251Schristos 				ND_PRINT(" 11g");
26850f74e101Schristos 		} else if (IS_CHAN_B(flags))
2686c74ad251Schristos 			ND_PRINT(" 11b");
26870f74e101Schristos 		if (flags & IEEE80211_CHAN_TURBO)
2688c74ad251Schristos 			ND_PRINT(" Turbo");
2689fdccd7e4Schristos 	}
2690fdccd7e4Schristos 	/*
2691fdccd7e4Schristos 	 * These apply to 11n.
2692fdccd7e4Schristos 	 */
26930f74e101Schristos 	if (flags & IEEE80211_CHAN_HT20)
2694c74ad251Schristos 		ND_PRINT(" ht/20");
26950f74e101Schristos 	else if (flags & IEEE80211_CHAN_HT40D)
2696c74ad251Schristos 		ND_PRINT(" ht/40-");
26970f74e101Schristos 	else if (flags & IEEE80211_CHAN_HT40U)
2698c74ad251Schristos 		ND_PRINT(" ht/40+");
2699c74ad251Schristos 	ND_PRINT(" ");
27000f74e101Schristos }
27010f74e101Schristos 
27020f74e101Schristos static int
2703b3a00663Schristos print_radiotap_field(netdissect_options *ndo,
2704fdccd7e4Schristos 		     struct cpack_state *s, uint32_t bit, uint8_t *flagsp,
2705fdccd7e4Schristos 		     uint32_t presentflags)
27060f74e101Schristos {
2707fdccd7e4Schristos 	u_int i;
27080f74e101Schristos 	int rc;
27090f74e101Schristos 
27100f74e101Schristos 	switch (bit) {
27110e9868baSchristos 
2712fdccd7e4Schristos 	case IEEE80211_RADIOTAP_TSFT: {
2713fdccd7e4Schristos 		uint64_t tsft;
27140e9868baSchristos 
2715c74ad251Schristos 		rc = nd_cpack_uint64(ndo, s, &tsft);
2716fdccd7e4Schristos 		if (rc != 0)
2717fdccd7e4Schristos 			goto trunc;
2718c74ad251Schristos 		ND_PRINT("%" PRIu64 "us tsft ", tsft);
27190e9868baSchristos 		break;
27200e9868baSchristos 		}
27210e9868baSchristos 
2722fdccd7e4Schristos 	case IEEE80211_RADIOTAP_FLAGS: {
2723fdccd7e4Schristos 		uint8_t flagsval;
27240e9868baSchristos 
2725c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &flagsval);
2726fdccd7e4Schristos 		if (rc != 0)
2727fdccd7e4Schristos 			goto trunc;
2728fdccd7e4Schristos 		*flagsp = flagsval;
2729fdccd7e4Schristos 		if (flagsval & IEEE80211_RADIOTAP_F_CFP)
2730c74ad251Schristos 			ND_PRINT("cfp ");
2731fdccd7e4Schristos 		if (flagsval & IEEE80211_RADIOTAP_F_SHORTPRE)
2732c74ad251Schristos 			ND_PRINT("short preamble ");
2733fdccd7e4Schristos 		if (flagsval & IEEE80211_RADIOTAP_F_WEP)
2734c74ad251Schristos 			ND_PRINT("wep ");
2735fdccd7e4Schristos 		if (flagsval & IEEE80211_RADIOTAP_F_FRAG)
2736c74ad251Schristos 			ND_PRINT("fragmented ");
2737fdccd7e4Schristos 		if (flagsval & IEEE80211_RADIOTAP_F_BADFCS)
2738c74ad251Schristos 			ND_PRINT("bad-fcs ");
27390e9868baSchristos 		break;
27400e9868baSchristos 		}
27410f74e101Schristos 
2742fdccd7e4Schristos 	case IEEE80211_RADIOTAP_RATE: {
2743fdccd7e4Schristos 		uint8_t rate;
27440f74e101Schristos 
2745c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &rate);
2746fdccd7e4Schristos 		if (rc != 0)
2747fdccd7e4Schristos 			goto trunc;
27480e9868baSchristos 		/*
27490e9868baSchristos 		 * XXX On FreeBSD rate & 0x80 means we have an MCS. On
27500e9868baSchristos 		 * Linux and AirPcap it does not.  (What about
2751c74ad251Schristos 		 * macOS, NetBSD, OpenBSD, and DragonFly BSD?)
27520e9868baSchristos 		 *
27530e9868baSchristos 		 * This is an issue either for proprietary extensions
27540e9868baSchristos 		 * to 11a or 11g, which do exist, or for 11n
27550e9868baSchristos 		 * implementations that stuff a rate value into
27560e9868baSchristos 		 * this field, which also appear to exist.
27570e9868baSchristos 		 *
27580e9868baSchristos 		 * We currently handle that by assuming that
27590e9868baSchristos 		 * if the 0x80 bit is set *and* the remaining
27600e9868baSchristos 		 * bits have a value between 0 and 15 it's
27610e9868baSchristos 		 * an MCS value, otherwise it's a rate.  If
27620e9868baSchristos 		 * there are cases where systems that use
27630e9868baSchristos 		 * "0x80 + MCS index" for MCS indices > 15,
27640e9868baSchristos 		 * or stuff a rate value here between 64 and
27650e9868baSchristos 		 * 71.5 Mb/s in here, we'll need a preference
27660e9868baSchristos 		 * setting.  Such rates do exist, e.g. 11n
27670e9868baSchristos 		 * MCS 7 at 20 MHz with a long guard interval.
27680e9868baSchristos 		 */
2769fdccd7e4Schristos 		if (rate >= 0x80 && rate <= 0x8f) {
27700e9868baSchristos 			/*
27710e9868baSchristos 			 * XXX - we don't know the channel width
27720e9868baSchristos 			 * or guard interval length, so we can't
27730e9868baSchristos 			 * convert this to a data rate.
27740e9868baSchristos 			 *
27750e9868baSchristos 			 * If you want us to show a data rate,
27760e9868baSchristos 			 * use the MCS field, not the Rate field;
27770e9868baSchristos 			 * the MCS field includes not only the
27780e9868baSchristos 			 * MCS index, it also includes bandwidth
27790e9868baSchristos 			 * and guard interval information.
27800e9868baSchristos 			 *
27810e9868baSchristos 			 * XXX - can we get the channel width
27820e9868baSchristos 			 * from XChannel and the guard interval
27830e9868baSchristos 			 * information from Flags, at least on
27840e9868baSchristos 			 * FreeBSD?
27850e9868baSchristos 			 */
2786c74ad251Schristos 			ND_PRINT("MCS %u ", rate & 0x7f);
27870e9868baSchristos 		} else
2788c74ad251Schristos 			ND_PRINT("%2.1f Mb/s ", .5 * rate);
27890f74e101Schristos 		break;
2790fdccd7e4Schristos 		}
2791fdccd7e4Schristos 
2792fdccd7e4Schristos 	case IEEE80211_RADIOTAP_CHANNEL: {
2793fdccd7e4Schristos 		uint16_t frequency;
2794fdccd7e4Schristos 		uint16_t flags;
2795fdccd7e4Schristos 
2796c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &frequency);
2797fdccd7e4Schristos 		if (rc != 0)
2798fdccd7e4Schristos 			goto trunc;
2799c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &flags);
2800fdccd7e4Schristos 		if (rc != 0)
2801fdccd7e4Schristos 			goto trunc;
2802fdccd7e4Schristos 		/*
2803fdccd7e4Schristos 		 * If CHANNEL and XCHANNEL are both present, skip
2804fdccd7e4Schristos 		 * CHANNEL.
2805fdccd7e4Schristos 		 */
2806fdccd7e4Schristos 		if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL))
28070f74e101Schristos 			break;
2808fdccd7e4Schristos 		print_chaninfo(ndo, frequency, flags, presentflags);
28090f74e101Schristos 		break;
2810fdccd7e4Schristos 		}
2811fdccd7e4Schristos 
2812fdccd7e4Schristos 	case IEEE80211_RADIOTAP_FHSS: {
2813fdccd7e4Schristos 		uint8_t hopset;
2814fdccd7e4Schristos 		uint8_t hoppat;
2815fdccd7e4Schristos 
2816c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &hopset);
2817fdccd7e4Schristos 		if (rc != 0)
2818fdccd7e4Schristos 			goto trunc;
2819c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &hoppat);
2820fdccd7e4Schristos 		if (rc != 0)
2821fdccd7e4Schristos 			goto trunc;
2822c74ad251Schristos 		ND_PRINT("fhset %u fhpat %u ", hopset, hoppat);
28230f74e101Schristos 		break;
2824fdccd7e4Schristos 		}
2825fdccd7e4Schristos 
2826fdccd7e4Schristos 	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: {
2827fdccd7e4Schristos 		int8_t dbm_antsignal;
2828fdccd7e4Schristos 
2829c74ad251Schristos 		rc = nd_cpack_int8(ndo, s, &dbm_antsignal);
2830fdccd7e4Schristos 		if (rc != 0)
2831fdccd7e4Schristos 			goto trunc;
2832c74ad251Schristos 		ND_PRINT("%ddBm signal ", dbm_antsignal);
28330f74e101Schristos 		break;
2834fdccd7e4Schristos 		}
2835fdccd7e4Schristos 
2836fdccd7e4Schristos 	case IEEE80211_RADIOTAP_DBM_ANTNOISE: {
2837fdccd7e4Schristos 		int8_t dbm_antnoise;
2838fdccd7e4Schristos 
2839c74ad251Schristos 		rc = nd_cpack_int8(ndo, s, &dbm_antnoise);
2840fdccd7e4Schristos 		if (rc != 0)
2841fdccd7e4Schristos 			goto trunc;
2842c74ad251Schristos 		ND_PRINT("%ddBm noise ", dbm_antnoise);
28430f74e101Schristos 		break;
2844fdccd7e4Schristos 		}
2845fdccd7e4Schristos 
2846fdccd7e4Schristos 	case IEEE80211_RADIOTAP_LOCK_QUALITY: {
2847fdccd7e4Schristos 		uint16_t lock_quality;
2848fdccd7e4Schristos 
2849c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &lock_quality);
2850fdccd7e4Schristos 		if (rc != 0)
2851fdccd7e4Schristos 			goto trunc;
2852c74ad251Schristos 		ND_PRINT("%u sq ", lock_quality);
28530f74e101Schristos 		break;
2854fdccd7e4Schristos 		}
2855fdccd7e4Schristos 
2856fdccd7e4Schristos 	case IEEE80211_RADIOTAP_TX_ATTENUATION: {
2857c74ad251Schristos 		int16_t tx_attenuation;
2858fdccd7e4Schristos 
2859c74ad251Schristos 		rc = nd_cpack_int16(ndo, s, &tx_attenuation);
2860fdccd7e4Schristos 		if (rc != 0)
2861fdccd7e4Schristos 			goto trunc;
2862c74ad251Schristos 		ND_PRINT("%d tx power ", -tx_attenuation);
28630f74e101Schristos 		break;
2864fdccd7e4Schristos 		}
2865fdccd7e4Schristos 
2866fdccd7e4Schristos 	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: {
2867c74ad251Schristos 		int8_t db_tx_attenuation;
2868fdccd7e4Schristos 
2869c74ad251Schristos 		rc = nd_cpack_int8(ndo, s, &db_tx_attenuation);
2870fdccd7e4Schristos 		if (rc != 0)
2871fdccd7e4Schristos 			goto trunc;
2872c74ad251Schristos 		ND_PRINT("%ddB tx attenuation ", -db_tx_attenuation);
28730f74e101Schristos 		break;
2874fdccd7e4Schristos 		}
2875fdccd7e4Schristos 
2876fdccd7e4Schristos 	case IEEE80211_RADIOTAP_DBM_TX_POWER: {
2877fdccd7e4Schristos 		int8_t dbm_tx_power;
2878fdccd7e4Schristos 
2879c74ad251Schristos 		rc = nd_cpack_int8(ndo, s, &dbm_tx_power);
2880fdccd7e4Schristos 		if (rc != 0)
2881fdccd7e4Schristos 			goto trunc;
2882c74ad251Schristos 		ND_PRINT("%ddBm tx power ", dbm_tx_power);
28830f74e101Schristos 		break;
2884fdccd7e4Schristos 		}
2885fdccd7e4Schristos 
2886fdccd7e4Schristos 	case IEEE80211_RADIOTAP_ANTENNA: {
2887fdccd7e4Schristos 		uint8_t antenna;
2888fdccd7e4Schristos 
2889c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &antenna);
2890fdccd7e4Schristos 		if (rc != 0)
2891fdccd7e4Schristos 			goto trunc;
2892c74ad251Schristos 		ND_PRINT("antenna %u ", antenna);
28930f74e101Schristos 		break;
2894fdccd7e4Schristos 		}
2895fdccd7e4Schristos 
2896fdccd7e4Schristos 	case IEEE80211_RADIOTAP_DB_ANTSIGNAL: {
2897fdccd7e4Schristos 		uint8_t db_antsignal;
2898fdccd7e4Schristos 
2899c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &db_antsignal);
2900fdccd7e4Schristos 		if (rc != 0)
2901fdccd7e4Schristos 			goto trunc;
2902c74ad251Schristos 		ND_PRINT("%udB signal ", db_antsignal);
29030f74e101Schristos 		break;
2904fdccd7e4Schristos 		}
2905fdccd7e4Schristos 
2906fdccd7e4Schristos 	case IEEE80211_RADIOTAP_DB_ANTNOISE: {
2907fdccd7e4Schristos 		uint8_t db_antnoise;
2908fdccd7e4Schristos 
2909c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &db_antnoise);
2910fdccd7e4Schristos 		if (rc != 0)
2911fdccd7e4Schristos 			goto trunc;
2912c74ad251Schristos 		ND_PRINT("%udB noise ", db_antnoise);
2913fdccd7e4Schristos 		break;
2914fdccd7e4Schristos 		}
2915fdccd7e4Schristos 
2916fdccd7e4Schristos 	case IEEE80211_RADIOTAP_RX_FLAGS: {
2917fdccd7e4Schristos 		uint16_t rx_flags;
2918fdccd7e4Schristos 
2919c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &rx_flags);
2920fdccd7e4Schristos 		if (rc != 0)
2921fdccd7e4Schristos 			goto trunc;
29220e9868baSchristos 		/* Do nothing for now */
29230e9868baSchristos 		break;
2924fdccd7e4Schristos 		}
2925fdccd7e4Schristos 
2926fdccd7e4Schristos 	case IEEE80211_RADIOTAP_XCHANNEL: {
2927fdccd7e4Schristos 		uint32_t flags;
2928fdccd7e4Schristos 		uint16_t frequency;
2929fdccd7e4Schristos 		uint8_t channel;
2930fdccd7e4Schristos 		uint8_t maxpower;
2931fdccd7e4Schristos 
2932c74ad251Schristos 		rc = nd_cpack_uint32(ndo, s, &flags);
2933fdccd7e4Schristos 		if (rc != 0)
2934fdccd7e4Schristos 			goto trunc;
2935c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &frequency);
2936fdccd7e4Schristos 		if (rc != 0)
2937fdccd7e4Schristos 			goto trunc;
2938c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &channel);
2939fdccd7e4Schristos 		if (rc != 0)
2940fdccd7e4Schristos 			goto trunc;
2941c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &maxpower);
2942fdccd7e4Schristos 		if (rc != 0)
2943fdccd7e4Schristos 			goto trunc;
2944fdccd7e4Schristos 		print_chaninfo(ndo, frequency, flags, presentflags);
29450f74e101Schristos 		break;
2946fdccd7e4Schristos 		}
2947fdccd7e4Schristos 
29480e9868baSchristos 	case IEEE80211_RADIOTAP_MCS: {
2949fdccd7e4Schristos 		uint8_t known;
2950fdccd7e4Schristos 		uint8_t flags;
2951fdccd7e4Schristos 		uint8_t mcs_index;
2952fdccd7e4Schristos 		static const char *ht_bandwidth[4] = {
29530e9868baSchristos 			"20 MHz",
29540e9868baSchristos 			"40 MHz",
29550e9868baSchristos 			"20 MHz (L)",
29560e9868baSchristos 			"20 MHz (U)"
29570e9868baSchristos 		};
29580e9868baSchristos 		float htrate;
29590e9868baSchristos 
2960c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &known);
2961fdccd7e4Schristos 		if (rc != 0)
2962fdccd7e4Schristos 			goto trunc;
2963c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &flags);
2964fdccd7e4Schristos 		if (rc != 0)
2965fdccd7e4Schristos 			goto trunc;
2966c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &mcs_index);
2967fdccd7e4Schristos 		if (rc != 0)
2968fdccd7e4Schristos 			goto trunc;
2969fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) {
29700e9868baSchristos 			/*
29710e9868baSchristos 			 * We know the MCS index.
29720e9868baSchristos 			 */
2973fdccd7e4Schristos 			if (mcs_index <= MAX_MCS_INDEX) {
29740e9868baSchristos 				/*
29750e9868baSchristos 				 * And it's in-range.
29760e9868baSchristos 				 */
2977fdccd7e4Schristos 				if (known & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) {
29780e9868baSchristos 					/*
29790e9868baSchristos 					 * And we know both the bandwidth and
29800e9868baSchristos 					 * the guard interval, so we can look
29810e9868baSchristos 					 * up the rate.
29820e9868baSchristos 					 */
29830e9868baSchristos 					htrate =
2984c74ad251Schristos 						ieee80211_float_htrates
2985c74ad251Schristos 							[mcs_index]
2986c74ad251Schristos 							[((flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)]
2987fdccd7e4Schristos 							[((flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)];
29880e9868baSchristos 				} else {
29890e9868baSchristos 					/*
29900e9868baSchristos 					 * We don't know both the bandwidth
29910e9868baSchristos 					 * and the guard interval, so we can
29920e9868baSchristos 					 * only report the MCS index.
29930e9868baSchristos 					 */
29940e9868baSchristos 					htrate = 0.0;
29950e9868baSchristos 				}
29960e9868baSchristos 			} else {
29970e9868baSchristos 				/*
29980e9868baSchristos 				 * The MCS value is out of range.
29990e9868baSchristos 				 */
30000e9868baSchristos 				htrate = 0.0;
30010e9868baSchristos 			}
30020e9868baSchristos 			if (htrate != 0.0) {
30030e9868baSchristos 				/*
30040e9868baSchristos 				 * We have the rate.
30050e9868baSchristos 				 * Print it.
30060e9868baSchristos 				 */
3007c74ad251Schristos 				ND_PRINT("%.1f Mb/s MCS %u ", htrate, mcs_index);
30080e9868baSchristos 			} else {
30090e9868baSchristos 				/*
30100e9868baSchristos 				 * We at least have the MCS index.
30110e9868baSchristos 				 * Print it.
30120e9868baSchristos 				 */
3013c74ad251Schristos 				ND_PRINT("MCS %u ", mcs_index);
30140e9868baSchristos 			}
30150e9868baSchristos 		}
3016fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) {
3017c74ad251Schristos 			ND_PRINT("%s ",
3018c74ad251Schristos 				ht_bandwidth[flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK]);
30190e9868baSchristos 		}
3020fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) {
3021c74ad251Schristos 			ND_PRINT("%s GI ",
3022fdccd7e4Schristos 				(flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ?
3023c74ad251Schristos 				"short" : "long");
30240e9868baSchristos 		}
3025fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) {
3026c74ad251Schristos 			ND_PRINT("%s ",
3027fdccd7e4Schristos 				(flags & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ?
3028c74ad251Schristos 				"greenfield" : "mixed");
30290e9868baSchristos 		}
3030fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) {
3031c74ad251Schristos 			ND_PRINT("%s FEC ",
3032fdccd7e4Schristos 				(flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ?
3033c74ad251Schristos 				"LDPC" : "BCC");
30340e9868baSchristos 		}
3035fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) {
3036c74ad251Schristos 			ND_PRINT("RX-STBC%u ",
3037c74ad251Schristos 				(flags & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT);
3038870189d2Schristos 		}
30390e9868baSchristos 		break;
30400e9868baSchristos 		}
3041fdccd7e4Schristos 
3042fdccd7e4Schristos 	case IEEE80211_RADIOTAP_AMPDU_STATUS: {
3043fdccd7e4Schristos 		uint32_t reference_num;
3044fdccd7e4Schristos 		uint16_t flags;
3045fdccd7e4Schristos 		uint8_t delim_crc;
3046fdccd7e4Schristos 		uint8_t reserved;
3047fdccd7e4Schristos 
3048c74ad251Schristos 		rc = nd_cpack_uint32(ndo, s, &reference_num);
3049fdccd7e4Schristos 		if (rc != 0)
3050fdccd7e4Schristos 			goto trunc;
3051c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &flags);
3052fdccd7e4Schristos 		if (rc != 0)
3053fdccd7e4Schristos 			goto trunc;
3054c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &delim_crc);
3055fdccd7e4Schristos 		if (rc != 0)
3056fdccd7e4Schristos 			goto trunc;
3057c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &reserved);
3058fdccd7e4Schristos 		if (rc != 0)
3059fdccd7e4Schristos 			goto trunc;
3060fdccd7e4Schristos 		/* Do nothing for now */
3061fdccd7e4Schristos 		break;
30620f74e101Schristos 		}
3063fdccd7e4Schristos 
3064fdccd7e4Schristos 	case IEEE80211_RADIOTAP_VHT: {
3065fdccd7e4Schristos 		uint16_t known;
3066fdccd7e4Schristos 		uint8_t flags;
3067fdccd7e4Schristos 		uint8_t bandwidth;
3068fdccd7e4Schristos 		uint8_t mcs_nss[4];
3069fdccd7e4Schristos 		uint8_t coding;
3070fdccd7e4Schristos 		uint8_t group_id;
3071fdccd7e4Schristos 		uint16_t partial_aid;
3072fdccd7e4Schristos 		static const char *vht_bandwidth[32] = {
3073fdccd7e4Schristos 			"20 MHz",
3074fdccd7e4Schristos 			"40 MHz",
3075fdccd7e4Schristos 			"20 MHz (L)",
3076fdccd7e4Schristos 			"20 MHz (U)",
3077fdccd7e4Schristos 			"80 MHz",
3078fdccd7e4Schristos 			"80 MHz (L)",
3079fdccd7e4Schristos 			"80 MHz (U)",
3080fdccd7e4Schristos 			"80 MHz (LL)",
3081fdccd7e4Schristos 			"80 MHz (LU)",
3082fdccd7e4Schristos 			"80 MHz (UL)",
3083fdccd7e4Schristos 			"80 MHz (UU)",
3084fdccd7e4Schristos 			"160 MHz",
3085fdccd7e4Schristos 			"160 MHz (L)",
3086fdccd7e4Schristos 			"160 MHz (U)",
3087fdccd7e4Schristos 			"160 MHz (LL)",
3088fdccd7e4Schristos 			"160 MHz (LU)",
3089fdccd7e4Schristos 			"160 MHz (UL)",
3090fdccd7e4Schristos 			"160 MHz (UU)",
3091fdccd7e4Schristos 			"160 MHz (LLL)",
3092fdccd7e4Schristos 			"160 MHz (LLU)",
3093fdccd7e4Schristos 			"160 MHz (LUL)",
3094fdccd7e4Schristos 			"160 MHz (UUU)",
3095fdccd7e4Schristos 			"160 MHz (ULL)",
3096fdccd7e4Schristos 			"160 MHz (ULU)",
3097fdccd7e4Schristos 			"160 MHz (UUL)",
3098fdccd7e4Schristos 			"160 MHz (UUU)",
3099fdccd7e4Schristos 			"unknown (26)",
3100fdccd7e4Schristos 			"unknown (27)",
3101fdccd7e4Schristos 			"unknown (28)",
3102fdccd7e4Schristos 			"unknown (29)",
3103fdccd7e4Schristos 			"unknown (30)",
3104fdccd7e4Schristos 			"unknown (31)"
3105fdccd7e4Schristos 		};
3106fdccd7e4Schristos 
3107c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &known);
3108fdccd7e4Schristos 		if (rc != 0)
3109fdccd7e4Schristos 			goto trunc;
3110c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &flags);
3111fdccd7e4Schristos 		if (rc != 0)
3112fdccd7e4Schristos 			goto trunc;
3113c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &bandwidth);
3114fdccd7e4Schristos 		if (rc != 0)
3115fdccd7e4Schristos 			goto trunc;
3116fdccd7e4Schristos 		for (i = 0; i < 4; i++) {
3117c74ad251Schristos 			rc = nd_cpack_uint8(ndo, s, &mcs_nss[i]);
3118fdccd7e4Schristos 			if (rc != 0)
3119fdccd7e4Schristos 				goto trunc;
3120fdccd7e4Schristos 		}
3121c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &coding);
3122fdccd7e4Schristos 		if (rc != 0)
3123fdccd7e4Schristos 			goto trunc;
3124c74ad251Schristos 		rc = nd_cpack_uint8(ndo, s, &group_id);
3125fdccd7e4Schristos 		if (rc != 0)
3126fdccd7e4Schristos 			goto trunc;
3127c74ad251Schristos 		rc = nd_cpack_uint16(ndo, s, &partial_aid);
3128fdccd7e4Schristos 		if (rc != 0)
3129fdccd7e4Schristos 			goto trunc;
3130fdccd7e4Schristos 		for (i = 0; i < 4; i++) {
3131fdccd7e4Schristos 			u_int nss, mcs;
3132fdccd7e4Schristos 			nss = mcs_nss[i] & IEEE80211_RADIOTAP_VHT_NSS_MASK;
3133fdccd7e4Schristos 			mcs = (mcs_nss[i] & IEEE80211_RADIOTAP_VHT_MCS_MASK) >> IEEE80211_RADIOTAP_VHT_MCS_SHIFT;
3134fdccd7e4Schristos 
3135fdccd7e4Schristos 			if (nss == 0)
3136fdccd7e4Schristos 				continue;
3137fdccd7e4Schristos 
3138c74ad251Schristos 			ND_PRINT("User %u MCS %u ", i, mcs);
3139c74ad251Schristos 			ND_PRINT("%s FEC ",
3140fdccd7e4Schristos 				(coding & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ?
3141c74ad251Schristos 				"LDPC" : "BCC");
3142fdccd7e4Schristos 		}
3143fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) {
3144c74ad251Schristos 			ND_PRINT("%s ",
3145c74ad251Schristos 				vht_bandwidth[bandwidth & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK]);
3146fdccd7e4Schristos 		}
3147fdccd7e4Schristos 		if (known & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) {
3148c74ad251Schristos 			ND_PRINT("%s GI ",
3149fdccd7e4Schristos 				(flags & IEEE80211_RADIOTAP_VHT_SHORT_GI) ?
3150c74ad251Schristos 				"short" : "long");
3151fdccd7e4Schristos 		}
3152fdccd7e4Schristos 		break;
3153fdccd7e4Schristos 		}
3154fdccd7e4Schristos 
3155fdccd7e4Schristos 	default:
3156fdccd7e4Schristos 		/* this bit indicates a field whose
3157fdccd7e4Schristos 		 * size we do not know, so we cannot
3158fdccd7e4Schristos 		 * proceed.  Just print the bit number.
3159fdccd7e4Schristos 		 */
3160c74ad251Schristos 		ND_PRINT("[bit %u] ", bit);
3161fdccd7e4Schristos 		return -1;
3162fdccd7e4Schristos 	}
3163fdccd7e4Schristos 
3164fdccd7e4Schristos 	return 0;
3165fdccd7e4Schristos 
3166fdccd7e4Schristos trunc:
3167c74ad251Schristos 	nd_print_trunc(ndo);
3168fdccd7e4Schristos 	return rc;
3169fdccd7e4Schristos }
3170fdccd7e4Schristos 
3171fdccd7e4Schristos 
3172fdccd7e4Schristos static int
3173fdccd7e4Schristos print_in_radiotap_namespace(netdissect_options *ndo,
3174fdccd7e4Schristos 			    struct cpack_state *s, uint8_t *flags,
3175fdccd7e4Schristos 			    uint32_t presentflags, int bit0)
3176fdccd7e4Schristos {
3177fdccd7e4Schristos #define	BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
3178fdccd7e4Schristos #define	BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
3179fdccd7e4Schristos #define	BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
3180fdccd7e4Schristos #define	BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
3181fdccd7e4Schristos #define	BITNO_2(x) (((x) & 2) ? 1 : 0)
3182fdccd7e4Schristos 	uint32_t present, next_present;
3183fdccd7e4Schristos 	int bitno;
3184fdccd7e4Schristos 	enum ieee80211_radiotap_type bit;
3185fdccd7e4Schristos 	int rc;
3186fdccd7e4Schristos 
3187fdccd7e4Schristos 	for (present = presentflags; present; present = next_present) {
3188fdccd7e4Schristos 		/*
3189fdccd7e4Schristos 		 * Clear the least significant bit that is set.
3190fdccd7e4Schristos 		 */
3191fdccd7e4Schristos 		next_present = present & (present - 1);
3192fdccd7e4Schristos 
3193fdccd7e4Schristos 		/*
3194fdccd7e4Schristos 		 * Get the bit number, within this presence word,
3195fdccd7e4Schristos 		 * of the remaining least significant bit that
3196fdccd7e4Schristos 		 * is set.
3197fdccd7e4Schristos 		 */
3198fdccd7e4Schristos 		bitno = BITNO_32(present ^ next_present);
3199fdccd7e4Schristos 
3200fdccd7e4Schristos 		/*
3201fdccd7e4Schristos 		 * Stop if this is one of the "same meaning
3202fdccd7e4Schristos 		 * in all presence flags" bits.
3203fdccd7e4Schristos 		 */
3204fdccd7e4Schristos 		if (bitno >= IEEE80211_RADIOTAP_NAMESPACE)
3205fdccd7e4Schristos 			break;
3206fdccd7e4Schristos 
3207fdccd7e4Schristos 		/*
3208fdccd7e4Schristos 		 * Get the radiotap bit number of that bit.
3209fdccd7e4Schristos 		 */
3210fdccd7e4Schristos 		bit = (enum ieee80211_radiotap_type)(bit0 + bitno);
3211fdccd7e4Schristos 
3212fdccd7e4Schristos 		rc = print_radiotap_field(ndo, s, bit, flags, presentflags);
3213fdccd7e4Schristos 		if (rc != 0)
3214fdccd7e4Schristos 			return rc;
3215fdccd7e4Schristos 	}
3216fdccd7e4Schristos 
32170f74e101Schristos 	return 0;
32180f74e101Schristos }
32190f74e101Schristos 
3220817e9a7eSchristos u_int
3221b3a00663Schristos ieee802_11_radio_print(netdissect_options *ndo,
3222b3a00663Schristos 		       const u_char *p, u_int length, u_int caplen)
32230f74e101Schristos {
32240f74e101Schristos #define	BIT(n)	(1U << n)
32250f74e101Schristos #define	IS_EXTENDED(__p)	\
3226c74ad251Schristos 	    (GET_LE_U_4(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
32270f74e101Schristos 
32280f74e101Schristos 	struct cpack_state cpacker;
3229fdccd7e4Schristos 	const struct ieee80211_radiotap_header *hdr;
3230fdccd7e4Schristos 	uint32_t presentflags;
3231c74ad251Schristos 	const nd_uint32_t *presentp, *last_presentp;
3232fdccd7e4Schristos 	int vendor_namespace;
3233fdccd7e4Schristos 	uint8_t vendor_oui[3];
3234fdccd7e4Schristos 	uint8_t vendor_subnamespace;
3235fdccd7e4Schristos 	uint16_t skip_length;
32360f74e101Schristos 	int bit0;
32370f74e101Schristos 	u_int len;
3238b3a00663Schristos 	uint8_t flags;
32390f74e101Schristos 	int pad;
32400f74e101Schristos 	u_int fcslen;
32410f74e101Schristos 
3242c74ad251Schristos 	ndo->ndo_protocol = "802.11_radio";
32430f74e101Schristos 	if (caplen < sizeof(*hdr)) {
3244c74ad251Schristos 		nd_print_trunc(ndo);
32450f74e101Schristos 		return caplen;
32460f74e101Schristos 	}
32470f74e101Schristos 
3248fdccd7e4Schristos 	hdr = (const struct ieee80211_radiotap_header *)p;
32490f74e101Schristos 
3250c74ad251Schristos 	len = GET_LE_U_2(hdr->it_len);
3251817e9a7eSchristos 	if (len < sizeof(*hdr)) {
3252817e9a7eSchristos 		/*
3253817e9a7eSchristos 		 * The length is the length of the entire header, so
3254817e9a7eSchristos 		 * it must be as large as the fixed-length part of
3255817e9a7eSchristos 		 * the header.
3256817e9a7eSchristos 		 */
3257c74ad251Schristos 		nd_print_trunc(ndo);
3258817e9a7eSchristos 		return caplen;
3259817e9a7eSchristos 	}
32600f74e101Schristos 
3261dc860a36Sspz 	/*
3262dc860a36Sspz 	 * If we don't have the entire radiotap header, just give up.
3263dc860a36Sspz 	 */
32640f74e101Schristos 	if (caplen < len) {
3265c74ad251Schristos 		nd_print_trunc(ndo);
32660f74e101Schristos 		return caplen;
32670f74e101Schristos 	}
3268c74ad251Schristos 	nd_cpack_init(&cpacker, (const uint8_t *)hdr, len); /* align against header start */
3269c74ad251Schristos 	nd_cpack_advance(&cpacker, sizeof(*hdr)); /* includes the 1st bitmap */
32700f74e101Schristos 	for (last_presentp = &hdr->it_present;
3271dc860a36Sspz 	     (const u_char*)(last_presentp + 1) <= p + len &&
3272dc860a36Sspz 	     IS_EXTENDED(last_presentp);
3273870189d2Schristos 	     last_presentp++)
3274c74ad251Schristos 	  nd_cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */
32750f74e101Schristos 
32760f74e101Schristos 	/* are there more bitmap extensions than bytes in header? */
3277dc860a36Sspz 	if ((const u_char*)(last_presentp + 1) > p + len) {
3278c74ad251Schristos 		nd_print_trunc(ndo);
32790f74e101Schristos 		return caplen;
32800f74e101Schristos 	}
32810f74e101Schristos 
3282fdccd7e4Schristos 	/*
3283fdccd7e4Schristos 	 * Start out at the beginning of the default radiotap namespace.
3284fdccd7e4Schristos 	 */
3285fdccd7e4Schristos 	bit0 = 0;
3286fdccd7e4Schristos 	vendor_namespace = 0;
3287fdccd7e4Schristos 	memset(vendor_oui, 0, 3);
3288fdccd7e4Schristos 	vendor_subnamespace = 0;
3289fdccd7e4Schristos 	skip_length = 0;
32900f74e101Schristos 	/* Assume no flags */
32910f74e101Schristos 	flags = 0;
32920f74e101Schristos 	/* Assume no Atheros padding between 802.11 header and body */
32930f74e101Schristos 	pad = 0;
32940f74e101Schristos 	/* Assume no FCS at end of frame */
32950f74e101Schristos 	fcslen = 0;
3296fdccd7e4Schristos 	for (presentp = &hdr->it_present; presentp <= last_presentp;
3297fdccd7e4Schristos 	    presentp++) {
3298c74ad251Schristos 		presentflags = GET_LE_U_4(presentp);
32990e9868baSchristos 
3300fdccd7e4Schristos 		/*
3301fdccd7e4Schristos 		 * If this is a vendor namespace, we don't handle it.
3302fdccd7e4Schristos 		 */
3303fdccd7e4Schristos 		if (vendor_namespace) {
3304fdccd7e4Schristos 			/*
3305fdccd7e4Schristos 			 * Skip past the stuff we don't understand.
3306fdccd7e4Schristos 			 * If we add support for any vendor namespaces,
3307fdccd7e4Schristos 			 * it'd be added here; use vendor_oui and
3308fdccd7e4Schristos 			 * vendor_subnamespace to interpret the fields.
3309fdccd7e4Schristos 			 */
3310c74ad251Schristos 			if (nd_cpack_advance(&cpacker, skip_length) != 0) {
3311fdccd7e4Schristos 				/*
3312fdccd7e4Schristos 				 * Ran out of space in the packet.
3313fdccd7e4Schristos 				 */
3314fdccd7e4Schristos 				break;
3315fdccd7e4Schristos 			}
33160e9868baSchristos 
3317fdccd7e4Schristos 			/*
3318fdccd7e4Schristos 			 * We've skipped it all; nothing more to
3319fdccd7e4Schristos 			 * skip.
3320fdccd7e4Schristos 			 */
3321fdccd7e4Schristos 			skip_length = 0;
3322fdccd7e4Schristos 		} else {
3323fdccd7e4Schristos 			if (print_in_radiotap_namespace(ndo, &cpacker,
3324fdccd7e4Schristos 			    &flags, presentflags, bit0) != 0) {
3325fdccd7e4Schristos 				/*
3326fdccd7e4Schristos 				 * Fatal error - can't process anything
3327fdccd7e4Schristos 				 * more in the radiotap header.
3328fdccd7e4Schristos 				 */
3329fdccd7e4Schristos 				break;
33300f74e101Schristos 			}
33310f74e101Schristos 		}
33320f74e101Schristos 
3333fdccd7e4Schristos 		/*
3334fdccd7e4Schristos 		 * Handle the namespace switch bits; we've already handled
3335fdccd7e4Schristos 		 * the extension bit in all but the last word above.
3336fdccd7e4Schristos 		 */
3337fdccd7e4Schristos 		switch (presentflags &
3338fdccd7e4Schristos 		    (BIT(IEEE80211_RADIOTAP_NAMESPACE)|BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE))) {
3339fdccd7e4Schristos 
3340fdccd7e4Schristos 		case 0:
3341fdccd7e4Schristos 			/*
3342fdccd7e4Schristos 			 * We're not changing namespaces.
3343fdccd7e4Schristos 			 * advance to the next 32 bits in the current
3344fdccd7e4Schristos 			 * namespace.
3345fdccd7e4Schristos 			 */
3346fdccd7e4Schristos 			bit0 += 32;
3347fdccd7e4Schristos 			break;
3348fdccd7e4Schristos 
3349fdccd7e4Schristos 		case BIT(IEEE80211_RADIOTAP_NAMESPACE):
3350fdccd7e4Schristos 			/*
3351fdccd7e4Schristos 			 * We're switching to the radiotap namespace.
3352fdccd7e4Schristos 			 * Reset the presence-bitmap index to 0, and
3353fdccd7e4Schristos 			 * reset the namespace to the default radiotap
3354fdccd7e4Schristos 			 * namespace.
3355fdccd7e4Schristos 			 */
3356fdccd7e4Schristos 			bit0 = 0;
3357fdccd7e4Schristos 			vendor_namespace = 0;
3358fdccd7e4Schristos 			memset(vendor_oui, 0, 3);
3359fdccd7e4Schristos 			vendor_subnamespace = 0;
3360fdccd7e4Schristos 			skip_length = 0;
3361fdccd7e4Schristos 			break;
3362fdccd7e4Schristos 
3363fdccd7e4Schristos 		case BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE):
3364fdccd7e4Schristos 			/*
3365fdccd7e4Schristos 			 * We're switching to a vendor namespace.
3366fdccd7e4Schristos 			 * Reset the presence-bitmap index to 0,
3367fdccd7e4Schristos 			 * note that we're in a vendor namespace,
3368fdccd7e4Schristos 			 * and fetch the fields of the Vendor Namespace
3369fdccd7e4Schristos 			 * item.
3370fdccd7e4Schristos 			 */
3371fdccd7e4Schristos 			bit0 = 0;
3372fdccd7e4Schristos 			vendor_namespace = 1;
3373c74ad251Schristos 			if ((nd_cpack_align_and_reserve(&cpacker, 2)) == NULL) {
3374c74ad251Schristos 				nd_print_trunc(ndo);
3375fdccd7e4Schristos 				break;
3376fdccd7e4Schristos 			}
3377c74ad251Schristos 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[0]) != 0) {
3378c74ad251Schristos 				nd_print_trunc(ndo);
3379fdccd7e4Schristos 				break;
3380fdccd7e4Schristos 			}
3381c74ad251Schristos 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[1]) != 0) {
3382c74ad251Schristos 				nd_print_trunc(ndo);
3383fdccd7e4Schristos 				break;
3384fdccd7e4Schristos 			}
3385c74ad251Schristos 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_oui[2]) != 0) {
3386c74ad251Schristos 				nd_print_trunc(ndo);
3387fdccd7e4Schristos 				break;
3388fdccd7e4Schristos 			}
3389c74ad251Schristos 			if (nd_cpack_uint8(ndo, &cpacker, &vendor_subnamespace) != 0) {
3390c74ad251Schristos 				nd_print_trunc(ndo);
3391fdccd7e4Schristos 				break;
3392fdccd7e4Schristos 			}
3393c74ad251Schristos 			if (nd_cpack_uint16(ndo, &cpacker, &skip_length) != 0) {
3394c74ad251Schristos 				nd_print_trunc(ndo);
3395fdccd7e4Schristos 				break;
3396fdccd7e4Schristos 			}
3397fdccd7e4Schristos 			break;
3398fdccd7e4Schristos 
3399fdccd7e4Schristos 		default:
3400fdccd7e4Schristos 			/*
3401fdccd7e4Schristos 			 * Illegal combination.  The behavior in this
3402fdccd7e4Schristos 			 * case is undefined by the radiotap spec; we
3403fdccd7e4Schristos 			 * just ignore both bits.
3404fdccd7e4Schristos 			 */
3405fdccd7e4Schristos 			break;
3406fdccd7e4Schristos 		}
3407fdccd7e4Schristos 	}
3408fdccd7e4Schristos 
34090f74e101Schristos 	if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
34100f74e101Schristos 		pad = 1;	/* Atheros padding */
34110f74e101Schristos 	if (flags & IEEE80211_RADIOTAP_F_FCS)
34120f74e101Schristos 		fcslen = 4;	/* FCS at end of packet */
3413b3a00663Schristos 	return len + ieee802_11_print(ndo, p + len, length - len, caplen - len, pad,
34140f74e101Schristos 	    fcslen);
34150f74e101Schristos #undef BITNO_32
34160f74e101Schristos #undef BITNO_16
34170f74e101Schristos #undef BITNO_8
34180f74e101Schristos #undef BITNO_4
34190f74e101Schristos #undef BITNO_2
34200f74e101Schristos #undef BIT
34210f74e101Schristos }
34220f74e101Schristos 
34230f74e101Schristos static u_int
3424c74ad251Schristos ieee802_11_radio_avs_print(netdissect_options *ndo,
3425b3a00663Schristos 			   const u_char *p, u_int length, u_int caplen)
34260f74e101Schristos {
3427b3a00663Schristos 	uint32_t caphdr_len;
34280f74e101Schristos 
3429c74ad251Schristos 	ndo->ndo_protocol = "802.11_radio_avs";
34300f74e101Schristos 	if (caplen < 8) {
3431c74ad251Schristos 		nd_print_trunc(ndo);
34320f74e101Schristos 		return caplen;
34330f74e101Schristos 	}
34340f74e101Schristos 
3435c74ad251Schristos 	caphdr_len = GET_BE_U_4(p + 4);
34360f74e101Schristos 	if (caphdr_len < 8) {
34370f74e101Schristos 		/*
34380f74e101Schristos 		 * Yow!  The capture header length is claimed not
34390f74e101Schristos 		 * to be large enough to include even the version
34400f74e101Schristos 		 * cookie or capture header length!
34410f74e101Schristos 		 */
3442c74ad251Schristos 		nd_print_trunc(ndo);
34430f74e101Schristos 		return caplen;
34440f74e101Schristos 	}
34450f74e101Schristos 
34460f74e101Schristos 	if (caplen < caphdr_len) {
3447c74ad251Schristos 		nd_print_trunc(ndo);
34480f74e101Schristos 		return caplen;
34490f74e101Schristos 	}
34500f74e101Schristos 
3451b3a00663Schristos 	return caphdr_len + ieee802_11_print(ndo, p + caphdr_len,
34520f74e101Schristos 	    length - caphdr_len, caplen - caphdr_len, 0, 0);
34530f74e101Schristos }
34540f74e101Schristos 
34550f74e101Schristos #define PRISM_HDR_LEN		144
34560f74e101Schristos 
34570f74e101Schristos #define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
34580f74e101Schristos #define WLANCAP_MAGIC_COOKIE_V1	0x80211001
34590f74e101Schristos #define WLANCAP_MAGIC_COOKIE_V2	0x80211002
34600f74e101Schristos 
34610f74e101Schristos /*
34620f74e101Schristos  * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
34630f74e101Schristos  * containing information such as radio information, which we
34640f74e101Schristos  * currently ignore.
34650f74e101Schristos  *
34660f74e101Schristos  * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or
34670f74e101Schristos  * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS
34680f74e101Schristos  * (currently, on Linux, there's no ARPHRD_ type for
34690f74e101Schristos  * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM
34700f74e101Schristos  * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for
34710f74e101Schristos  * the AVS header, and the first 4 bytes of the header are used to
34720f74e101Schristos  * indicate whether it's a Prism header or an AVS header).
34730f74e101Schristos  */
3474c74ad251Schristos void
3475b3a00663Schristos prism_if_print(netdissect_options *ndo,
3476b3a00663Schristos 	       const struct pcap_pkthdr *h, const u_char *p)
34770f74e101Schristos {
34780f74e101Schristos 	u_int caplen = h->caplen;
34790f74e101Schristos 	u_int length = h->len;
3480b3a00663Schristos 	uint32_t msgcode;
34810f74e101Schristos 
3482c74ad251Schristos 	ndo->ndo_protocol = "prism";
34830f74e101Schristos 	if (caplen < 4) {
3484c74ad251Schristos 		nd_print_trunc(ndo);
3485c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
3486c74ad251Schristos 		return;
34870f74e101Schristos 	}
34880f74e101Schristos 
3489c74ad251Schristos 	msgcode = GET_BE_U_4(p);
34900f74e101Schristos 	if (msgcode == WLANCAP_MAGIC_COOKIE_V1 ||
3491c74ad251Schristos 	    msgcode == WLANCAP_MAGIC_COOKIE_V2) {
3492c74ad251Schristos 		ndo->ndo_ll_hdr_len += ieee802_11_radio_avs_print(ndo, p, length, caplen);
3493c74ad251Schristos 		return;
3494c74ad251Schristos 	}
34950f74e101Schristos 
34960f74e101Schristos 	if (caplen < PRISM_HDR_LEN) {
3497c74ad251Schristos 		nd_print_trunc(ndo);
3498c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
3499c74ad251Schristos 		return;
35000f74e101Schristos 	}
35010f74e101Schristos 
3502c74ad251Schristos 	p += PRISM_HDR_LEN;
3503c74ad251Schristos 	length -= PRISM_HDR_LEN;
3504c74ad251Schristos 	caplen -= PRISM_HDR_LEN;
3505c74ad251Schristos 	ndo->ndo_ll_hdr_len += PRISM_HDR_LEN;
3506c74ad251Schristos 	ndo->ndo_ll_hdr_len += ieee802_11_print(ndo, p, length, caplen, 0, 0);
35070f74e101Schristos }
35080f74e101Schristos 
35090f74e101Schristos /*
35100f74e101Schristos  * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra
35110f74e101Schristos  * header, containing information such as radio information.
35120f74e101Schristos  */
3513c74ad251Schristos void
3514b3a00663Schristos ieee802_11_radio_if_print(netdissect_options *ndo,
3515b3a00663Schristos 			  const struct pcap_pkthdr *h, const u_char *p)
35160f74e101Schristos {
3517c74ad251Schristos 	ndo->ndo_protocol = "802.11_radio";
3518c74ad251Schristos 	ndo->ndo_ll_hdr_len += ieee802_11_radio_print(ndo, p, h->len, h->caplen);
35190f74e101Schristos }
35200f74e101Schristos 
35210f74e101Schristos /*
35220f74e101Schristos  * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an
35230f74e101Schristos  * extra header, containing information such as radio information,
35240f74e101Schristos  * which we currently ignore.
35250f74e101Schristos  */
3526c74ad251Schristos void
3527b3a00663Schristos ieee802_11_radio_avs_if_print(netdissect_options *ndo,
3528b3a00663Schristos 			      const struct pcap_pkthdr *h, const u_char *p)
35290f74e101Schristos {
3530c74ad251Schristos 	ndo->ndo_protocol = "802.11_radio_avs";
3531c74ad251Schristos 	ndo->ndo_ll_hdr_len += ieee802_11_radio_avs_print(ndo, p, h->len, h->caplen);
35320f74e101Schristos }
3533