1193326Sed/*
2193326Sed * Copyright (c) 2001
3193326Sed *	Fortress Technologies, Inc.  All rights reserved.
4193326Sed *      Charlie Lenahan (clenahan@fortresstech.com)
5193326Sed *
6193326Sed * Redistribution and use in source and binary forms, with or without
7193326Sed * modification, are permitted provided that: (1) source code distributions
8193326Sed * retain the above copyright notice and this paragraph in its entirety, (2)
9193326Sed * distributions including binary code include the above copyright notice and
10193326Sed * this paragraph in its entirety in the documentation or other materials
11193326Sed * provided with the distribution, and (3) all advertising materials mentioning
12193326Sed * features or use of this software display the following acknowledgement:
13193326Sed * ``This product includes software developed by the University of California,
14193326Sed * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15193326Sed * the University nor the names of its contributors may be used to endorse
16193326Sed * or promote products derived from this software without specific prior
17193326Sed * written permission.
18193326Sed * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19193326Sed * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20193326Sed * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21193326Sed */
22193326Sed
23193326Sed/* \summary: IEEE 802.11 printer */
24193326Sed
25193326Sed#ifdef HAVE_CONFIG_H
26193326Sed#include "config.h"
27193326Sed#endif
28193326Sed
29193326Sed#include <netdissect-stdinc.h>
30193326Sed
31193326Sed#include <string.h>
32193326Sed
33193326Sed#include "netdissect.h"
34193326Sed#include "addrtoname.h"
35193326Sed
36193326Sed#include "extract.h"
37193326Sed
38193326Sed#include "cpack.h"
39193326Sed
40193326Sed
41193326Sed/* Lengths of 802.11 header components. */
42193326Sed#define	IEEE802_11_FC_LEN		2
43193326Sed#define	IEEE802_11_DUR_LEN		2
44193326Sed#define	IEEE802_11_DA_LEN		6
45193326Sed#define	IEEE802_11_SA_LEN		6
46193326Sed#define	IEEE802_11_BSSID_LEN		6
47193326Sed#define	IEEE802_11_RA_LEN		6
48193326Sed#define	IEEE802_11_TA_LEN		6
49193326Sed#define	IEEE802_11_ADDR1_LEN		6
50193326Sed#define	IEEE802_11_SEQ_LEN		2
51193326Sed#define	IEEE802_11_CTL_LEN		2
52193326Sed#define	IEEE802_11_CARRIED_FC_LEN	2
53193326Sed#define	IEEE802_11_HT_CONTROL_LEN	4
54193326Sed#define	IEEE802_11_IV_LEN		3
55193326Sed#define	IEEE802_11_KID_LEN		1
56193326Sed
57193326Sed/* Frame check sequence length. */
58193326Sed#define	IEEE802_11_FCS_LEN		4
59193326Sed
60193326Sed/* Lengths of beacon components. */
61193326Sed#define	IEEE802_11_TSTAMP_LEN		8
62193326Sed#define	IEEE802_11_BCNINT_LEN		2
63193326Sed#define	IEEE802_11_CAPINFO_LEN		2
64193326Sed#define	IEEE802_11_LISTENINT_LEN	2
65193326Sed
66193326Sed#define	IEEE802_11_AID_LEN		2
67193326Sed#define	IEEE802_11_STATUS_LEN		2
68193326Sed#define	IEEE802_11_REASON_LEN		2
69193326Sed
70193326Sed/* Length of previous AP in reassocation frame */
71193326Sed#define	IEEE802_11_AP_LEN		6
72193326Sed
73193326Sed#define	T_MGMT 0x0  /* management */
74193326Sed#define	T_CTRL 0x1  /* control */
75193326Sed#define	T_DATA 0x2 /* data */
76193326Sed#define	T_RESV 0x3  /* reserved */
77193326Sed
78193326Sed#define	ST_ASSOC_REQUEST   	0x0
79193326Sed#define	ST_ASSOC_RESPONSE 	0x1
80193326Sed#define	ST_REASSOC_REQUEST   	0x2
81193326Sed#define	ST_REASSOC_RESPONSE  	0x3
82193326Sed#define	ST_PROBE_REQUEST   	0x4
83193326Sed#define	ST_PROBE_RESPONSE   	0x5
84193326Sed/* RESERVED 			0x6  */
85193326Sed/* RESERVED 			0x7  */
86193326Sed#define	ST_BEACON   		0x8
87193326Sed#define	ST_ATIM			0x9
88193326Sed#define	ST_DISASSOC		0xA
89193326Sed#define	ST_AUTH			0xB
90193326Sed#define	ST_DEAUTH		0xC
91193326Sed#define	ST_ACTION		0xD
92193326Sed/* RESERVED 			0xE  */
93193326Sed/* RESERVED 			0xF  */
94193326Sed
95193326Sedstatic const struct tok st_str[] = {
96193326Sed	{ ST_ASSOC_REQUEST,    "Assoc Request"    },
97193326Sed	{ ST_ASSOC_RESPONSE,   "Assoc Response"   },
98193326Sed	{ ST_REASSOC_REQUEST,  "ReAssoc Request"  },
99193326Sed	{ ST_REASSOC_RESPONSE, "ReAssoc Response" },
100193326Sed	{ ST_PROBE_REQUEST,    "Probe Request"    },
101193326Sed	{ ST_PROBE_RESPONSE,   "Probe Response"   },
102193326Sed	{ ST_BEACON,           "Beacon"           },
103193326Sed	{ ST_ATIM,             "ATIM"             },
104193326Sed	{ ST_DISASSOC,         "Disassociation"   },
105193326Sed	{ ST_AUTH,             "Authentication"   },
106193326Sed	{ ST_DEAUTH,           "DeAuthentication" },
107193326Sed	{ ST_ACTION,           "Action"           },
108193326Sed	{ 0, NULL }
109193326Sed};
110193326Sed
111193326Sed#define CTRL_CONTROL_WRAPPER	0x7
112193326Sed#define	CTRL_BAR	0x8
113193326Sed#define	CTRL_BA		0x9
114193326Sed#define	CTRL_PS_POLL	0xA
115193326Sed#define	CTRL_RTS	0xB
116193326Sed#define	CTRL_CTS	0xC
117193326Sed#define	CTRL_ACK	0xD
118193326Sed#define	CTRL_CF_END	0xE
119193326Sed#define	CTRL_END_ACK	0xF
120193326Sed
121193326Sedstatic const struct tok ctrl_str[] = {
122193326Sed	{ CTRL_CONTROL_WRAPPER, "Control Wrapper" },
123193326Sed	{ CTRL_BAR,             "BAR"             },
124193326Sed	{ CTRL_BA,              "BA"              },
125193326Sed	{ CTRL_PS_POLL,         "Power Save-Poll" },
126193326Sed	{ CTRL_RTS,             "Request-To-Send" },
127193326Sed	{ CTRL_CTS,             "Clear-To-Send"   },
128193326Sed	{ CTRL_ACK,             "Acknowledgment"  },
129193326Sed	{ CTRL_CF_END,          "CF-End"          },
130193326Sed	{ CTRL_END_ACK,         "CF-End+CF-Ack"   },
131193326Sed	{ 0, NULL }
132193326Sed};
133193326Sed
134193326Sed#define	DATA_DATA			0x0
135193326Sed#define	DATA_DATA_CF_ACK		0x1
136193326Sed#define	DATA_DATA_CF_POLL		0x2
137193326Sed#define	DATA_DATA_CF_ACK_POLL		0x3
138193326Sed#define	DATA_NODATA			0x4
139193326Sed#define	DATA_NODATA_CF_ACK		0x5
140193326Sed#define	DATA_NODATA_CF_POLL		0x6
141193326Sed#define	DATA_NODATA_CF_ACK_POLL		0x7
142193326Sed
143194179Sed#define DATA_QOS_DATA			0x8
144194179Sed#define DATA_QOS_DATA_CF_ACK		0x9
145193326Sed#define DATA_QOS_DATA_CF_POLL		0xA
146193326Sed#define DATA_QOS_DATA_CF_ACK_POLL	0xB
147193326Sed#define DATA_QOS_NODATA			0xC
148193326Sed#define DATA_QOS_CF_POLL_NODATA		0xE
149193326Sed#define DATA_QOS_CF_ACK_POLL_NODATA	0xF
150193326Sed
151193326Sed/*
152193326Sed * The subtype field of a data frame is, in effect, composed of 4 flag
153193326Sed * bits - CF-Ack, CF-Poll, Null (means the frame doesn't actually have
154193326Sed * any data), and QoS.
155193326Sed */
156193326Sed#define DATA_FRAME_IS_CF_ACK(x)		((x) & 0x01)
157193326Sed#define DATA_FRAME_IS_CF_POLL(x)	((x) & 0x02)
158193326Sed#define DATA_FRAME_IS_NULL(x)		((x) & 0x04)
159193326Sed#define DATA_FRAME_IS_QOS(x)		((x) & 0x08)
160193326Sed
161193326Sed/*
162193326Sed * Bits in the frame control field.
163193326Sed */
164193326Sed#define	FC_VERSION(fc)		((fc) & 0x3)
165193326Sed#define	FC_TYPE(fc)		(((fc) >> 2) & 0x3)
166194179Sed#define	FC_SUBTYPE(fc)		(((fc) >> 4) & 0xF)
167194179Sed#define	FC_TO_DS(fc)		((fc) & 0x0100)
168193326Sed#define	FC_FROM_DS(fc)		((fc) & 0x0200)
169193326Sed#define	FC_MORE_FLAG(fc)	((fc) & 0x0400)
170193326Sed#define	FC_RETRY(fc)		((fc) & 0x0800)
171193326Sed#define	FC_POWER_MGMT(fc)	((fc) & 0x1000)
172193326Sed#define	FC_MORE_DATA(fc)	((fc) & 0x2000)
173193326Sed#define	FC_PROTECTED(fc)	((fc) & 0x4000)
174193326Sed#define	FC_ORDER(fc)		((fc) & 0x8000)
175193326Sed
176193326Sedstruct mgmt_header_t {
177193326Sed	uint16_t	fc;
178193326Sed	uint16_t 	duration;
179193326Sed	uint8_t		da[IEEE802_11_DA_LEN];
180193326Sed	uint8_t		sa[IEEE802_11_SA_LEN];
181193326Sed	uint8_t		bssid[IEEE802_11_BSSID_LEN];
182193326Sed	uint16_t	seq_ctrl;
183193326Sed};
184193326Sed
185193326Sed#define	MGMT_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
186193326Sed			 IEEE802_11_DA_LEN+IEEE802_11_SA_LEN+\
187193326Sed			 IEEE802_11_BSSID_LEN+IEEE802_11_SEQ_LEN)
188193326Sed
189193326Sed#define	CAPABILITY_ESS(cap)	((cap) & 0x0001)
190194179Sed#define	CAPABILITY_IBSS(cap)	((cap) & 0x0002)
191194179Sed#define	CAPABILITY_CFP(cap)	((cap) & 0x0004)
192194179Sed#define	CAPABILITY_CFP_REQ(cap)	((cap) & 0x0008)
193194179Sed#define	CAPABILITY_PRIVACY(cap)	((cap) & 0x0010)
194194179Sed
195194179Sedstruct ssid_t {
196194179Sed	uint8_t		element_id;
197194179Sed	uint8_t		length;
198193326Sed	u_char		ssid[33];  /* 32 + 1 for null */
199193326Sed};
200193326Sed
201193326Sedstruct rates_t {
202193326Sed	uint8_t		element_id;
203193326Sed	uint8_t		length;
204193326Sed	uint8_t		rate[16];
205193326Sed};
206193326Sed
207193326Sedstruct challenge_t {
208193326Sed	uint8_t		element_id;
209193326Sed	uint8_t		length;
210193326Sed	uint8_t		text[254]; /* 1-253 + 1 for null */
211193326Sed};
212193326Sed
213193326Sedstruct fh_t {
214193326Sed	uint8_t		element_id;
215193326Sed	uint8_t		length;
216193326Sed	uint16_t	dwell_time;
217193326Sed	uint8_t		hop_set;
218193326Sed	uint8_t 	hop_pattern;
219193326Sed	uint8_t		hop_index;
220193326Sed};
221193326Sed
222193326Sedstruct ds_t {
223193326Sed	uint8_t		element_id;
224193326Sed	uint8_t		length;
225193326Sed	uint8_t		channel;
226193326Sed};
227193326Sed
228193326Sedstruct cf_t {
229193326Sed	uint8_t		element_id;
230193326Sed	uint8_t		length;
231193326Sed	uint8_t		count;
232193326Sed	uint8_t		period;
233193326Sed	uint16_t	max_duration;
234193326Sed	uint16_t	dur_remaing;
235193326Sed};
236193326Sed
237193326Sedstruct tim_t {
238193326Sed	uint8_t		element_id;
239193326Sed	uint8_t		length;
240193326Sed	uint8_t		count;
241193326Sed	uint8_t		period;
242193326Sed	uint8_t		bitmap_control;
243193326Sed	uint8_t		bitmap[251];
244193326Sed};
245193326Sed
246193326Sed#define	E_SSID 		0
247193326Sed#define	E_RATES 	1
248193326Sed#define	E_FH	 	2
249193326Sed#define	E_DS 		3
250193326Sed#define	E_CF	 	4
251193326Sed#define	E_TIM	 	5
252193326Sed#define	E_IBSS 		6
253193326Sed/* reserved 		7 */
254193326Sed/* reserved 		8 */
255193326Sed/* reserved 		9 */
256193326Sed/* reserved 		10 */
257193326Sed/* reserved 		11 */
258193326Sed/* reserved 		12 */
259193326Sed/* reserved 		13 */
260193326Sed/* reserved 		14 */
261193326Sed/* reserved 		15 */
262193326Sed/* reserved 		16 */
263193326Sed
264193326Sed#define	E_CHALLENGE 	16
265193326Sed/* reserved 		17 */
266193326Sed/* reserved 		18 */
267193326Sed/* reserved 		19 */
268193326Sed/* reserved 		16 */
269193326Sed/* reserved 		16 */
270193326Sed
271193326Sed
272193326Sedstruct mgmt_body_t {
273193326Sed	uint8_t   	timestamp[IEEE802_11_TSTAMP_LEN];
274193326Sed	uint16_t  	beacon_interval;
275193326Sed	uint16_t 	listen_interval;
276193326Sed	uint16_t 	status_code;
277193326Sed	uint16_t 	aid;
278193326Sed	u_char		ap[IEEE802_11_AP_LEN];
279193326Sed	uint16_t	reason_code;
280193326Sed	uint16_t	auth_alg;
281193326Sed	uint16_t	auth_trans_seq_num;
282193326Sed	int		challenge_present;
283193326Sed	struct challenge_t  challenge;
284193326Sed	uint16_t	capability_info;
285193326Sed	int		ssid_present;
286193326Sed	struct ssid_t	ssid;
287193326Sed	int		rates_present;
288193326Sed	struct rates_t 	rates;
289193326Sed	int		ds_present;
290193326Sed	struct ds_t	ds;
291193326Sed	int		cf_present;
292193326Sed	struct cf_t	cf;
293193326Sed	int		fh_present;
294193326Sed	struct fh_t	fh;
295193326Sed	int		tim_present;
296193326Sed	struct tim_t	tim;
297193326Sed};
298193326Sed
299193326Sedstruct ctrl_control_wrapper_hdr_t {
300193326Sed	uint16_t	fc;
301193326Sed	uint16_t	duration;
302193326Sed	uint8_t		addr1[IEEE802_11_ADDR1_LEN];
303193326Sed	uint16_t	carried_fc[IEEE802_11_CARRIED_FC_LEN];
304193326Sed	uint16_t	ht_control[IEEE802_11_HT_CONTROL_LEN];
305193326Sed};
306193326Sed
307193326Sed#define	CTRL_CONTROL_WRAPPER_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
308193326Sed					 IEEE802_11_ADDR1_LEN+\
309193326Sed					 IEEE802_11_CARRIED_FC_LEN+\
310194179Sed					 IEEE802_11_HT_CONTROL_LEN)
311194179Sed
312194179Sedstruct ctrl_rts_hdr_t {
313193326Sed	uint16_t	fc;
314193326Sed	uint16_t	duration;
315193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
316193326Sed	uint8_t		ta[IEEE802_11_TA_LEN];
317193326Sed};
318193326Sed
319193326Sed#define	CTRL_RTS_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
320193326Sed			 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN)
321193326Sed
322193326Sedstruct ctrl_cts_hdr_t {
323193326Sed	uint16_t	fc;
324193326Sed	uint16_t	duration;
325193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
326193326Sed};
327193326Sed
328193326Sed#define	CTRL_CTS_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
329193326Sed
330193326Sedstruct ctrl_ack_hdr_t {
331193326Sed	uint16_t	fc;
332193326Sed	uint16_t	duration;
333193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
334193326Sed};
335193326Sed
336193326Sed#define	CTRL_ACK_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
337193326Sed
338193326Sedstruct ctrl_ps_poll_hdr_t {
339193326Sed	uint16_t	fc;
340193326Sed	uint16_t	aid;
341193326Sed	uint8_t		bssid[IEEE802_11_BSSID_LEN];
342193326Sed	uint8_t		ta[IEEE802_11_TA_LEN];
343193326Sed};
344193326Sed
345193326Sed#define	CTRL_PS_POLL_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_AID_LEN+\
346193326Sed				 IEEE802_11_BSSID_LEN+IEEE802_11_TA_LEN)
347193326Sed
348193326Sedstruct ctrl_end_hdr_t {
349193326Sed	uint16_t	fc;
350193326Sed	uint16_t	duration;
351193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
352193326Sed	uint8_t		bssid[IEEE802_11_BSSID_LEN];
353193326Sed};
354193326Sed
355193326Sed#define	CTRL_END_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
356193326Sed			 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
357193326Sed
358193326Sedstruct ctrl_end_ack_hdr_t {
359193326Sed	uint16_t	fc;
360193326Sed	uint16_t	duration;
361193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
362193326Sed	uint8_t		bssid[IEEE802_11_BSSID_LEN];
363193326Sed};
364193326Sed
365193326Sed#define	CTRL_END_ACK_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
366193326Sed				 IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN)
367193326Sed
368193326Sedstruct ctrl_ba_hdr_t {
369193326Sed	uint16_t	fc;
370193326Sed	uint16_t	duration;
371193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
372193326Sed};
373193326Sed
374193326Sed#define	CTRL_BA_HDRLEN	(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN)
375193326Sed
376193326Sedstruct ctrl_bar_hdr_t {
377193326Sed	uint16_t	fc;
378193326Sed	uint16_t	dur;
379193326Sed	uint8_t		ra[IEEE802_11_RA_LEN];
380193326Sed	uint8_t		ta[IEEE802_11_TA_LEN];
381193326Sed	uint16_t	ctl;
382193326Sed	uint16_t	seq;
383193326Sed};
384193326Sed
385193326Sed#define	CTRL_BAR_HDRLEN		(IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+\
386193326Sed				 IEEE802_11_RA_LEN+IEEE802_11_TA_LEN+\
387193326Sed				 IEEE802_11_CTL_LEN+IEEE802_11_SEQ_LEN)
388193326Sed
389193326Sedstruct meshcntl_t {
390193326Sed	uint8_t		flags;
391193326Sed	uint8_t		ttl;
392193326Sed	uint8_t		seq[4];
393193326Sed	uint8_t		addr4[6];
394193326Sed	uint8_t		addr5[6];
395193326Sed	uint8_t		addr6[6];
396193326Sed};
397193326Sed
398193326Sed#define	IV_IV(iv)	((iv) & 0xFFFFFF)
399193326Sed#define	IV_PAD(iv)	(((iv) >> 24) & 0x3F)
400193326Sed#define	IV_KEYID(iv)	(((iv) >> 30) & 0x03)
401193326Sed
402193326Sed#define PRINT_SSID(p) \
403193326Sed	if (p.ssid_present) { \
404193326Sed		ND_PRINT((ndo, " (")); \
405193326Sed		fn_print(ndo, p.ssid.ssid, NULL); \
406193326Sed		ND_PRINT((ndo, ")")); \
407193326Sed	}
408193326Sed
409193326Sed#define PRINT_RATE(_sep, _r, _suf) \
410193326Sed	ND_PRINT((ndo, "%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf))
411193326Sed#define PRINT_RATES(p) \
412193326Sed	if (p.rates_present) { \
413193326Sed		int z; \
414193326Sed		const char *sep = " ["; \
415193326Sed		for (z = 0; z < p.rates.length ; z++) { \
416193326Sed			PRINT_RATE(sep, p.rates.rate[z], \
417193326Sed				(p.rates.rate[z] & 0x80 ? "*" : "")); \
418193326Sed			sep = " "; \
419193326Sed		} \
420193326Sed		if (p.rates.length != 0) \
421193326Sed			ND_PRINT((ndo, " Mbit]")); \
422193326Sed	}
423193326Sed
424193326Sed#define PRINT_DS_CHANNEL(p) \
425193326Sed	if (p.ds_present) \
426193326Sed		ND_PRINT((ndo, " CH: %u", p.ds.channel)); \
427193326Sed	ND_PRINT((ndo, "%s", \
428193326Sed	    CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : ""));
429193326Sed
430193326Sed#define MAX_MCS_INDEX	76
431193326Sed
432193326Sed/*
433193326Sed * Indices are:
434193326Sed *
435193326Sed *	the MCS index (0-76);
436193326Sed *
437193326Sed *	0 for 20 MHz, 1 for 40 MHz;
438193326Sed *
439193326Sed *	0 for a long guard interval, 1 for a short guard interval.
440193326Sed */
441193326Sedstatic const float ieee80211_float_htrates[MAX_MCS_INDEX+1][2][2] = {
442193326Sed	/* MCS  0  */
443193326Sed	{	/* 20 Mhz */ {    6.5,		/* SGI */    7.2, },
444193326Sed		/* 40 Mhz */ {   13.5,		/* SGI */   15.0, },
445193326Sed	},
446193326Sed
447194613Sed	/* MCS  1  */
448194613Sed	{	/* 20 Mhz */ {   13.0,		/* SGI */   14.4, },
449194613Sed		/* 40 Mhz */ {   27.0,		/* SGI */   30.0, },
450193326Sed	},
451193326Sed
452193326Sed	/* MCS  2  */
453193326Sed	{	/* 20 Mhz */ {   19.5,		/* SGI */   21.7, },
454193326Sed		/* 40 Mhz */ {   40.5,		/* SGI */   45.0, },
455193326Sed	},
456193326Sed
457193326Sed	/* MCS  3  */
458193326Sed	{	/* 20 Mhz */ {   26.0,		/* SGI */   28.9, },
459193326Sed		/* 40 Mhz */ {   54.0,		/* SGI */   60.0, },
460193326Sed	},
461193326Sed
462193326Sed	/* MCS  4  */
463193326Sed	{	/* 20 Mhz */ {   39.0,		/* SGI */   43.3, },
464193326Sed		/* 40 Mhz */ {   81.0,		/* SGI */   90.0, },
465193326Sed	},
466193326Sed
467193326Sed	/* MCS  5  */
468193326Sed	{	/* 20 Mhz */ {   52.0,		/* SGI */   57.8, },
469193326Sed		/* 40 Mhz */ {  108.0,		/* SGI */  120.0, },
470193326Sed	},
471193326Sed
472193326Sed	/* MCS  6  */
473193326Sed	{	/* 20 Mhz */ {   58.5,		/* SGI */   65.0, },
474193326Sed		/* 40 Mhz */ {  121.5,		/* SGI */  135.0, },
475193326Sed	},
476193326Sed
477193326Sed	/* MCS  7  */
478193326Sed	{	/* 20 Mhz */ {   65.0,		/* SGI */   72.2, },
479193326Sed		/* 40 Mhz */ {   135.0,		/* SGI */  150.0, },
480193326Sed	},
481193326Sed
482193326Sed	/* MCS  8  */
483193326Sed	{	/* 20 Mhz */ {   13.0,		/* SGI */   14.4, },
484193326Sed		/* 40 Mhz */ {   27.0,		/* SGI */   30.0, },
485193326Sed	},
486193326Sed
487193326Sed	/* MCS  9  */
488193326Sed	{	/* 20 Mhz */ {   26.0,		/* SGI */   28.9, },
489193326Sed		/* 40 Mhz */ {   54.0,		/* SGI */   60.0, },
490193326Sed	},
491193326Sed
492193326Sed	/* MCS 10  */
493193326Sed	{	/* 20 Mhz */ {   39.0,		/* SGI */   43.3, },
494193326Sed		/* 40 Mhz */ {   81.0,		/* SGI */   90.0, },
495193326Sed	},
496193326Sed
497193326Sed	/* MCS 11  */
498193326Sed	{	/* 20 Mhz */ {   52.0,		/* SGI */   57.8, },
499193326Sed		/* 40 Mhz */ {  108.0,		/* SGI */  120.0, },
500193326Sed	},
501193326Sed
502193326Sed	/* MCS 12  */
503193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
504193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
505193326Sed	},
506193326Sed
507193326Sed	/* MCS 13  */
508193326Sed	{	/* 20 Mhz */ {  104.0,		/* SGI */  115.6, },
509193326Sed		/* 40 Mhz */ {  216.0,		/* SGI */  240.0, },
510193326Sed	},
511193326Sed
512193326Sed	/* MCS 14  */
513193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
514193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
515193326Sed	},
516193326Sed
517193326Sed	/* MCS 15  */
518193326Sed	{	/* 20 Mhz */ {  130.0,		/* SGI */  144.4, },
519193326Sed		/* 40 Mhz */ {  270.0,		/* SGI */  300.0, },
520193326Sed	},
521193326Sed
522193326Sed	/* MCS 16  */
523193326Sed	{	/* 20 Mhz */ {   19.5,		/* SGI */   21.7, },
524193326Sed		/* 40 Mhz */ {   40.5,		/* SGI */   45.0, },
525193326Sed	},
526193326Sed
527193326Sed	/* MCS 17  */
528193326Sed	{	/* 20 Mhz */ {   39.0,		/* SGI */   43.3, },
529193326Sed		/* 40 Mhz */ {   81.0,		/* SGI */   90.0, },
530193326Sed	},
531193326Sed
532193326Sed	/* MCS 18  */
533193326Sed	{	/* 20 Mhz */ {   58.5,		/* SGI */   65.0, },
534193326Sed		/* 40 Mhz */ {  121.5,		/* SGI */  135.0, },
535193326Sed	},
536193326Sed
537193326Sed	/* MCS 19  */
538193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
539193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
540193326Sed	},
541193326Sed
542193326Sed	/* MCS 20  */
543193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
544193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
545193326Sed	},
546193326Sed
547193326Sed	/* MCS 21  */
548193326Sed	{	/* 20 Mhz */ {  156.0,		/* SGI */  173.3, },
549193326Sed		/* 40 Mhz */ {  324.0,		/* SGI */  360.0, },
550193326Sed	},
551193326Sed
552193326Sed	/* MCS 22  */
553193326Sed	{	/* 20 Mhz */ {  175.5,		/* SGI */  195.0, },
554194613Sed		/* 40 Mhz */ {  364.5,		/* SGI */  405.0, },
555193326Sed	},
556193326Sed
557193326Sed	/* MCS 23  */
558193326Sed	{	/* 20 Mhz */ {  195.0,		/* SGI */  216.7, },
559193326Sed		/* 40 Mhz */ {  405.0,		/* SGI */  450.0, },
560193326Sed	},
561193326Sed
562193326Sed	/* MCS 24  */
563193326Sed	{	/* 20 Mhz */ {   26.0,		/* SGI */   28.9, },
564193326Sed		/* 40 Mhz */ {   54.0,		/* SGI */   60.0, },
565193326Sed	},
566193326Sed
567193326Sed	/* MCS 25  */
568193326Sed	{	/* 20 Mhz */ {   52.0,		/* SGI */   57.8, },
569193326Sed		/* 40 Mhz */ {  108.0,		/* SGI */  120.0, },
570193326Sed	},
571193326Sed
572193326Sed	/* MCS 26  */
573193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
574193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
575193326Sed	},
576193326Sed
577193326Sed	/* MCS 27  */
578193326Sed	{	/* 20 Mhz */ {  104.0,		/* SGI */  115.6, },
579193326Sed		/* 40 Mhz */ {  216.0,		/* SGI */  240.0, },
580193326Sed	},
581193326Sed
582193326Sed	/* MCS 28  */
583193326Sed	{	/* 20 Mhz */ {  156.0,		/* SGI */  173.3, },
584193326Sed		/* 40 Mhz */ {  324.0,		/* SGI */  360.0, },
585193326Sed	},
586193326Sed
587193326Sed	/* MCS 29  */
588193326Sed	{	/* 20 Mhz */ {  208.0,		/* SGI */  231.1, },
589193326Sed		/* 40 Mhz */ {  432.0,		/* SGI */  480.0, },
590193326Sed	},
591193326Sed
592193326Sed	/* MCS 30  */
593193326Sed	{	/* 20 Mhz */ {  234.0,		/* SGI */  260.0, },
594193326Sed		/* 40 Mhz */ {  486.0,		/* SGI */  540.0, },
595193326Sed	},
596193326Sed
597194179Sed	/* MCS 31  */
598194179Sed	{	/* 20 Mhz */ {  260.0,		/* SGI */  288.9, },
599194179Sed		/* 40 Mhz */ {  540.0,		/* SGI */  600.0, },
600193326Sed	},
601193326Sed
602193326Sed	/* MCS 32  */
603193326Sed	{	/* 20 Mhz */ {    0.0,		/* SGI */    0.0, }, /* not valid */
604193326Sed		/* 40 Mhz */ {    6.0,		/* SGI */    6.7, },
605193326Sed	},
606193326Sed
607193326Sed	/* MCS 33  */
608193326Sed	{	/* 20 Mhz */ {   39.0,		/* SGI */   43.3, },
609193326Sed		/* 40 Mhz */ {   81.0,		/* SGI */   90.0, },
610193326Sed	},
611193326Sed
612193326Sed	/* MCS 34  */
613193326Sed	{	/* 20 Mhz */ {   52.0,		/* SGI */   57.8, },
614193326Sed		/* 40 Mhz */ {  108.0,		/* SGI */  120.0, },
615193326Sed	},
616194179Sed
617194179Sed	/* MCS 35  */
618194179Sed	{	/* 20 Mhz */ {   65.0,		/* SGI */   72.2, },
619194179Sed		/* 40 Mhz */ {  135.0,		/* SGI */  150.0, },
620194179Sed	},
621194179Sed
622194179Sed	/* MCS 36  */
623194179Sed	{	/* 20 Mhz */ {   58.5,		/* SGI */   65.0, },
624194179Sed		/* 40 Mhz */ {  121.5,		/* SGI */  135.0, },
625193326Sed	},
626193326Sed
627193326Sed	/* MCS 37  */
628193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
629193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
630193326Sed	},
631194179Sed
632194179Sed	/* MCS 38  */
633194179Sed	{	/* 20 Mhz */ {   97.5,		/* SGI */  108.3, },
634194179Sed		/* 40 Mhz */ {  202.5,		/* SGI */  225.0, },
635194179Sed	},
636194179Sed
637193326Sed	/* MCS 39  */
638193326Sed	{	/* 20 Mhz */ {   52.0,		/* SGI */   57.8, },
639193326Sed		/* 40 Mhz */ {  108.0,		/* SGI */  120.0, },
640193326Sed	},
641193326Sed
642193326Sed	/* MCS 40  */
643193326Sed	{	/* 20 Mhz */ {   65.0,		/* SGI */   72.2, },
644193326Sed		/* 40 Mhz */ {  135.0,		/* SGI */  150.0, },
645193326Sed	},
646193326Sed
647193326Sed	/* MCS 41  */
648193326Sed	{	/* 20 Mhz */ {   65.0,		/* SGI */   72.2, },
649193326Sed		/* 40 Mhz */ {  135.0,		/* SGI */  150.0, },
650193326Sed	},
651193326Sed
652193326Sed	/* MCS 42  */
653193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
654193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
655193326Sed	},
656193326Sed
657193326Sed	/* MCS 43  */
658193326Sed	{	/* 20 Mhz */ {   91.0,		/* SGI */  101.1, },
659193326Sed		/* 40 Mhz */ {  189.0,		/* SGI */  210.0, },
660193326Sed	},
661193326Sed
662193326Sed	/* MCS 44  */
663193326Sed	{	/* 20 Mhz */ {   91.0,		/* SGI */  101.1, },
664193326Sed		/* 40 Mhz */ {  189.0,		/* SGI */  210.0, },
665193326Sed	},
666193326Sed
667193326Sed	/* MCS 45  */
668193326Sed	{	/* 20 Mhz */ {  104.0,		/* SGI */  115.6, },
669193326Sed		/* 40 Mhz */ {  216.0,		/* SGI */  240.0, },
670193326Sed	},
671193326Sed
672193326Sed	/* MCS 46  */
673193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
674193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
675193326Sed	},
676193326Sed
677193326Sed	/* MCS 47  */
678193326Sed	{	/* 20 Mhz */ {   97.5,		/* SGI */  108.3, },
679193326Sed		/* 40 Mhz */ {  202.5,		/* SGI */  225.0, },
680193326Sed	},
681193326Sed
682193326Sed	/* MCS 48  */
683193326Sed	{	/* 20 Mhz */ {   97.5,		/* SGI */  108.3, },
684193326Sed		/* 40 Mhz */ {  202.5,		/* SGI */  225.0, },
685193326Sed	},
686193326Sed
687193326Sed	/* MCS 49  */
688193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
689193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
690193326Sed	},
691193326Sed
692193326Sed	/* MCS 50  */
693193326Sed	{	/* 20 Mhz */ {  136.5,		/* SGI */  151.7, },
694193326Sed		/* 40 Mhz */ {  283.5,		/* SGI */  315.0, },
695193326Sed	},
696193326Sed
697193326Sed	/* MCS 51  */
698193326Sed	{	/* 20 Mhz */ {  136.5,		/* SGI */  151.7, },
699193326Sed		/* 40 Mhz */ {  283.5,		/* SGI */  315.0, },
700193326Sed	},
701193326Sed
702193326Sed	/* MCS 52  */
703193326Sed	{	/* 20 Mhz */ {  156.0,		/* SGI */  173.3, },
704193326Sed		/* 40 Mhz */ {  324.0,		/* SGI */  360.0, },
705193326Sed	},
706193326Sed
707193326Sed	/* MCS 53  */
708193326Sed	{	/* 20 Mhz */ {   65.0,		/* SGI */   72.2, },
709193326Sed		/* 40 Mhz */ {  135.0,		/* SGI */  150.0, },
710193326Sed	},
711193326Sed
712193326Sed	/* MCS 54  */
713193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
714193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
715193326Sed	},
716193326Sed
717193326Sed	/* MCS 55  */
718193326Sed	{	/* 20 Mhz */ {   91.0,		/* SGI */  101.1, },
719193326Sed		/* 40 Mhz */ {  189.0,		/* SGI */  210.0, },
720193326Sed	},
721193326Sed
722193326Sed	/* MCS 56  */
723193326Sed	{	/* 20 Mhz */ {   78.0,		/* SGI */   86.7, },
724193326Sed		/* 40 Mhz */ {  162.0,		/* SGI */  180.0, },
725193326Sed	},
726193326Sed
727193326Sed	/* MCS 57  */
728193326Sed	{	/* 20 Mhz */ {   91.0,		/* SGI */  101.1, },
729193326Sed		/* 40 Mhz */ {  189.0,		/* SGI */  210.0, },
730193326Sed	},
731193326Sed
732193326Sed	/* MCS 58  */
733193326Sed	{	/* 20 Mhz */ {  104.0,		/* SGI */  115.6, },
734193326Sed		/* 40 Mhz */ {  216.0,		/* SGI */  240.0, },
735193326Sed	},
736193326Sed
737193326Sed	/* MCS 59  */
738193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
739193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
740193326Sed	},
741193326Sed
742193326Sed	/* MCS 60  */
743193326Sed	{	/* 20 Mhz */ {  104.0,		/* SGI */  115.6, },
744193326Sed		/* 40 Mhz */ {  216.0,		/* SGI */  240.0, },
745193326Sed	},
746193326Sed
747193326Sed	/* MCS 61  */
748193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
749193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
750193326Sed	},
751193326Sed
752193326Sed	/* MCS 62  */
753193326Sed	{	/* 20 Mhz */ {  130.0,		/* SGI */  144.4, },
754193326Sed		/* 40 Mhz */ {  270.0,		/* SGI */  300.0, },
755193326Sed	},
756193326Sed
757193326Sed	/* MCS 63  */
758193326Sed	{	/* 20 Mhz */ {  130.0,		/* SGI */  144.4, },
759193326Sed		/* 40 Mhz */ {  270.0,		/* SGI */  300.0, },
760193326Sed	},
761193326Sed
762193326Sed	/* MCS 64  */
763193326Sed	{	/* 20 Mhz */ {  143.0,		/* SGI */  158.9, },
764193326Sed		/* 40 Mhz */ {  297.0,		/* SGI */  330.0, },
765193326Sed	},
766193326Sed
767193326Sed	/* MCS 65  */
768193326Sed	{	/* 20 Mhz */ {   97.5,		/* SGI */  108.3, },
769193326Sed		/* 40 Mhz */ {  202.5,		/* SGI */  225.0, },
770193326Sed	},
771193326Sed
772193326Sed	/* MCS 66  */
773193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
774193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
775193326Sed	},
776193326Sed
777193326Sed	/* MCS 67  */
778193326Sed	{	/* 20 Mhz */ {  136.5,		/* SGI */  151.7, },
779193326Sed		/* 40 Mhz */ {  283.5,		/* SGI */  315.0, },
780193326Sed	},
781193326Sed
782193326Sed	/* MCS 68  */
783193326Sed	{	/* 20 Mhz */ {  117.0,		/* SGI */  130.0, },
784193326Sed		/* 40 Mhz */ {  243.0,		/* SGI */  270.0, },
785193576Sed	},
786193576Sed
787193576Sed	/* MCS 69  */
788193576Sed	{	/* 20 Mhz */ {  136.5,		/* SGI */  151.7, },
789193326Sed		/* 40 Mhz */ {  283.5,		/* SGI */  315.0, },
790193326Sed	},
791193326Sed
792193326Sed	/* MCS 70  */
793193326Sed	{	/* 20 Mhz */ {  156.0,		/* SGI */  173.3, },
794193326Sed		/* 40 Mhz */ {  324.0,		/* SGI */  360.0, },
795193326Sed	},
796193326Sed
797193326Sed	/* MCS 71  */
798193326Sed	{	/* 20 Mhz */ {  175.5,		/* SGI */  195.0, },
799193326Sed		/* 40 Mhz */ {  364.5,		/* SGI */  405.0, },
800193326Sed	},
801193326Sed
802193326Sed	/* MCS 72  */
803193326Sed	{	/* 20 Mhz */ {  156.0,		/* SGI */  173.3, },
804193576Sed		/* 40 Mhz */ {  324.0,		/* SGI */  360.0, },
805193326Sed	},
806193326Sed
807193326Sed	/* MCS 73  */
808193326Sed	{	/* 20 Mhz */ {  175.5,		/* SGI */  195.0, },
809193326Sed		/* 40 Mhz */ {  364.5,		/* SGI */  405.0, },
810193576Sed	},
811193326Sed
812194613Sed	/* MCS 74  */
813194613Sed	{	/* 20 Mhz */ {  195.0,		/* SGI */  216.7, },
814194613Sed		/* 40 Mhz */ {  405.0,		/* SGI */  450.0, },
815194613Sed	},
816193326Sed
817193326Sed	/* MCS 75  */
818193326Sed	{	/* 20 Mhz */ {  195.0,		/* SGI */  216.7, },
819193326Sed		/* 40 Mhz */ {  405.0,		/* SGI */  450.0, },
820193326Sed	},
821193326Sed
822193326Sed	/* MCS 76  */
823193326Sed	{	/* 20 Mhz */ {  214.5,		/* SGI */  238.3, },
824193326Sed		/* 40 Mhz */ {  445.5,		/* SGI */  495.0, },
825193326Sed	},
826193326Sed};
827193326Sed
828193326Sedstatic const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
829193326Sed#define NUM_AUTH_ALGS	(sizeof auth_alg_text / sizeof auth_alg_text[0])
830193326Sed
831193326Sedstatic const char *status_text[] = {
832193326Sed	"Successful",						/*  0 */
833193326Sed	"Unspecified failure",					/*  1 */
834193326Sed	"Reserved",						/*  2 */
835193326Sed	"Reserved",						/*  3 */
836193326Sed	"Reserved",						/*  4 */
837193326Sed	"Reserved",						/*  5 */
838193326Sed	"Reserved",						/*  6 */
839193326Sed	"Reserved",						/*  7 */
840193326Sed	"Reserved",						/*  8 */
841193326Sed	"Reserved",						/*  9 */
842193326Sed	"Cannot Support all requested capabilities in the Capability "
843193326Sed	  "Information field",	  				/* 10 */
844193326Sed	"Reassociation denied due to inability to confirm that association "
845193326Sed	  "exists",						/* 11 */
846193326Sed	"Association denied due to reason outside the scope of the "
847193326Sed	  "standard",						/* 12 */
848193326Sed	"Responding station does not support the specified authentication "
849193326Sed	  "algorithm ",						/* 13 */
850193576Sed	"Received an Authentication frame with authentication transaction "
851193326Sed	  "sequence number out of expected sequence",		/* 14 */
852193326Sed	"Authentication rejected because of challenge failure",	/* 15 */
853193326Sed	"Authentication rejected due to timeout waiting for next frame in "
854193326Sed	  "sequence",	  					/* 16 */
855193326Sed	"Association denied because AP is unable to handle additional"
856194613Sed	  "associated stations",	  			/* 17 */
857193326Sed	"Association denied due to requesting station not supporting all of "
858193326Sed	  "the data rates in BSSBasicRateSet parameter",	/* 18 */
859193326Sed	"Association denied due to requesting station not supporting "
860193326Sed	  "short preamble operation",				/* 19 */
861193326Sed	"Association denied due to requesting station not supporting "
862193326Sed	  "PBCC encoding",					/* 20 */
863193326Sed	"Association denied due to requesting station not supporting "
864193326Sed	  "channel agility",					/* 21 */
865193326Sed	"Association request rejected because Spectrum Management "
866193326Sed	  "capability is required",				/* 22 */
867193326Sed	"Association request rejected because the information in the "
868193326Sed	  "Power Capability element is unacceptable",		/* 23 */
869193326Sed	"Association request rejected because the information in the "
870193326Sed	  "Supported Channels element is unacceptable",		/* 24 */
871193326Sed	"Association denied due to requesting station not supporting "
872193326Sed	  "short slot operation",				/* 25 */
873193326Sed	"Association denied due to requesting station not supporting "
874193576Sed	  "DSSS-OFDM operation",				/* 26 */
875193576Sed	"Association denied because the requested STA does not support HT "
876193326Sed	  "features",						/* 27 */
877193326Sed	"Reserved",						/* 28 */
878193326Sed	"Association denied because the requested STA does not support "
879193326Sed	  "the PCO transition time required by the AP",		/* 29 */
880193326Sed	"Reserved",						/* 30 */
881193576Sed	"Reserved",						/* 31 */
882193576Sed	"Unspecified, QoS-related failure",			/* 32 */
883193576Sed	"Association denied due to QAP having insufficient bandwidth "
884193326Sed	  "to handle another QSTA",				/* 33 */
885193326Sed	"Association denied due to excessive frame loss rates and/or "
886193326Sed	  "poor conditions on current operating channel",	/* 34 */
887193326Sed	"Association (with QBSS) denied due to requesting station not "
888193326Sed	  "supporting the QoS facility",			/* 35 */
889193326Sed	"Association denied due to requesting station not supporting "
890193326Sed	  "Block Ack",						/* 36 */
891193326Sed	"The request has been declined",			/* 37 */
892193576Sed	"The request has not been successful as one or more parameters "
893193576Sed	  "have invalid values",				/* 38 */
894193576Sed	"The TS has not been created because the request cannot be honored. "
895193576Sed	  "Try again with the suggested changes to the TSPEC",	/* 39 */
896193326Sed	"Invalid Information Element",				/* 40 */
897193326Sed	"Group Cipher is not valid",				/* 41 */
898193326Sed	"Pairwise Cipher is not valid",				/* 42 */
899193326Sed	"AKMP is not valid",					/* 43 */
900193326Sed	"Unsupported RSN IE version",				/* 44 */
901193326Sed	"Invalid RSN IE Capabilities",				/* 45 */
902193326Sed	"Cipher suite is rejected per security policy",		/* 46 */
903193326Sed	"The TS has not been created. However, the HC may be capable of "
904193326Sed	  "creating a TS, in response to a request, after the time indicated "
905193326Sed	  "in the TS Delay element",				/* 47 */
906193326Sed	"Direct Link is not allowed in the BSS by policy",	/* 48 */
907193326Sed	"Destination STA is not present within this QBSS.",	/* 49 */
908193326Sed	"The Destination STA is not a QSTA.",			/* 50 */
909193326Sed
910193326Sed};
911193326Sed#define NUM_STATUSES	(sizeof status_text / sizeof status_text[0])
912193326Sed
913193326Sedstatic const char *reason_text[] = {
914193326Sed	"Reserved",						/* 0 */
915193326Sed	"Unspecified reason",					/* 1 */
916193326Sed	"Previous authentication no longer valid",  		/* 2 */
917193326Sed	"Deauthenticated because sending station is leaving (or has left) "
918193326Sed	  "IBSS or ESS",					/* 3 */
919193326Sed	"Disassociated due to inactivity",			/* 4 */
920193326Sed	"Disassociated because AP is unable to handle all currently "
921193326Sed	  " associated stations",				/* 5 */
922193326Sed	"Class 2 frame received from nonauthenticated station", /* 6 */
923193326Sed	"Class 3 frame received from nonassociated station",	/* 7 */
924193326Sed	"Disassociated because sending station is leaving "
925193326Sed	  "(or has left) BSS",					/* 8 */
926193326Sed	"Station requesting (re)association is not authenticated with "
927193326Sed	  "responding station",					/* 9 */
928193326Sed	"Disassociated because the information in the Power Capability "
929193326Sed	  "element is unacceptable",				/* 10 */
930193326Sed	"Disassociated because the information in the SupportedChannels "
931193326Sed	  "element is unacceptable",				/* 11 */
932193326Sed	"Invalid Information Element",				/* 12 */
933193326Sed	"Reserved",						/* 13 */
934193326Sed	"Michael MIC failure",					/* 14 */
935193326Sed	"4-Way Handshake timeout",				/* 15 */
936193326Sed	"Group key update timeout",				/* 16 */
937193326Sed	"Information element in 4-Way Handshake different from (Re)Association"
938193326Sed	  "Request/Probe Response/Beacon",			/* 17 */
939193326Sed	"Group Cipher is not valid",				/* 18 */
940193326Sed	"AKMP is not valid",					/* 20 */
941193326Sed	"Unsupported RSN IE version",				/* 21 */
942193326Sed	"Invalid RSN IE Capabilities",				/* 22 */
943193326Sed	"IEEE 802.1X Authentication failed",			/* 23 */
944193326Sed	"Cipher suite is rejected per security policy",		/* 24 */
945193326Sed	"Reserved",						/* 25 */
946193326Sed	"Reserved",						/* 26 */
947193326Sed	"Reserved",						/* 27 */
948193326Sed	"Reserved",						/* 28 */
949193326Sed	"Reserved",						/* 29 */
950193326Sed	"Reserved",						/* 30 */
951193326Sed	"TS deleted because QoS AP lacks sufficient bandwidth for this "
952193326Sed	  "QoS STA due to a change in BSS service characteristics or "
953193326Sed	  "operational mode (e.g. an HT BSS change from 40 MHz channel "
954193326Sed	  "to 20 MHz channel)",					/* 31 */
955193326Sed	"Disassociated for unspecified, QoS-related reason",	/* 32 */
956193326Sed	"Disassociated because QoS AP lacks sufficient bandwidth for this "
957193326Sed	  "QoS STA",						/* 33 */
958193326Sed	"Disassociated because of excessive number of frames that need to be "
959193326Sed          "acknowledged, but are not acknowledged for AP transmissions "
960193326Sed	  "and/or poor channel conditions",			/* 34 */
961193326Sed	"Disassociated because STA is transmitting outside the limits "
962193326Sed	  "of its TXOPs",					/* 35 */
963193326Sed	"Requested from peer STA as the STA is leaving the BSS "
964193326Sed	  "(or resetting)",					/* 36 */
965193326Sed	"Requested from peer STA as it does not want to use the "
966193326Sed	  "mechanism",						/* 37 */
967193326Sed	"Requested from peer STA as the STA received frames using the "
968193326Sed	  "mechanism for which a set up is required",		/* 38 */
969193326Sed	"Requested from peer STA due to time out",		/* 39 */
970193326Sed	"Reserved",						/* 40 */
971193326Sed	"Reserved",						/* 41 */
972193326Sed	"Reserved",						/* 42 */
973193326Sed	"Reserved",						/* 43 */
974193326Sed	"Reserved",						/* 44 */
975193326Sed	"Peer STA does not support the requested cipher suite",	/* 45 */
976193326Sed	"Association denied due to requesting STA not supporting HT "
977193326Sed	  "features",						/* 46 */
978193326Sed};
979193326Sed#define NUM_REASONS	(sizeof reason_text / sizeof reason_text[0])
980193326Sed
981193326Sedstatic int
982193326Sedwep_print(netdissect_options *ndo,
983193326Sed          const u_char *p)
984193326Sed{
985194179Sed	uint32_t iv;
986194179Sed
987194179Sed	if (!ND_TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN))
988194179Sed		return 0;
989194179Sed	iv = EXTRACT_LE_32BITS(p);
990194179Sed
991194179Sed	ND_PRINT((ndo, " IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
992194179Sed	    IV_KEYID(iv)));
993194179Sed
994194179Sed	return 1;
995194179Sed}
996194179Sed
997194179Sedstatic int
998194179Sedparse_elements(netdissect_options *ndo,
999194179Sed               struct mgmt_body_t *pbody, const u_char *p, int offset,
1000194179Sed               u_int length)
1001194179Sed{
1002194179Sed	u_int elementlen;
1003194179Sed	struct ssid_t ssid;
1004194179Sed	struct challenge_t challenge;
1005194179Sed	struct rates_t rates;
1006194179Sed	struct ds_t ds;
1007194179Sed	struct cf_t cf;
1008194179Sed	struct tim_t tim;
1009194179Sed
1010194179Sed	/*
1011194179Sed	 * We haven't seen any elements yet.
1012193326Sed	 */
1013193326Sed	pbody->challenge_present = 0;
1014193326Sed	pbody->ssid_present = 0;
1015193326Sed	pbody->rates_present = 0;
1016193326Sed	pbody->ds_present = 0;
1017193326Sed	pbody->cf_present = 0;
1018193326Sed	pbody->tim_present = 0;
1019193326Sed
1020193576Sed	while (length != 0) {
1021193326Sed		/* Make sure we at least have the element ID and length. */
1022193326Sed		if (!ND_TTEST2(*(p + offset), 2))
1023193326Sed			return 0;
1024193326Sed		if (length < 2)
1025193326Sed			return 0;
1026194179Sed		elementlen = *(p + offset + 1);
1027194179Sed
1028194179Sed		/* Make sure we have the entire element. */
1029194179Sed		if (!ND_TTEST2(*(p + offset + 2), elementlen))
1030193326Sed			return 0;
1031193326Sed		if (length < elementlen + 2)
1032193326Sed			return 0;
1033193326Sed
1034193326Sed		switch (*(p + offset)) {
1035193326Sed		case E_SSID:
1036193326Sed			memcpy(&ssid, p + offset, 2);
1037193326Sed			offset += 2;
1038193326Sed			length -= 2;
1039193326Sed			if (ssid.length != 0) {
1040193326Sed				if (ssid.length > sizeof(ssid.ssid) - 1)
1041193326Sed					return 0;
1042193326Sed				memcpy(&ssid.ssid, p + offset, ssid.length);
1043193326Sed				offset += ssid.length;
1044193326Sed				length -= ssid.length;
1045193326Sed			}
1046193326Sed			ssid.ssid[ssid.length] = '\0';
1047193326Sed			/*
1048193326Sed			 * Present and not truncated.
1049193326Sed			 *
1050193326Sed			 * If we haven't already seen an SSID IE,
1051193326Sed			 * copy this one, otherwise ignore this one,
1052193326Sed			 * so we later report the first one we saw.
1053193326Sed			 */
1054193326Sed			if (!pbody->ssid_present) {
1055193326Sed				pbody->ssid = ssid;
1056193326Sed				pbody->ssid_present = 1;
1057193326Sed			}
1058193326Sed			break;
1059193326Sed		case E_CHALLENGE:
1060193326Sed			memcpy(&challenge, p + offset, 2);
1061193326Sed			offset += 2;
1062193326Sed			length -= 2;
1063194179Sed			if (challenge.length != 0) {
1064194179Sed				if (challenge.length >
1065194179Sed				    sizeof(challenge.text) - 1)
1066194179Sed					return 0;
1067194179Sed				memcpy(&challenge.text, p + offset,
1068194179Sed				    challenge.length);
1069194179Sed				offset += challenge.length;
1070193326Sed				length -= challenge.length;
1071193326Sed			}
1072193326Sed			challenge.text[challenge.length] = '\0';
1073193326Sed			/*
1074193326Sed			 * Present and not truncated.
1075193326Sed			 *
1076193326Sed			 * If we haven't already seen a challenge IE,
1077193326Sed			 * copy this one, otherwise ignore this one,
1078193326Sed			 * so we later report the first one we saw.
1079193576Sed			 */
1080193576Sed			if (!pbody->challenge_present) {
1081193326Sed				pbody->challenge = challenge;
1082193326Sed				pbody->challenge_present = 1;
1083193576Sed			}
1084193576Sed			break;
1085193576Sed		case E_RATES:
1086193326Sed			memcpy(&rates, p + offset, 2);
1087193326Sed			offset += 2;
1088193326Sed			length -= 2;
1089193326Sed			if (rates.length != 0) {
1090193326Sed				if (rates.length > sizeof rates.rate)
1091193326Sed					return 0;
1092193326Sed				memcpy(&rates.rate, p + offset, rates.length);
1093193326Sed				offset += rates.length;
1094193326Sed				length -= rates.length;
1095193326Sed			}
1096193326Sed			/*
1097193326Sed			 * Present and not truncated.
1098193326Sed			 *
1099193326Sed			 * If we haven't already seen a rates IE,
1100194179Sed			 * copy this one if it's not zero-length,
1101194179Sed			 * otherwise ignore this one, so we later
1102194179Sed			 * report the first one we saw.
1103194179Sed			 *
1104194179Sed			 * We ignore zero-length rates IEs as some
1105194179Sed			 * devices seem to put a zero-length rates
1106194179Sed			 * IE, followed by an SSID IE, followed by
1107194179Sed			 * a non-zero-length rates IE into frames,
1108194179Sed			 * even though IEEE Std 802.11-2007 doesn't
1109194179Sed			 * seem to indicate that a zero-length rates
1110194179Sed			 * IE is valid.
1111194179Sed			 */
1112194179Sed			if (!pbody->rates_present && rates.length != 0) {
1113194179Sed				pbody->rates = rates;
1114194179Sed				pbody->rates_present = 1;
1115193326Sed			}
1116193326Sed			break;
1117193326Sed		case E_DS:
1118193326Sed			memcpy(&ds, p + offset, 2);
1119193326Sed			offset += 2;
1120193326Sed			length -= 2;
1121193326Sed			if (ds.length != 1) {
1122193326Sed				offset += ds.length;
1123193326Sed				length -= ds.length;
1124193326Sed				break;
1125193326Sed			}
1126193326Sed			ds.channel = *(p + offset);
1127193326Sed			offset += 1;
1128193326Sed			length -= 1;
1129193326Sed			/*
1130193326Sed			 * Present and not truncated.
1131193326Sed			 *
1132194179Sed			 * If we haven't already seen a DS IE,
1133194179Sed			 * copy this one, otherwise ignore this one,
1134194179Sed			 * so we later report the first one we saw.
1135194179Sed			 */
1136194179Sed			if (!pbody->ds_present) {
1137194179Sed				pbody->ds = ds;
1138194179Sed				pbody->ds_present = 1;
1139194179Sed			}
1140194179Sed			break;
1141194179Sed		case E_CF:
1142194179Sed			memcpy(&cf, p + offset, 2);
1143193326Sed			offset += 2;
1144193326Sed			length -= 2;
1145193326Sed			if (cf.length != 6) {
1146193326Sed				offset += cf.length;
1147193326Sed				length -= cf.length;
1148193326Sed				break;
1149193326Sed			}
1150193326Sed			memcpy(&cf.count, p + offset, 6);
1151193326Sed			offset += 6;
1152193326Sed			length -= 6;
1153193326Sed			/*
1154193326Sed			 * Present and not truncated.
1155193576Sed			 *
1156193576Sed			 * If we haven't already seen a CF IE,
1157193326Sed			 * copy this one, otherwise ignore this one,
1158193326Sed			 * so we later report the first one we saw.
1159193576Sed			 */
1160193576Sed			if (!pbody->cf_present) {
1161193576Sed				pbody->cf = cf;
1162193326Sed				pbody->cf_present = 1;
1163193326Sed			}
1164193326Sed			break;
1165193326Sed		case E_TIM:
1166193326Sed			memcpy(&tim, p + offset, 2);
1167193326Sed			offset += 2;
1168193326Sed			length -= 2;
1169193326Sed			if (tim.length <= 3) {
1170193326Sed				offset += tim.length;
1171193326Sed				length -= tim.length;
1172193326Sed				break;
1173193326Sed			}
1174193326Sed			if (tim.length - 3 > (int)sizeof tim.bitmap)
1175193326Sed				return 0;
1176193326Sed			memcpy(&tim.count, p + offset, 3);
1177193326Sed			offset += 3;
1178193576Sed			length -= 3;
1179193576Sed
1180193576Sed			memcpy(tim.bitmap, p + offset, tim.length - 3);
1181193576Sed			offset += tim.length - 3;
1182193326Sed			length -= tim.length - 3;
1183193326Sed			/*
1184194179Sed			 * Present and not truncated.
1185194179Sed			 *
1186193326Sed			 * If we haven't already seen a TIM IE,
1187194179Sed			 * copy this one, otherwise ignore this one,
1188194179Sed			 * so we later report the first one we saw.
1189193326Sed			 */
1190193326Sed			if (!pbody->tim_present) {
1191193326Sed				pbody->tim = tim;
1192193326Sed				pbody->tim_present = 1;
1193193326Sed			}
1194193326Sed			break;
1195193326Sed		default:
1196193326Sed#if 0
1197193326Sed			ND_PRINT((ndo, "(1) unhandled element_id (%d)  ",
1198193326Sed			    *(p + offset)));
1199193326Sed#endif
1200193326Sed			offset += 2 + elementlen;
1201193326Sed			length -= 2 + elementlen;
1202193326Sed			break;
1203193326Sed		}
1204193326Sed	}
1205193326Sed
1206193326Sed	/* No problems found. */
1207193326Sed	return 1;
1208193326Sed}
1209193326Sed
1210193326Sed/*********************************************************************************
1211193326Sed * Print Handle functions for the management frame types
1212193326Sed *********************************************************************************/
1213193326Sed
1214193326Sedstatic int
1215193326Sedhandle_beacon(netdissect_options *ndo,
1216193326Sed              const u_char *p, u_int length)
1217194613Sed{
1218194613Sed	struct mgmt_body_t pbody;
1219194613Sed	int offset = 0;
1220194613Sed	int ret;
1221194613Sed
1222193326Sed	memset(&pbody, 0, sizeof(pbody));
1223193326Sed
1224193326Sed	if (!ND_TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1225193326Sed	    IEEE802_11_CAPINFO_LEN))
1226193326Sed		return 0;
1227193326Sed	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1228193326Sed	    IEEE802_11_CAPINFO_LEN)
1229193576Sed		return 0;
1230193576Sed	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
1231193576Sed	offset += IEEE802_11_TSTAMP_LEN;
1232193576Sed	length -= IEEE802_11_TSTAMP_LEN;
1233193326Sed	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
1234193326Sed	offset += IEEE802_11_BCNINT_LEN;
1235193326Sed	length -= IEEE802_11_BCNINT_LEN;
1236193326Sed	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
1237193326Sed	offset += IEEE802_11_CAPINFO_LEN;
1238193326Sed	length -= IEEE802_11_CAPINFO_LEN;
1239193326Sed
1240193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1241193326Sed
1242193326Sed	PRINT_SSID(pbody);
1243193326Sed	PRINT_RATES(pbody);
1244193326Sed	ND_PRINT((ndo, " %s",
1245193326Sed	    CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS"));
1246193326Sed	PRINT_DS_CHANNEL(pbody);
1247193326Sed
1248193326Sed	return ret;
1249193326Sed}
1250193326Sed
1251193326Sedstatic int
1252193326Sedhandle_assoc_request(netdissect_options *ndo,
1253193326Sed                     const u_char *p, u_int length)
1254193326Sed{
1255193326Sed	struct mgmt_body_t pbody;
1256193326Sed	int offset = 0;
1257193326Sed	int ret;
1258193326Sed
1259193326Sed	memset(&pbody, 0, sizeof(pbody));
1260193326Sed
1261193326Sed	if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
1262193326Sed		return 0;
1263193326Sed	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
1264193326Sed		return 0;
1265193326Sed	pbody.capability_info = EXTRACT_LE_16BITS(p);
1266194613Sed	offset += IEEE802_11_CAPINFO_LEN;
1267194613Sed	length -= IEEE802_11_CAPINFO_LEN;
1268194613Sed	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
1269194613Sed	offset += IEEE802_11_LISTENINT_LEN;
1270193326Sed	length -= IEEE802_11_LISTENINT_LEN;
1271193326Sed
1272193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1273193326Sed
1274193326Sed	PRINT_SSID(pbody);
1275193326Sed	PRINT_RATES(pbody);
1276193326Sed	return ret;
1277193326Sed}
1278193326Sed
1279193326Sedstatic int
1280193326Sedhandle_assoc_response(netdissect_options *ndo,
1281193326Sed                      const u_char *p, u_int length)
1282193326Sed{
1283193326Sed	struct mgmt_body_t pbody;
1284193326Sed	int offset = 0;
1285193326Sed	int ret;
1286193326Sed
1287193326Sed	memset(&pbody, 0, sizeof(pbody));
1288193326Sed
1289193326Sed	if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1290193326Sed	    IEEE802_11_AID_LEN))
1291193326Sed		return 0;
1292193326Sed	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
1293193326Sed	    IEEE802_11_AID_LEN)
1294193326Sed		return 0;
1295193326Sed	pbody.capability_info = EXTRACT_LE_16BITS(p);
1296193326Sed	offset += IEEE802_11_CAPINFO_LEN;
1297193326Sed	length -= IEEE802_11_CAPINFO_LEN;
1298193326Sed	pbody.status_code = EXTRACT_LE_16BITS(p+offset);
1299193326Sed	offset += IEEE802_11_STATUS_LEN;
1300193326Sed	length -= IEEE802_11_STATUS_LEN;
1301193326Sed	pbody.aid = EXTRACT_LE_16BITS(p+offset);
1302193326Sed	offset += IEEE802_11_AID_LEN;
1303193326Sed	length -= IEEE802_11_AID_LEN;
1304193326Sed
1305193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1306193326Sed
1307193326Sed	ND_PRINT((ndo, " AID(%x) :%s: %s", ((uint16_t)(pbody.aid << 2 )) >> 2 ,
1308193326Sed	    CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
1309193326Sed	    (pbody.status_code < NUM_STATUSES
1310193326Sed		? status_text[pbody.status_code]
1311193326Sed		: "n/a")));
1312193326Sed
1313193326Sed	return ret;
1314193326Sed}
1315193326Sed
1316193326Sedstatic int
1317193326Sedhandle_reassoc_request(netdissect_options *ndo,
1318193326Sed                       const u_char *p, u_int length)
1319193326Sed{
1320193326Sed	struct mgmt_body_t pbody;
1321193326Sed	int offset = 0;
1322193326Sed	int ret;
1323193326Sed
1324193326Sed	memset(&pbody, 0, sizeof(pbody));
1325193326Sed
1326193326Sed	if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1327193326Sed	    IEEE802_11_AP_LEN))
1328193326Sed		return 0;
1329193326Sed	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
1330193326Sed	    IEEE802_11_AP_LEN)
1331193326Sed		return 0;
1332193326Sed	pbody.capability_info = EXTRACT_LE_16BITS(p);
1333193326Sed	offset += IEEE802_11_CAPINFO_LEN;
1334193326Sed	length -= IEEE802_11_CAPINFO_LEN;
1335193326Sed	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
1336193326Sed	offset += IEEE802_11_LISTENINT_LEN;
1337193326Sed	length -= IEEE802_11_LISTENINT_LEN;
1338193326Sed	memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
1339193326Sed	offset += IEEE802_11_AP_LEN;
1340193326Sed	length -= IEEE802_11_AP_LEN;
1341193326Sed
1342193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1343193326Sed
1344193326Sed	PRINT_SSID(pbody);
1345193326Sed	ND_PRINT((ndo, " AP : %s", etheraddr_string(ndo,  pbody.ap )));
1346193326Sed
1347193326Sed	return ret;
1348193326Sed}
1349193326Sed
1350193326Sedstatic int
1351193326Sedhandle_reassoc_response(netdissect_options *ndo,
1352193326Sed                        const u_char *p, u_int length)
1353193326Sed{
1354193326Sed	/* Same as a Association Reponse */
1355193326Sed	return handle_assoc_response(ndo, p, length);
1356193326Sed}
1357193326Sed
1358193326Sedstatic int
1359193326Sedhandle_probe_request(netdissect_options *ndo,
1360193326Sed                     const u_char *p, u_int length)
1361193326Sed{
1362193326Sed	struct mgmt_body_t  pbody;
1363193326Sed	int offset = 0;
1364193326Sed	int ret;
1365193326Sed
1366193326Sed	memset(&pbody, 0, sizeof(pbody));
1367193326Sed
1368193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1369193326Sed
1370193326Sed	PRINT_SSID(pbody);
1371193326Sed	PRINT_RATES(pbody);
1372193326Sed
1373193326Sed	return ret;
1374193326Sed}
1375193326Sed
1376193326Sedstatic int
1377193326Sedhandle_probe_response(netdissect_options *ndo,
1378193326Sed                      const u_char *p, u_int length)
1379193326Sed{
1380193326Sed	struct mgmt_body_t  pbody;
1381193326Sed	int offset = 0;
1382193326Sed	int ret;
1383193326Sed
1384193326Sed	memset(&pbody, 0, sizeof(pbody));
1385193326Sed
1386193326Sed	if (!ND_TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1387193326Sed	    IEEE802_11_CAPINFO_LEN))
1388193326Sed		return 0;
1389193326Sed	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
1390193326Sed	    IEEE802_11_CAPINFO_LEN)
1391193326Sed		return 0;
1392193326Sed	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
1393193326Sed	offset += IEEE802_11_TSTAMP_LEN;
1394193326Sed	length -= IEEE802_11_TSTAMP_LEN;
1395193326Sed	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
1396193326Sed	offset += IEEE802_11_BCNINT_LEN;
1397193326Sed	length -= IEEE802_11_BCNINT_LEN;
1398193326Sed	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
1399193326Sed	offset += IEEE802_11_CAPINFO_LEN;
1400193326Sed	length -= IEEE802_11_CAPINFO_LEN;
1401193326Sed
1402193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1403193326Sed
1404193326Sed	PRINT_SSID(pbody);
1405193326Sed	PRINT_RATES(pbody);
1406193326Sed	PRINT_DS_CHANNEL(pbody);
1407193326Sed
1408193326Sed	return ret;
1409193326Sed}
1410193326Sed
1411193326Sedstatic int
1412193326Sedhandle_atim(void)
1413193326Sed{
1414193326Sed	/* the frame body for ATIM is null. */
1415193326Sed	return 1;
1416193326Sed}
1417193326Sed
1418193326Sedstatic int
1419193326Sedhandle_disassoc(netdissect_options *ndo,
1420193326Sed                const u_char *p, u_int length)
1421193326Sed{
1422193326Sed	struct mgmt_body_t  pbody;
1423193326Sed
1424193326Sed	memset(&pbody, 0, sizeof(pbody));
1425193326Sed
1426193326Sed	if (!ND_TTEST2(*p, IEEE802_11_REASON_LEN))
1427193326Sed		return 0;
1428193326Sed	if (length < IEEE802_11_REASON_LEN)
1429193326Sed		return 0;
1430193326Sed	pbody.reason_code = EXTRACT_LE_16BITS(p);
1431193326Sed
1432193326Sed	ND_PRINT((ndo, ": %s",
1433193326Sed	    (pbody.reason_code < NUM_REASONS)
1434193326Sed		? reason_text[pbody.reason_code]
1435193326Sed		: "Reserved"));
1436193326Sed
1437193326Sed	return 1;
1438193326Sed}
1439193326Sed
1440193326Sedstatic int
1441193326Sedhandle_auth(netdissect_options *ndo,
1442193326Sed            const u_char *p, u_int length)
1443193326Sed{
1444193326Sed	struct mgmt_body_t  pbody;
1445193326Sed	int offset = 0;
1446193326Sed	int ret;
1447193326Sed
1448193326Sed	memset(&pbody, 0, sizeof(pbody));
1449193326Sed
1450193326Sed	if (!ND_TTEST2(*p, 6))
1451193326Sed		return 0;
1452193326Sed	if (length < 6)
1453193326Sed		return 0;
1454193326Sed	pbody.auth_alg = EXTRACT_LE_16BITS(p);
1455193326Sed	offset += 2;
1456193326Sed	length -= 2;
1457193326Sed	pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
1458193326Sed	offset += 2;
1459193326Sed	length -= 2;
1460193326Sed	pbody.status_code = EXTRACT_LE_16BITS(p + offset);
1461193326Sed	offset += 2;
1462193326Sed	length -= 2;
1463193326Sed
1464193326Sed	ret = parse_elements(ndo, &pbody, p, offset, length);
1465193326Sed
1466193326Sed	if ((pbody.auth_alg == 1) &&
1467193326Sed	    ((pbody.auth_trans_seq_num == 2) ||
1468193326Sed	     (pbody.auth_trans_seq_num == 3))) {
1469193326Sed		ND_PRINT((ndo, " (%s)-%x [Challenge Text] %s",
1470193326Sed		    (pbody.auth_alg < NUM_AUTH_ALGS)
1471193326Sed			? auth_alg_text[pbody.auth_alg]
1472193326Sed			: "Reserved",
1473193326Sed		    pbody.auth_trans_seq_num,
1474193326Sed		    ((pbody.auth_trans_seq_num % 2)
1475193326Sed		        ? ((pbody.status_code < NUM_STATUSES)
1476193326Sed			       ? status_text[pbody.status_code]
1477193326Sed			       : "n/a") : "")));
1478193326Sed		return ret;
1479193326Sed	}
1480193326Sed	ND_PRINT((ndo, " (%s)-%x: %s",
1481194179Sed	    (pbody.auth_alg < NUM_AUTH_ALGS)
1482193326Sed		? auth_alg_text[pbody.auth_alg]
1483193326Sed		: "Reserved",
1484194179Sed	    pbody.auth_trans_seq_num,
1485193326Sed	    (pbody.auth_trans_seq_num % 2)
1486193326Sed	        ? ((pbody.status_code < NUM_STATUSES)
1487193326Sed		    ? status_text[pbody.status_code]
1488193326Sed	            : "n/a")
1489193326Sed	        : ""));
1490193326Sed
1491193326Sed	return ret;
1492194179Sed}
1493193326Sed
1494193326Sedstatic int
1495193326Sedhandle_deauth(netdissect_options *ndo,
1496193326Sed              const uint8_t *src, const u_char *p, u_int length)
1497193326Sed{
1498193326Sed	struct mgmt_body_t  pbody;
1499193326Sed	const char *reason = NULL;
1500193326Sed
1501193326Sed	memset(&pbody, 0, sizeof(pbody));
1502193326Sed
1503193326Sed	if (!ND_TTEST2(*p, IEEE802_11_REASON_LEN))
1504193326Sed		return 0;
1505193326Sed	if (length < IEEE802_11_REASON_LEN)
1506193326Sed		return 0;
1507193326Sed	pbody.reason_code = EXTRACT_LE_16BITS(p);
1508193326Sed
1509193326Sed	reason = (pbody.reason_code < NUM_REASONS)
1510193326Sed			? reason_text[pbody.reason_code]
1511193326Sed			: "Reserved";
1512193326Sed
1513193326Sed	if (ndo->ndo_eflag) {
1514193326Sed		ND_PRINT((ndo, ": %s", reason));
1515193326Sed	} else {
1516193326Sed		ND_PRINT((ndo, " (%s): %s", etheraddr_string(ndo, src), reason));
1517193326Sed	}
1518193326Sed	return 1;
1519193326Sed}
1520193326Sed
1521193326Sed#define	PRINT_HT_ACTION(v) (\
1522193326Sed	(v) == 0 ? ND_PRINT((ndo, "TxChWidth")) : \
1523193326Sed	(v) == 1 ? ND_PRINT((ndo, "MIMOPwrSave")) : \
1524193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1525193326Sed)
1526193326Sed#define	PRINT_BA_ACTION(v) (\
1527193326Sed	(v) == 0 ? ND_PRINT((ndo, "ADDBA Request")) : \
1528193326Sed	(v) == 1 ? ND_PRINT((ndo, "ADDBA Response")) : \
1529193326Sed	(v) == 2 ? ND_PRINT((ndo, "DELBA")) : \
1530193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1531193326Sed)
1532193326Sed#define	PRINT_MESHLINK_ACTION(v) (\
1533193326Sed	(v) == 0 ? ND_PRINT((ndo, "Request")) : \
1534193326Sed	(v) == 1 ? ND_PRINT((ndo, "Report")) : \
1535193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1536193326Sed)
1537193326Sed#define	PRINT_MESHPEERING_ACTION(v) (\
1538193326Sed	(v) == 0 ? ND_PRINT((ndo, "Open")) : \
1539193326Sed	(v) == 1 ? ND_PRINT((ndo, "Confirm")) : \
1540193326Sed	(v) == 2 ? ND_PRINT((ndo, "Close")) : \
1541193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1542193326Sed)
1543193326Sed#define	PRINT_MESHPATH_ACTION(v) (\
1544193326Sed	(v) == 0 ? ND_PRINT((ndo, "Request")) : \
1545193326Sed	(v) == 1 ? ND_PRINT((ndo, "Report")) : \
1546193326Sed	(v) == 2 ? ND_PRINT((ndo, "Error")) : \
1547193326Sed	(v) == 3 ? ND_PRINT((ndo, "RootAnnouncement")) : \
1548193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1549193326Sed)
1550193326Sed
1551193326Sed#define PRINT_MESH_ACTION(v) (\
1552193326Sed	(v) == 0 ? ND_PRINT((ndo, "MeshLink")) : \
1553193326Sed	(v) == 1 ? ND_PRINT((ndo, "HWMP")) : \
1554193326Sed	(v) == 2 ? ND_PRINT((ndo, "Gate Announcement")) : \
1555193326Sed	(v) == 3 ? ND_PRINT((ndo, "Congestion Control")) : \
1556193326Sed	(v) == 4 ? ND_PRINT((ndo, "MCCA Setup Request")) : \
1557194179Sed	(v) == 5 ? ND_PRINT((ndo, "MCCA Setup Reply")) : \
1558193326Sed	(v) == 6 ? ND_PRINT((ndo, "MCCA Advertisement Request")) : \
1559193326Sed	(v) == 7 ? ND_PRINT((ndo, "MCCA Advertisement")) : \
1560193326Sed	(v) == 8 ? ND_PRINT((ndo, "MCCA Teardown")) : \
1561193326Sed	(v) == 9 ? ND_PRINT((ndo, "TBTT Adjustment Request")) : \
1562193326Sed	(v) == 10 ? ND_PRINT((ndo, "TBTT Adjustment Response")) : \
1563193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1564193326Sed)
1565193326Sed#define PRINT_MULTIHOP_ACTION(v) (\
1566193326Sed	(v) == 0 ? ND_PRINT((ndo, "Proxy Update")) : \
1567193326Sed	(v) == 1 ? ND_PRINT((ndo, "Proxy Update Confirmation")) : \
1568193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1569193326Sed)
1570193326Sed#define PRINT_SELFPROT_ACTION(v) (\
1571193326Sed	(v) == 1 ? ND_PRINT((ndo, "Peering Open")) : \
1572193326Sed	(v) == 2 ? ND_PRINT((ndo, "Peering Confirm")) : \
1573193326Sed	(v) == 3 ? ND_PRINT((ndo, "Peering Close")) : \
1574193326Sed	(v) == 4 ? ND_PRINT((ndo, "Group Key Inform")) : \
1575193326Sed	(v) == 5 ? ND_PRINT((ndo, "Group Key Acknowledge")) : \
1576193326Sed		   ND_PRINT((ndo, "Act#%d", (v))) \
1577193326Sed)
1578193326Sed
1579193326Sedstatic int
1580193326Sedhandle_action(netdissect_options *ndo,
1581193326Sed              const uint8_t *src, const u_char *p, u_int length)
1582193326Sed{
1583193326Sed	if (!ND_TTEST2(*p, 2))
1584193326Sed		return 0;
1585193326Sed	if (length < 2)
1586193326Sed		return 0;
1587194179Sed	if (ndo->ndo_eflag) {
1588194179Sed		ND_PRINT((ndo, ": "));
1589194179Sed	} else {
1590194179Sed		ND_PRINT((ndo, " (%s): ", etheraddr_string(ndo, src)));
1591194179Sed	}
1592194179Sed	switch (p[0]) {
1593194179Sed	case 0: ND_PRINT((ndo, "Spectrum Management Act#%d", p[1])); break;
1594194179Sed	case 1: ND_PRINT((ndo, "QoS Act#%d", p[1])); break;
1595193326Sed	case 2: ND_PRINT((ndo, "DLS Act#%d", p[1])); break;
1596193326Sed	case 3: ND_PRINT((ndo, "BA ")); PRINT_BA_ACTION(p[1]); break;
1597194179Sed	case 7: ND_PRINT((ndo, "HT ")); PRINT_HT_ACTION(p[1]); break;
1598194179Sed	case 13: ND_PRINT((ndo, "MeshAction ")); PRINT_MESH_ACTION(p[1]); break;
1599194179Sed	case 14:
1600193326Sed		ND_PRINT((ndo, "MultiohopAction "));
1601193326Sed		PRINT_MULTIHOP_ACTION(p[1]); break;
1602193326Sed	case 15:
1603193326Sed		ND_PRINT((ndo, "SelfprotectAction "));
1604193326Sed		PRINT_SELFPROT_ACTION(p[1]); break;
1605193326Sed	case 127: ND_PRINT((ndo, "Vendor Act#%d", p[1])); break;
1606193326Sed	default:
1607193326Sed		ND_PRINT((ndo, "Reserved(%d) Act#%d", p[0], p[1]));
1608193326Sed		break;
1609193326Sed	}
1610193326Sed	return 1;
1611193326Sed}
1612193326Sed
1613193326Sed
1614193326Sed/*********************************************************************************
1615193326Sed * Print Body funcs
1616193326Sed *********************************************************************************/
1617193326Sed
1618193326Sed
1619193326Sedstatic int
1620193326Sedmgmt_body_print(netdissect_options *ndo,
1621193326Sed                uint16_t fc, const uint8_t *src, const u_char *p, u_int length)
1622193326Sed{
1623193326Sed	ND_PRINT((ndo, "%s", tok2str(st_str, "Unhandled Management subtype(%x)", FC_SUBTYPE(fc))));
1624193326Sed
1625193326Sed	/* There may be a problem w/ AP not having this bit set */
1626193326Sed	if (FC_PROTECTED(fc))
1627193326Sed		return wep_print(ndo, p);
1628193326Sed	switch (FC_SUBTYPE(fc)) {
1629193326Sed	case ST_ASSOC_REQUEST:
1630193326Sed		return handle_assoc_request(ndo, p, length);
1631193326Sed	case ST_ASSOC_RESPONSE:
1632193326Sed		return handle_assoc_response(ndo, p, length);
1633193326Sed	case ST_REASSOC_REQUEST:
1634193326Sed		return handle_reassoc_request(ndo, p, length);
1635193326Sed	case ST_REASSOC_RESPONSE:
1636193326Sed		return handle_reassoc_response(ndo, p, length);
1637193326Sed	case ST_PROBE_REQUEST:
1638193326Sed		return handle_probe_request(ndo, p, length);
1639193326Sed	case ST_PROBE_RESPONSE:
1640193326Sed		return handle_probe_response(ndo, p, length);
1641193326Sed	case ST_BEACON:
1642193326Sed		return handle_beacon(ndo, p, length);
1643193326Sed	case ST_ATIM:
1644193326Sed		return handle_atim();
1645193326Sed	case ST_DISASSOC:
1646193326Sed		return handle_disassoc(ndo, p, length);
1647193326Sed	case ST_AUTH:
1648193326Sed		return handle_auth(ndo, p, length);
1649193326Sed	case ST_DEAUTH:
1650193326Sed		return handle_deauth(ndo, src, p, length);
1651193326Sed	case ST_ACTION:
1652193326Sed		return handle_action(ndo, src, p, length);
1653193326Sed	default:
1654193326Sed		return 1;
1655193326Sed	}
1656193326Sed}
1657193326Sed
1658193326Sed
1659193326Sed/*********************************************************************************
1660193326Sed * Handles printing all the control frame types
1661193326Sed *********************************************************************************/
1662193326Sed
1663193326Sedstatic int
1664193326Sedctrl_body_print(netdissect_options *ndo,
1665193326Sed                uint16_t fc, const u_char *p)
1666194179Sed{
1667194179Sed	ND_PRINT((ndo, "%s", tok2str(ctrl_str, "Unknown Ctrl Subtype", FC_SUBTYPE(fc))));
1668193326Sed	switch (FC_SUBTYPE(fc)) {
1669193326Sed	case CTRL_CONTROL_WRAPPER:
1670193326Sed		/* XXX - requires special handling */
1671193326Sed		break;
1672193326Sed	case CTRL_BAR:
1673193326Sed		if (!ND_TTEST2(*p, CTRL_BAR_HDRLEN))
1674193326Sed			return 0;
1675194179Sed		if (!ndo->ndo_eflag)
1676194179Sed			ND_PRINT((ndo, " RA:%s TA:%s CTL(%x) SEQ(%u) ",
1677193326Sed			    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ra),
1678193326Sed			    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ta),
1679193326Sed			    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->ctl)),
1680193326Sed			    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->seq))));
1681193326Sed		break;
1682193326Sed	case CTRL_BA:
1683193326Sed		if (!ND_TTEST2(*p, CTRL_BA_HDRLEN))
1684193326Sed			return 0;
1685193326Sed		if (!ndo->ndo_eflag)
1686193326Sed			ND_PRINT((ndo, " RA:%s ",
1687193326Sed			    etheraddr_string(ndo, ((const struct ctrl_ba_hdr_t *)p)->ra)));
1688193326Sed		break;
1689193326Sed	case CTRL_PS_POLL:
1690193326Sed		if (!ND_TTEST2(*p, CTRL_PS_POLL_HDRLEN))
1691193326Sed			return 0;
1692193326Sed		ND_PRINT((ndo, " AID(%x)",
1693193326Sed		    EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_hdr_t *)p)->aid))));
1694193326Sed		break;
1695193326Sed	case CTRL_RTS:
1696193326Sed		if (!ND_TTEST2(*p, CTRL_RTS_HDRLEN))
1697193326Sed			return 0;
1698193326Sed		if (!ndo->ndo_eflag)
1699193326Sed			ND_PRINT((ndo, " TA:%s ",
1700193326Sed			    etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ta)));
1701193326Sed		break;
1702193326Sed	case CTRL_CTS:
1703193326Sed		if (!ND_TTEST2(*p, CTRL_CTS_HDRLEN))
1704193326Sed			return 0;
1705193326Sed		if (!ndo->ndo_eflag)
1706193326Sed			ND_PRINT((ndo, " RA:%s ",
1707193326Sed			    etheraddr_string(ndo, ((const struct ctrl_cts_hdr_t *)p)->ra)));
1708193326Sed		break;
1709193326Sed	case CTRL_ACK:
1710193326Sed		if (!ND_TTEST2(*p, CTRL_ACK_HDRLEN))
1711193326Sed			return 0;
1712193326Sed		if (!ndo->ndo_eflag)
1713193326Sed			ND_PRINT((ndo, " RA:%s ",
1714194179Sed			    etheraddr_string(ndo, ((const struct ctrl_ack_hdr_t *)p)->ra)));
1715194179Sed		break;
1716193326Sed	case CTRL_CF_END:
1717193326Sed		if (!ND_TTEST2(*p, CTRL_END_HDRLEN))
1718193326Sed			return 0;
1719193326Sed		if (!ndo->ndo_eflag)
1720193326Sed			ND_PRINT((ndo, " RA:%s ",
1721193326Sed			    etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->ra)));
1722193326Sed		break;
1723193326Sed	case CTRL_END_ACK:
1724193326Sed		if (!ND_TTEST2(*p, CTRL_END_ACK_HDRLEN))
1725193326Sed			return 0;
1726193326Sed		if (!ndo->ndo_eflag)
1727193326Sed			ND_PRINT((ndo, " RA:%s ",
1728193326Sed			    etheraddr_string(ndo, ((const struct ctrl_end_ack_hdr_t *)p)->ra)));
1729193326Sed		break;
1730193326Sed	}
1731193326Sed	return 1;
1732193326Sed}
1733193326Sed
1734193326Sed/*
1735193326Sed *  Data Frame - Address field contents
1736193326Sed *
1737193326Sed *  To Ds  | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
1738193326Sed *    0    |  0      |  DA    | SA     | BSSID  | n/a
1739193326Sed *    0    |  1      |  DA    | BSSID  | SA     | n/a
1740193326Sed *    1    |  0      |  BSSID | SA     | DA     | n/a
1741193326Sed *    1    |  1      |  RA    | TA     | DA     | SA
1742193326Sed */
1743193326Sed
1744193326Sed/*
1745193326Sed * Function to get source and destination MAC addresses for a data frame.
1746193326Sed */
1747193326Sedstatic void
1748193326Sedget_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp,
1749193326Sed                     const uint8_t **dstp)
1750193326Sed{
1751193326Sed#define ADDR1  (p + 4)
1752193326Sed#define ADDR2  (p + 10)
1753193326Sed#define ADDR3  (p + 16)
1754193326Sed#define ADDR4  (p + 24)
1755194179Sed
1756194179Sed	if (!FC_TO_DS(fc)) {
1757193326Sed		if (!FC_FROM_DS(fc)) {
1758193326Sed			/* not To DS and not From DS */
1759193326Sed			*srcp = ADDR2;
1760193326Sed			*dstp = ADDR1;
1761193326Sed		} else {
1762193326Sed			/* not To DS and From DS */
1763193326Sed			*srcp = ADDR3;
1764193326Sed			*dstp = ADDR1;
1765193326Sed		}
1766193326Sed	} else {
1767193326Sed		if (!FC_FROM_DS(fc)) {
1768193326Sed			/* From DS and not To DS */
1769193326Sed			*srcp = ADDR2;
1770193326Sed			*dstp = ADDR3;
1771193326Sed		} else {
1772193326Sed			/* To DS and From DS */
1773193326Sed			*srcp = ADDR4;
1774193326Sed			*dstp = ADDR3;
1775193326Sed		}
1776193326Sed	}
1777193326Sed
1778193326Sed#undef ADDR1
1779193326Sed#undef ADDR2
1780193326Sed#undef ADDR3
1781193326Sed#undef ADDR4
1782193326Sed}
1783193326Sed
1784194179Sedstatic void
1785194179Sedget_mgmt_src_dst_mac(const u_char *p, const uint8_t **srcp, const uint8_t **dstp)
1786193326Sed{
1787193326Sed	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
1788193326Sed
1789193326Sed	if (srcp != NULL)
1790193326Sed		*srcp = hp->sa;
1791193326Sed	if (dstp != NULL)
1792193326Sed		*dstp = hp->da;
1793193326Sed}
1794193326Sed
1795193326Sed/*
1796193326Sed * Print Header funcs
1797193326Sed */
1798193326Sed
1799193326Sedstatic void
1800193326Seddata_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
1801193326Sed{
1802193326Sed	u_int subtype = FC_SUBTYPE(fc);
1803193326Sed
1804193326Sed	if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) ||
1805193326Sed	    DATA_FRAME_IS_QOS(subtype)) {
1806194179Sed		ND_PRINT((ndo, "CF "));
1807194179Sed		if (DATA_FRAME_IS_CF_ACK(subtype)) {
1808194179Sed			if (DATA_FRAME_IS_CF_POLL(subtype))
1809194179Sed				ND_PRINT((ndo, "Ack/Poll"));
1810194179Sed			else
1811194179Sed				ND_PRINT((ndo, "Ack"));
1812193326Sed		} else {
1813193326Sed			if (DATA_FRAME_IS_CF_POLL(subtype))
1814193326Sed				ND_PRINT((ndo, "Poll"));
1815193326Sed		}
1816193326Sed		if (DATA_FRAME_IS_QOS(subtype))
1817193326Sed			ND_PRINT((ndo, "+QoS"));
1818193326Sed		ND_PRINT((ndo, " "));
1819193326Sed	}
1820193326Sed
1821193326Sed#define ADDR1  (p + 4)
1822193326Sed#define ADDR2  (p + 10)
1823193326Sed#define ADDR3  (p + 16)
1824193326Sed#define ADDR4  (p + 24)
1825193326Sed
1826193326Sed	if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1827193326Sed		ND_PRINT((ndo, "DA:%s SA:%s BSSID:%s ",
1828193326Sed		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
1829193326Sed		    etheraddr_string(ndo, ADDR3)));
1830193326Sed	} else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1831193326Sed		ND_PRINT((ndo, "DA:%s BSSID:%s SA:%s ",
1832193326Sed		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
1833193326Sed		    etheraddr_string(ndo, ADDR3)));
1834193326Sed	} else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1835193326Sed		ND_PRINT((ndo, "BSSID:%s SA:%s DA:%s ",
1836193326Sed		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
1837193326Sed		    etheraddr_string(ndo, ADDR3)));
1838193326Sed	} else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1839193326Sed		ND_PRINT((ndo, "RA:%s TA:%s DA:%s SA:%s ",
1840193326Sed		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
1841193326Sed		    etheraddr_string(ndo, ADDR3), etheraddr_string(ndo, ADDR4)));
1842193326Sed	}
1843193326Sed
1844193326Sed#undef ADDR1
1845193326Sed#undef ADDR2
1846193326Sed#undef ADDR3
1847193326Sed#undef ADDR4
1848193326Sed}
1849193326Sed
1850193326Sedstatic void
1851193326Sedmgmt_header_print(netdissect_options *ndo, const u_char *p)
1852193326Sed{
1853193326Sed	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
1854193326Sed
1855193326Sed	ND_PRINT((ndo, "BSSID:%s DA:%s SA:%s ",
1856193326Sed	    etheraddr_string(ndo, (hp)->bssid), etheraddr_string(ndo, (hp)->da),
1857193326Sed	    etheraddr_string(ndo, (hp)->sa)));
1858193326Sed}
1859193326Sed
1860193326Sedstatic void
1861193326Sedctrl_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
1862193326Sed{
1863193326Sed	switch (FC_SUBTYPE(fc)) {
1864193326Sed	case CTRL_BAR:
1865193326Sed		ND_PRINT((ndo, " RA:%s TA:%s CTL(%x) SEQ(%u) ",
1866193326Sed		    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ra),
1867193326Sed		    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ta),
1868193326Sed		    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->ctl)),
1869193326Sed		    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->seq))));
1870193326Sed		break;
1871193326Sed	case CTRL_BA:
1872193326Sed		ND_PRINT((ndo, "RA:%s ",
1873193326Sed		    etheraddr_string(ndo, ((const struct ctrl_ba_hdr_t *)p)->ra)));
1874193326Sed		break;
1875193326Sed	case CTRL_PS_POLL:
1876193326Sed		ND_PRINT((ndo, "BSSID:%s TA:%s ",
1877193326Sed		    etheraddr_string(ndo, ((const struct ctrl_ps_poll_hdr_t *)p)->bssid),
1878193326Sed		    etheraddr_string(ndo, ((const struct ctrl_ps_poll_hdr_t *)p)->ta)));
1879193326Sed		break;
1880193326Sed	case CTRL_RTS:
1881193326Sed		ND_PRINT((ndo, "RA:%s TA:%s ",
1882193326Sed		    etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ra),
1883193326Sed		    etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ta)));
1884193326Sed		break;
1885193326Sed	case CTRL_CTS:
1886193326Sed		ND_PRINT((ndo, "RA:%s ",
1887193326Sed		    etheraddr_string(ndo, ((const struct ctrl_cts_hdr_t *)p)->ra)));
1888193326Sed		break;
1889193326Sed	case CTRL_ACK:
1890193326Sed		ND_PRINT((ndo, "RA:%s ",
1891193326Sed		    etheraddr_string(ndo, ((const struct ctrl_ack_hdr_t *)p)->ra)));
1892193326Sed		break;
1893193326Sed	case CTRL_CF_END:
1894193326Sed		ND_PRINT((ndo, "RA:%s BSSID:%s ",
1895193326Sed		    etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->ra),
1896193326Sed		    etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->bssid)));
1897193326Sed		break;
1898193326Sed	case CTRL_END_ACK:
1899193326Sed		ND_PRINT((ndo, "RA:%s BSSID:%s ",
1900193326Sed		    etheraddr_string(ndo, ((const struct ctrl_end_ack_hdr_t *)p)->ra),
1901193326Sed		    etheraddr_string(ndo, ((const struct ctrl_end_ack_hdr_t *)p)->bssid)));
1902193326Sed		break;
1903193326Sed	default:
1904193326Sed		/* We shouldn't get here - we should already have quit */
1905193326Sed		break;
1906193326Sed	}
1907193326Sed}
1908193326Sed
1909193326Sedstatic int
1910193326Sedextract_header_length(netdissect_options *ndo,
1911193326Sed                      uint16_t fc)
1912193326Sed{
1913193326Sed	int len;
1914193326Sed
1915193326Sed	switch (FC_TYPE(fc)) {
1916193326Sed	case T_MGMT:
1917193326Sed		return MGMT_HDRLEN;
1918193326Sed	case T_CTRL:
1919193326Sed		switch (FC_SUBTYPE(fc)) {
1920193326Sed		case CTRL_CONTROL_WRAPPER:
1921193326Sed			return CTRL_CONTROL_WRAPPER_HDRLEN;
1922193326Sed		case CTRL_BAR:
1923193326Sed			return CTRL_BAR_HDRLEN;
1924193326Sed		case CTRL_BA:
1925193326Sed			return CTRL_BA_HDRLEN;
1926193326Sed		case CTRL_PS_POLL:
1927193326Sed			return CTRL_PS_POLL_HDRLEN;
1928193326Sed		case CTRL_RTS:
1929193326Sed			return CTRL_RTS_HDRLEN;
1930193326Sed		case CTRL_CTS:
1931193326Sed			return CTRL_CTS_HDRLEN;
1932193326Sed		case CTRL_ACK:
1933193326Sed			return CTRL_ACK_HDRLEN;
1934193326Sed		case CTRL_CF_END:
1935193326Sed			return CTRL_END_HDRLEN;
1936193326Sed		case CTRL_END_ACK:
1937193326Sed			return CTRL_END_ACK_HDRLEN;
1938193326Sed		default:
1939193326Sed			ND_PRINT((ndo, "unknown 802.11 ctrl frame subtype (%d)", FC_SUBTYPE(fc)));
1940193326Sed			return 0;
1941193326Sed		}
1942193326Sed	case T_DATA:
1943193326Sed		len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
1944193326Sed		if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
1945193326Sed			len += 2;
1946193326Sed		return len;
1947193326Sed	default:
1948193326Sed		ND_PRINT((ndo, "unknown 802.11 frame type (%d)", FC_TYPE(fc)));
1949193326Sed		return 0;
1950193326Sed	}
1951193326Sed}
1952193326Sed
1953193326Sedstatic int
1954193326Sedextract_mesh_header_length(const u_char *p)
1955193326Sed{
1956193326Sed	return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3));
1957193326Sed}
1958193326Sed
1959193326Sed/*
1960193326Sed * Print the 802.11 MAC header.
1961193326Sed */
1962193326Sedstatic void
1963193326Sedieee_802_11_hdr_print(netdissect_options *ndo,
1964193326Sed                      uint16_t fc, const u_char *p, u_int hdrlen,
1965193326Sed                      u_int meshdrlen)
1966193326Sed{
1967193326Sed	if (ndo->ndo_vflag) {
1968193326Sed		if (FC_MORE_DATA(fc))
1969193326Sed			ND_PRINT((ndo, "More Data "));
1970193326Sed		if (FC_MORE_FLAG(fc))
1971193326Sed			ND_PRINT((ndo, "More Fragments "));
1972193326Sed		if (FC_POWER_MGMT(fc))
1973193326Sed			ND_PRINT((ndo, "Pwr Mgmt "));
1974193326Sed		if (FC_RETRY(fc))
1975193326Sed			ND_PRINT((ndo, "Retry "));
1976193326Sed		if (FC_ORDER(fc))
1977193326Sed			ND_PRINT((ndo, "Strictly Ordered "));
1978193326Sed		if (FC_PROTECTED(fc))
1979193326Sed			ND_PRINT((ndo, "Protected "));
1980193326Sed		if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL)
1981193326Sed			ND_PRINT((ndo, "%dus ",
1982193326Sed			    EXTRACT_LE_16BITS(
1983193326Sed			        &((const struct mgmt_header_t *)p)->duration)));
1984193326Sed	}
1985193326Sed	if (meshdrlen != 0) {
1986193326Sed		const struct meshcntl_t *mc =
1987193326Sed		    (const struct meshcntl_t *)&p[hdrlen - meshdrlen];
1988193326Sed		int ae = mc->flags & 3;
1989193326Sed
1990193326Sed		ND_PRINT((ndo, "MeshData (AE %d TTL %u seq %u", ae, mc->ttl,
1991193326Sed		    EXTRACT_LE_32BITS(mc->seq)));
1992193326Sed		if (ae > 0)
1993193326Sed			ND_PRINT((ndo, " A4:%s", etheraddr_string(ndo, mc->addr4)));
1994193326Sed		if (ae > 1)
1995193326Sed			ND_PRINT((ndo, " A5:%s", etheraddr_string(ndo, mc->addr5)));
1996193326Sed		if (ae > 2)
1997193326Sed			ND_PRINT((ndo, " A6:%s", etheraddr_string(ndo, mc->addr6)));
1998193326Sed		ND_PRINT((ndo, ") "));
1999193326Sed	}
2000193326Sed
2001193326Sed	switch (FC_TYPE(fc)) {
2002193326Sed	case T_MGMT:
2003193326Sed		mgmt_header_print(ndo, p);
2004193326Sed		break;
2005193326Sed	case T_CTRL:
2006194179Sed		ctrl_header_print(ndo, fc, p);
2007193326Sed		break;
2008193326Sed	case T_DATA:
2009193326Sed		data_header_print(ndo, fc, p);
2010193326Sed		break;
2011193326Sed	default:
2012193326Sed		break;
2013193326Sed	}
2014193326Sed}
2015193326Sed
2016193326Sed#ifndef roundup2
2017193326Sed#define	roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
2018193326Sed#endif
2019193326Sed
2020193326Sedstatic const char tstr[] = "[|802.11]";
2021193326Sed
2022194179Sedstatic u_int
2023193326Sedieee802_11_print(netdissect_options *ndo,
2024194179Sed                 const u_char *p, u_int length, u_int orig_caplen, int pad,
2025193326Sed                 u_int fcslen)
2026193326Sed{
2027193326Sed	uint16_t fc;
2028193326Sed	u_int caplen, hdrlen, meshdrlen;
2029193326Sed	struct lladdr_info src, dst;
2030193326Sed	int llc_hdrlen;
2031193326Sed
2032193326Sed	caplen = orig_caplen;
2033193326Sed	/* Remove FCS, if present */
2034193326Sed	if (length < fcslen) {
2035193326Sed		ND_PRINT((ndo, "%s", tstr));
2036193326Sed		return caplen;
2037193326Sed	}
2038193326Sed	length -= fcslen;
2039194179Sed	if (caplen > length) {
2040193326Sed		/* Amount of FCS in actual packet data, if any */
2041193326Sed		fcslen = caplen - length;
2042193326Sed		caplen -= fcslen;
2043194179Sed		ndo->ndo_snapend -= fcslen;
2044194179Sed	}
2045193326Sed
2046193326Sed	if (caplen < IEEE802_11_FC_LEN) {
2047193326Sed		ND_PRINT((ndo, "%s", tstr));
2048193326Sed		return orig_caplen;
2049193326Sed	}
2050193326Sed
2051193326Sed	fc = EXTRACT_LE_16BITS(p);
2052193326Sed	hdrlen = extract_header_length(ndo, fc);
2053193326Sed	if (hdrlen == 0) {
2054193326Sed		/* Unknown frame type or control frame subtype; quit. */
2055193326Sed		return (0);
2056193326Sed	}
2057193326Sed	if (pad)
2058194179Sed		hdrlen = roundup2(hdrlen, 4);
2059193326Sed	if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA &&
2060193326Sed	    DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
2061193326Sed		if (caplen < hdrlen + 1) {
2062194179Sed			ND_PRINT((ndo, "%s", tstr));
2063193326Sed			return hdrlen;
2064193326Sed		}
2065193326Sed		meshdrlen = extract_mesh_header_length(p+hdrlen);
2066193326Sed		hdrlen += meshdrlen;
2067193326Sed	} else
2068194179Sed		meshdrlen = 0;
2069193326Sed
2070193326Sed	if (caplen < hdrlen) {
2071193326Sed		ND_PRINT((ndo, "%s", tstr));
2072193326Sed		return hdrlen;
2073193326Sed	}
2074193326Sed
2075193326Sed	if (ndo->ndo_eflag)
2076193326Sed		ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen);
2077193326Sed
2078193326Sed	/*
2079193326Sed	 * Go past the 802.11 header.
2080193326Sed	 */
2081194179Sed	length -= hdrlen;
2082194179Sed	caplen -= hdrlen;
2083194179Sed	p += hdrlen;
2084194179Sed
2085194179Sed	src.addr_string = etheraddr_string;
2086194179Sed	dst.addr_string = etheraddr_string;
2087194179Sed	switch (FC_TYPE(fc)) {
2088194179Sed	case T_MGMT:
2089194179Sed		get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr);
2090194179Sed		if (!mgmt_body_print(ndo, fc, src.addr, p, length)) {
2091194179Sed			ND_PRINT((ndo, "%s", tstr));
2092194179Sed			return hdrlen;
2093194179Sed		}
2094194179Sed		break;
2095194179Sed	case T_CTRL:
2096194179Sed		if (!ctrl_body_print(ndo, fc, p - hdrlen)) {
2097194179Sed			ND_PRINT((ndo, "%s", tstr));
2098194179Sed			return hdrlen;
2099194179Sed		}
2100194179Sed		break;
2101194179Sed	case T_DATA:
2102194179Sed		if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
2103194179Sed			return hdrlen;	/* no-data frame */
2104194179Sed		/* There may be a problem w/ AP not having this bit set */
2105194179Sed		if (FC_PROTECTED(fc)) {
2106194179Sed			ND_PRINT((ndo, "Data"));
2107194179Sed			if (!wep_print(ndo, p)) {
2108194179Sed				ND_PRINT((ndo, "%s", tstr));
2109194179Sed				return hdrlen;
2110194179Sed			}
2111194179Sed		} else {
2112194179Sed			get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr);
2113194179Sed			llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
2114194179Sed			if (llc_hdrlen < 0) {
2115194179Sed				/*
2116194179Sed				 * Some kinds of LLC packet we cannot
2117194179Sed				 * handle intelligently
2118194179Sed				 */
2119194179Sed				if (!ndo->ndo_suppress_default_print)
2120194179Sed					ND_DEFAULTPRINT(p, caplen);
2121194179Sed				llc_hdrlen = -llc_hdrlen;
2122194179Sed			}
2123194179Sed			hdrlen += llc_hdrlen;
2124194179Sed		}
2125194179Sed		break;
2126194179Sed	default:
2127194179Sed		/* We shouldn't get here - we should already have quit */
2128194179Sed		break;
2129194179Sed	}
2130194179Sed
2131194179Sed	return hdrlen;
2132194179Sed}
2133194179Sed
2134194179Sed/*
2135194179Sed * This is the top level routine of the printer.  'p' points
2136194179Sed * to the 802.11 header of the packet, 'h->ts' is the timestamp,
2137194179Sed * 'h->len' is the length of the packet off the wire, and 'h->caplen'
2138194179Sed * is the number of bytes actually captured.
2139194179Sed */
2140194179Sedu_int
2141194179Sedieee802_11_if_print(netdissect_options *ndo,
2142194179Sed                    const struct pcap_pkthdr *h, const u_char *p)
2143194179Sed{
2144194179Sed	return ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0);
2145194179Sed}
2146194179Sed
2147194179Sed
2148194179Sed/* $FreeBSD: stable/11/contrib/tcpdump/print-802_11.c 276788 2015-01-07 19:55:18Z delphij $ */
2149194179Sed/* NetBSD: ieee802_11_radio.h,v 1.2 2006/02/26 03:04:03 dyoung Exp  */
2150194179Sed
2151194179Sed/*-
2152194179Sed * Copyright (c) 2003, 2004 David Young.  All rights reserved.
2153194179Sed *
2154194179Sed * Redistribution and use in source and binary forms, with or without
2155194179Sed * modification, are permitted provided that the following conditions
2156194179Sed * are met:
2157194179Sed * 1. Redistributions of source code must retain the above copyright
2158194179Sed *    notice, this list of conditions and the following disclaimer.
2159194179Sed * 2. Redistributions in binary form must reproduce the above copyright
2160194179Sed *    notice, this list of conditions and the following disclaimer in the
2161194179Sed *    documentation and/or other materials provided with the distribution.
2162194179Sed * 3. The name of David Young may not be used to endorse or promote
2163194179Sed *    products derived from this software without specific prior
2164194179Sed *    written permission.
2165194179Sed *
2166194179Sed * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
2167194179Sed * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2168194179Sed * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2169194179Sed * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
2170194179Sed * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2171194179Sed * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2172194179Sed * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2173194179Sed * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2174194179Sed * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2175194179Sed * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2176194179Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
2177194179Sed * OF SUCH DAMAGE.
2178194179Sed */
2179194179Sed
2180194179Sed/* A generic radio capture format is desirable. It must be
2181194179Sed * rigidly defined (e.g., units for fields should be given),
2182194179Sed * and easily extensible.
2183194179Sed *
2184194179Sed * The following is an extensible radio capture format. It is
2185194179Sed * based on a bitmap indicating which fields are present.
2186194179Sed *
2187194179Sed * I am trying to describe precisely what the application programmer
2188194179Sed * should expect in the following, and for that reason I tell the
2189194179Sed * units and origin of each measurement (where it applies), or else I
2190194179Sed * use sufficiently weaselly language ("is a monotonically nondecreasing
2191194179Sed * function of...") that I cannot set false expectations for lawyerly
2192194179Sed * readers.
2193194179Sed */
2194194179Sed
2195194179Sed/*
2196194179Sed * The radio capture header precedes the 802.11 header.
2197194179Sed *
2198194179Sed * Note well: all radiotap fields are little-endian.
2199194179Sed */
2200194179Sedstruct ieee80211_radiotap_header {
2201193326Sed	uint8_t		it_version;	/* Version 0. Only increases
2202193326Sed					 * for drastic changes,
2203193326Sed					 * introduction of compatible
2204193326Sed					 * new fields does not count.
2205193326Sed					 */
2206193326Sed	uint8_t		it_pad;
2207193326Sed	uint16_t	it_len;		/* length of the whole
2208193326Sed					 * header in bytes, including
2209193326Sed					 * it_version, it_pad,
2210193326Sed					 * it_len, and data fields.
2211193326Sed					 */
2212193326Sed	uint32_t	it_present;	/* A bitmap telling which
2213193326Sed					 * fields are present. Set bit 31
2214193326Sed					 * (0x80000000) to extend the
2215193326Sed					 * bitmap by another 32 bits.
2216193326Sed					 * Additional extensions are made
2217193326Sed					 * by setting bit 31.
2218193326Sed					 */
2219193326Sed};
2220193326Sed
2221193326Sed/* Name                                 Data type       Units
2222193326Sed * ----                                 ---------       -----
2223193326Sed *
2224193326Sed * IEEE80211_RADIOTAP_TSFT              uint64_t       microseconds
2225193326Sed *
2226193326Sed *      Value in microseconds of the MAC's 64-bit 802.11 Time
2227193326Sed *      Synchronization Function timer when the first bit of the
2228193326Sed *      MPDU arrived at the MAC. For received frames, only.
2229193326Sed *
2230193326Sed * IEEE80211_RADIOTAP_CHANNEL           2 x uint16_t   MHz, bitmap
2231193326Sed *
2232193326Sed *      Tx/Rx frequency in MHz, followed by flags (see below).
2233193326Sed *	Note that IEEE80211_RADIOTAP_XCHANNEL must be used to
2234193326Sed *	represent an HT channel as there is not enough room in
2235193326Sed *	the flags word.
2236193326Sed *
2237194179Sed * IEEE80211_RADIOTAP_FHSS              uint16_t       see below
2238193326Sed *
2239194179Sed *      For frequency-hopping radios, the hop set (first byte)
2240194179Sed *      and pattern (second byte).
2241194179Sed *
2242194179Sed * IEEE80211_RADIOTAP_RATE              uint8_t        500kb/s or index
2243194179Sed *
2244194179Sed *      Tx/Rx data rate.  If bit 0x80 is set then it represents an
2245194179Sed *	an MCS index and not an IEEE rate.
2246194179Sed *
2247194179Sed * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     int8_t          decibels from
2248194179Sed *                                                      one milliwatt (dBm)
2249194179Sed *
2250194179Sed *      RF signal power at the antenna, decibel difference from
2251194179Sed *      one milliwatt.
2252194179Sed *
2253194179Sed * IEEE80211_RADIOTAP_DBM_ANTNOISE      int8_t          decibels from
2254194179Sed *                                                      one milliwatt (dBm)
2255194179Sed *
2256194179Sed *      RF noise power at the antenna, decibel difference from one
2257194179Sed *      milliwatt.
2258194179Sed *
2259194179Sed * IEEE80211_RADIOTAP_DB_ANTSIGNAL      uint8_t        decibel (dB)
2260194179Sed *
2261194179Sed *      RF signal power at the antenna, decibel difference from an
2262194179Sed *      arbitrary, fixed reference.
2263194179Sed *
2264194179Sed * IEEE80211_RADIOTAP_DB_ANTNOISE       uint8_t        decibel (dB)
2265194179Sed *
2266194179Sed *      RF noise power at the antenna, decibel difference from an
2267194179Sed *      arbitrary, fixed reference point.
2268194179Sed *
2269194179Sed * IEEE80211_RADIOTAP_LOCK_QUALITY      uint16_t       unitless
2270194179Sed *
2271194179Sed *      Quality of Barker code lock. Unitless. Monotonically
2272193326Sed *      nondecreasing with "better" lock strength. Called "Signal
2273193326Sed *      Quality" in datasheets.  (Is there a standard way to measure
2274193326Sed *      this?)
2275193326Sed *
2276193326Sed * IEEE80211_RADIOTAP_TX_ATTENUATION    uint16_t       unitless
2277193326Sed *
2278193326Sed *      Transmit power expressed as unitless distance from max
2279193326Sed *      power set at factory calibration.  0 is max power.
2280193326Sed *      Monotonically nondecreasing with lower power levels.
2281193326Sed *
2282193326Sed * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t       decibels (dB)
2283193326Sed *
2284193326Sed *      Transmit power expressed as decibel distance from max power
2285193326Sed *      set at factory calibration.  0 is max power.  Monotonically
2286193326Sed *      nondecreasing with lower power levels.
2287193326Sed *
2288193326Sed * IEEE80211_RADIOTAP_DBM_TX_POWER      int8_t          decibels from
2289193326Sed *                                                      one milliwatt (dBm)
2290193326Sed *
2291193326Sed *      Transmit power expressed as dBm (decibels from a 1 milliwatt
2292193326Sed *      reference). This is the absolute power level measured at
2293193326Sed *      the antenna port.
2294193326Sed *
2295193326Sed * IEEE80211_RADIOTAP_FLAGS             uint8_t        bitmap
2296193326Sed *
2297193326Sed *      Properties of transmitted and received frames. See flags
2298193326Sed *      defined below.
2299193326Sed *
2300193326Sed * IEEE80211_RADIOTAP_ANTENNA           uint8_t        antenna index
2301193576Sed *
2302193326Sed *      Unitless indication of the Rx/Tx antenna for this packet.
2303194179Sed *      The first antenna is antenna 0.
2304193326Sed *
2305193326Sed * IEEE80211_RADIOTAP_RX_FLAGS          uint16_t       bitmap
2306193326Sed *
2307194613Sed *     Properties of received frames. See flags defined below.
2308193326Sed *
2309193326Sed * IEEE80211_RADIOTAP_XCHANNEL          uint32_t	bitmap
2310193326Sed *					uint16_t	MHz
2311193326Sed *					uint8_t		channel number
2312193326Sed *					uint8_t		.5 dBm
2313193326Sed *
2314194179Sed *	Extended channel specification: flags (see below) followed by
2315194179Sed *	frequency in MHz, the corresponding IEEE channel number, and
2316194179Sed *	finally the maximum regulatory transmit power cap in .5 dBm
2317194179Sed *	units.  This property supersedes IEEE80211_RADIOTAP_CHANNEL
2318194179Sed *	and only one of the two should be present.
2319194179Sed *
2320194179Sed * IEEE80211_RADIOTAP_MCS		uint8_t		known
2321194179Sed *					uint8_t		flags
2322194179Sed *					uint8_t		mcs
2323194179Sed *
2324194179Sed *	Bitset indicating which fields have known values, followed
2325194179Sed *	by bitset of flag values, followed by the MCS rate index as
2326194179Sed *	in IEEE 802.11n.
2327194179Sed *
2328194179Sed *
2329194179Sed * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless
2330194179Sed *
2331194179Sed *	Contains the AMPDU information for the subframe.
2332194179Sed *
2333194179Sed * IEEE80211_RADIOTAP_VHT	u16, u8, u8, u8[4], u8, u8, u16
2334194179Sed *
2335194179Sed *	Contains VHT information about this frame.
2336194179Sed *
2337194179Sed * IEEE80211_RADIOTAP_VENDOR_NAMESPACE
2338194179Sed *					uint8_t  OUI[3]
2339193326Sed *                                   uint8_t  subspace
2340193576Sed *                                   uint16_t length
2341193576Sed *
2342193576Sed *     The Vendor Namespace Field contains three sub-fields. The first
2343194179Sed *     sub-field is 3 bytes long. It contains the vendor's IEEE 802
2344193326Sed *     Organizationally Unique Identifier (OUI). The fourth byte is a
2345193576Sed *     vendor-specific "namespace selector."
2346193576Sed *
2347193576Sed */
2348193326Sedenum ieee80211_radiotap_type {
2349193326Sed	IEEE80211_RADIOTAP_TSFT = 0,
2350193326Sed	IEEE80211_RADIOTAP_FLAGS = 1,
2351193326Sed	IEEE80211_RADIOTAP_RATE = 2,
2352193326Sed	IEEE80211_RADIOTAP_CHANNEL = 3,
2353193326Sed	IEEE80211_RADIOTAP_FHSS = 4,
2354193326Sed	IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
2355193326Sed	IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
2356193326Sed	IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
2357193326Sed	IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
2358193326Sed	IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
2359193326Sed	IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
2360193326Sed	IEEE80211_RADIOTAP_ANTENNA = 11,
2361193326Sed	IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
2362193326Sed	IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
2363193326Sed	IEEE80211_RADIOTAP_RX_FLAGS = 14,
2364193326Sed	/* NB: gap for netbsd definitions */
2365193326Sed	IEEE80211_RADIOTAP_XCHANNEL = 18,
2366194179Sed	IEEE80211_RADIOTAP_MCS = 19,
2367193326Sed	IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
2368193326Sed	IEEE80211_RADIOTAP_VHT = 21,
2369193326Sed	IEEE80211_RADIOTAP_NAMESPACE = 29,
2370193326Sed	IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
2371193326Sed	IEEE80211_RADIOTAP_EXT = 31
2372193326Sed};
2373193326Sed
2374193326Sed/* channel attributes */
2375193326Sed#define	IEEE80211_CHAN_TURBO	0x00010	/* Turbo channel */
2376193326Sed#define	IEEE80211_CHAN_CCK	0x00020	/* CCK channel */
2377193326Sed#define	IEEE80211_CHAN_OFDM	0x00040	/* OFDM channel */
2378193326Sed#define	IEEE80211_CHAN_2GHZ	0x00080	/* 2 GHz spectrum channel. */
2379193326Sed#define	IEEE80211_CHAN_5GHZ	0x00100	/* 5 GHz spectrum channel */
2380193326Sed#define	IEEE80211_CHAN_PASSIVE	0x00200	/* Only passive scan allowed */
2381193326Sed#define	IEEE80211_CHAN_DYN	0x00400	/* Dynamic CCK-OFDM channel */
2382193326Sed#define	IEEE80211_CHAN_GFSK	0x00800	/* GFSK channel (FHSS PHY) */
2383193326Sed#define	IEEE80211_CHAN_GSM	0x01000	/* 900 MHz spectrum channel */
2384193326Sed#define	IEEE80211_CHAN_STURBO	0x02000	/* 11a static turbo channel only */
2385193326Sed#define	IEEE80211_CHAN_HALF	0x04000	/* Half rate channel */
2386193326Sed#define	IEEE80211_CHAN_QUARTER	0x08000	/* Quarter rate channel */
2387193576Sed#define	IEEE80211_CHAN_HT20	0x10000	/* HT 20 channel */
2388193576Sed#define	IEEE80211_CHAN_HT40U	0x20000	/* HT 40 channel w/ ext above */
2389193576Sed#define	IEEE80211_CHAN_HT40D	0x40000	/* HT 40 channel w/ ext below */
2390193576Sed
2391193576Sed/* Useful combinations of channel characteristics, borrowed from Ethereal */
2392193326Sed#define IEEE80211_CHAN_A \
2393193326Sed        (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
2394193326Sed#define IEEE80211_CHAN_B \
2395193326Sed        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
2396193326Sed#define IEEE80211_CHAN_G \
2397193326Sed        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2398193326Sed#define IEEE80211_CHAN_TA \
2399193326Sed        (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
2400194179Sed#define IEEE80211_CHAN_TG \
2401194179Sed        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN  | IEEE80211_CHAN_TURBO)
2402194179Sed
2403194179Sed
2404194179Sed/* For IEEE80211_RADIOTAP_FLAGS */
2405194179Sed#define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
2406194179Sed						 * during CFP
2407194179Sed						 */
2408194179Sed#define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
2409194179Sed						 * with short
2410194179Sed						 * preamble
2411194179Sed						 */
2412194179Sed#define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
2413194179Sed						 * with WEP encryption
2414194179Sed						 */
2415194179Sed#define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
2416194179Sed						 * with fragmentation
2417194179Sed						 */
2418194179Sed#define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
2419194179Sed#define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
2420194179Sed						 * 802.11 header and payload
2421194179Sed						 * (to 32-bit boundary)
2422194179Sed						 */
2423194179Sed#define	IEEE80211_RADIOTAP_F_BADFCS	0x40	/* does not pass FCS check */
2424194179Sed
2425194179Sed/* For IEEE80211_RADIOTAP_RX_FLAGS */
2426194179Sed#define IEEE80211_RADIOTAP_F_RX_BADFCS	0x0001	/* frame failed crc check */
2427194179Sed#define IEEE80211_RADIOTAP_F_RX_PLCP_CRC	0x0002	/* frame failed PLCP CRC check */
2428194179Sed
2429194179Sed/* For IEEE80211_RADIOTAP_MCS known */
2430194179Sed#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN		0x01
2431194179Sed#define IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN		0x02	/* MCS index field */
2432193326Sed#define IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN	0x04
2433193326Sed#define IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN		0x08
2434193326Sed#define IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN		0x10
2435193326Sed#define IEEE80211_RADIOTAP_MCS_STBC_KNOWN		0x20
2436193326Sed#define IEEE80211_RADIOTAP_MCS_NESS_KNOWN		0x40
2437193326Sed#define IEEE80211_RADIOTAP_MCS_NESS_BIT_1		0x80
2438193326Sed
2439193576Sed/* For IEEE80211_RADIOTAP_MCS flags */
2440193576Sed#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK	0x03
2441193326Sed#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20	0
2442193326Sed#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_40	1
2443193326Sed#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20L	2
2444193326Sed#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20U	3
2445193326Sed#define IEEE80211_RADIOTAP_MCS_SHORT_GI		0x04 /* short guard interval */
2446193326Sed#define IEEE80211_RADIOTAP_MCS_HT_GREENFIELD	0x08
2447193326Sed#define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10
2448193326Sed#define IEEE80211_RADIOTAP_MCS_STBC_MASK	0x60
2449193326Sed#define		IEEE80211_RADIOTAP_MCS_STBC_1	1
2450193326Sed#define		IEEE80211_RADIOTAP_MCS_STBC_2	2
2451193326Sed#define		IEEE80211_RADIOTAP_MCS_STBC_3	3
2452193326Sed#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT	5
2453193326Sed#define IEEE80211_RADIOTAP_MCS_NESS_BIT_0	0x80
2454193326Sed
2455193326Sed/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
2456193326Sed#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN		0x0001
2457193326Sed#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN		0x0002
2458193326Sed#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN		0x0004
2459193326Sed#define IEEE80211_RADIOTAP_AMPDU_IS_LAST		0x0008
2460193326Sed#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR		0x0010
2461193326Sed#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN	0x0020
2462193326Sed
2463193326Sed/* For IEEE80211_RADIOTAP_VHT known */
2464193326Sed#define IEEE80211_RADIOTAP_VHT_STBC_KNOWN			0x0001
2465193326Sed#define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA_KNOWN			0x0002
2466193326Sed#define IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN		0x0004
2467193326Sed#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_DIS_KNOWN		0x0008
2468193326Sed#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM_KNOWN	0x0010
2469193326Sed#define IEEE80211_RADIOTAP_VHT_BEAMFORMED_KNOWN			0x0020
2470193326Sed#define IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN			0x0040
2471193326Sed#define IEEE80211_RADIOTAP_VHT_GROUP_ID_KNOWN			0x0080
2472193326Sed#define IEEE80211_RADIOTAP_VHT_PARTIAL_AID_KNOWN		0x0100
2473193326Sed
2474193326Sed/* For IEEE80211_RADIOTAP_VHT flags */
2475193326Sed#define IEEE80211_RADIOTAP_VHT_STBC			0x01
2476193326Sed#define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA		0x02
2477193326Sed#define IEEE80211_RADIOTAP_VHT_SHORT_GI			0x04
2478194179Sed#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_M10_9		0x08
2479193326Sed#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM	0x10
2480193326Sed#define IEEE80211_RADIOTAP_VHT_BEAMFORMED		0x20
2481193326Sed
2482193326Sed#define IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK	0x1f
2483193326Sed
2484193326Sed#define IEEE80211_RADIOTAP_VHT_NSS_MASK		0x0f
2485193326Sed#define IEEE80211_RADIOTAP_VHT_MCS_MASK		0xf0
2486193326Sed#define IEEE80211_RADIOTAP_VHT_MCS_SHIFT	4
2487193326Sed
2488193326Sed#define IEEE80211_RADIOTAP_CODING_LDPC_USERn			0x01
2489193326Sed
2490193326Sed#define	IEEE80211_CHAN_FHSS \
2491193326Sed	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
2492193326Sed#define	IEEE80211_CHAN_A \
2493193326Sed	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
2494193326Sed#define	IEEE80211_CHAN_B \
2495193326Sed	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
2496193326Sed#define	IEEE80211_CHAN_PUREG \
2497193326Sed	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
2498193326Sed#define	IEEE80211_CHAN_G \
2499193326Sed	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2500193326Sed
2501193326Sed#define	IS_CHAN_FHSS(flags) \
2502193326Sed	((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
2503193326Sed#define	IS_CHAN_A(flags) \
2504193326Sed	((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
2505193326Sed#define	IS_CHAN_B(flags) \
2506193326Sed	((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
2507193326Sed#define	IS_CHAN_PUREG(flags) \
2508193326Sed	((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
2509193326Sed#define	IS_CHAN_G(flags) \
2510193326Sed	((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
2511193326Sed#define	IS_CHAN_ANYG(flags) \
2512193326Sed	(IS_CHAN_PUREG(flags) || IS_CHAN_G(flags))
2513193326Sed
2514193326Sedstatic void
2515193326Sedprint_chaninfo(netdissect_options *ndo,
2516193326Sed               uint16_t freq, int flags, int presentflags)
2517193326Sed{
2518193326Sed	ND_PRINT((ndo, "%u MHz", freq));
2519193326Sed	if (presentflags & (1 << IEEE80211_RADIOTAP_MCS)) {
2520193326Sed		/*
2521193326Sed		 * We have the MCS field, so this is 11n, regardless
2522193326Sed		 * of what the channel flags say.
2523193326Sed		 */
2524193326Sed		ND_PRINT((ndo, " 11n"));
2525193326Sed	} else {
2526193326Sed		if (IS_CHAN_FHSS(flags))
2527193326Sed			ND_PRINT((ndo, " FHSS"));
2528193326Sed		if (IS_CHAN_A(flags)) {
2529193326Sed			if (flags & IEEE80211_CHAN_HALF)
2530193326Sed				ND_PRINT((ndo, " 11a/10Mhz"));
2531193326Sed			else if (flags & IEEE80211_CHAN_QUARTER)
2532193326Sed				ND_PRINT((ndo, " 11a/5Mhz"));
2533193326Sed			else
2534193326Sed				ND_PRINT((ndo, " 11a"));
2535193326Sed		}
2536193326Sed		if (IS_CHAN_ANYG(flags)) {
2537193326Sed			if (flags & IEEE80211_CHAN_HALF)
2538193326Sed				ND_PRINT((ndo, " 11g/10Mhz"));
2539193326Sed			else if (flags & IEEE80211_CHAN_QUARTER)
2540193326Sed				ND_PRINT((ndo, " 11g/5Mhz"));
2541193326Sed			else
2542193326Sed				ND_PRINT((ndo, " 11g"));
2543193326Sed		} else if (IS_CHAN_B(flags))
2544193326Sed			ND_PRINT((ndo, " 11b"));
2545193326Sed		if (flags & IEEE80211_CHAN_TURBO)
2546193326Sed			ND_PRINT((ndo, " Turbo"));
2547193326Sed	}
2548193326Sed	/*
2549193326Sed	 * These apply to 11n.
2550193326Sed	 */
2551193326Sed	if (flags & IEEE80211_CHAN_HT20)
2552194179Sed		ND_PRINT((ndo, " ht/20"));
2553193326Sed	else if (flags & IEEE80211_CHAN_HT40D)
2554193326Sed		ND_PRINT((ndo, " ht/40-"));
2555193326Sed	else if (flags & IEEE80211_CHAN_HT40U)
2556193326Sed		ND_PRINT((ndo, " ht/40+"));
2557193326Sed	ND_PRINT((ndo, " "));
2558193326Sed}
2559193326Sed
2560193326Sedstatic int
2561193326Sedprint_radiotap_field(netdissect_options *ndo,
2562193576Sed                     struct cpack_state *s, uint32_t bit, uint8_t *flagsp,
2563193326Sed                     uint32_t presentflags)
2564193576Sed{
2565193326Sed	u_int i;
2566193326Sed	int rc;
2567193326Sed
2568194613Sed	switch (bit) {
2569193326Sed
2570193326Sed	case IEEE80211_RADIOTAP_TSFT: {
2571193326Sed		uint64_t tsft;
2572193326Sed
2573193326Sed		rc = cpack_uint64(s, &tsft);
2574193326Sed		if (rc != 0)
2575193576Sed			goto trunc;
2576193576Sed		ND_PRINT((ndo, "%" PRIu64 "us tsft ", tsft));
2577193576Sed		break;
2578193326Sed		}
2579193326Sed
2580193326Sed	case IEEE80211_RADIOTAP_FLAGS: {
2581193326Sed		uint8_t flagsval;
2582193326Sed
2583193326Sed		rc = cpack_uint8(s, &flagsval);
2584193326Sed		if (rc != 0)
2585193326Sed			goto trunc;
2586193326Sed		*flagsp = flagsval;
2587193326Sed		if (flagsval & IEEE80211_RADIOTAP_F_CFP)
2588193326Sed			ND_PRINT((ndo, "cfp "));
2589193326Sed		if (flagsval & IEEE80211_RADIOTAP_F_SHORTPRE)
2590193326Sed			ND_PRINT((ndo, "short preamble "));
2591193326Sed		if (flagsval & IEEE80211_RADIOTAP_F_WEP)
2592193326Sed			ND_PRINT((ndo, "wep "));
2593193326Sed		if (flagsval & IEEE80211_RADIOTAP_F_FRAG)
2594193326Sed			ND_PRINT((ndo, "fragmented "));
2595193326Sed		if (flagsval & IEEE80211_RADIOTAP_F_BADFCS)
2596193326Sed			ND_PRINT((ndo, "bad-fcs "));
2597193326Sed		break;
2598193326Sed		}
2599193326Sed
2600193326Sed	case IEEE80211_RADIOTAP_RATE: {
2601193326Sed		uint8_t rate;
2602193326Sed
2603193326Sed		rc = cpack_uint8(s, &rate);
2604193326Sed		if (rc != 0)
2605193326Sed			goto trunc;
2606193326Sed		/*
2607193326Sed		 * XXX On FreeBSD rate & 0x80 means we have an MCS. On
2608193326Sed		 * Linux and AirPcap it does not.  (What about
2609193326Sed		 * Mac OS X, NetBSD, OpenBSD, and DragonFly BSD?)
2610193326Sed		 *
2611193326Sed		 * This is an issue either for proprietary extensions
2612193326Sed		 * to 11a or 11g, which do exist, or for 11n
2613193326Sed		 * implementations that stuff a rate value into
2614193326Sed		 * this field, which also appear to exist.
2615193326Sed		 *
2616193326Sed		 * We currently handle that by assuming that
2617193326Sed		 * if the 0x80 bit is set *and* the remaining
2618193326Sed		 * bits have a value between 0 and 15 it's
2619193326Sed		 * an MCS value, otherwise it's a rate.  If
2620193576Sed		 * there are cases where systems that use
2621193326Sed		 * "0x80 + MCS index" for MCS indices > 15,
2622193326Sed		 * or stuff a rate value here between 64 and
2623193326Sed		 * 71.5 Mb/s in here, we'll need a preference
2624193326Sed		 * setting.  Such rates do exist, e.g. 11n
2625193326Sed		 * MCS 7 at 20 MHz with a long guard interval.
2626193326Sed		 */
2627193326Sed		if (rate >= 0x80 && rate <= 0x8f) {
2628193326Sed			/*
2629193326Sed			 * XXX - we don't know the channel width
2630193326Sed			 * or guard interval length, so we can't
2631193326Sed			 * convert this to a data rate.
2632193326Sed			 *
2633193326Sed			 * If you want us to show a data rate,
2634193326Sed			 * use the MCS field, not the Rate field;
2635193326Sed			 * the MCS field includes not only the
2636193326Sed			 * MCS index, it also includes bandwidth
2637193326Sed			 * and guard interval information.
2638193326Sed			 *
2639193326Sed			 * XXX - can we get the channel width
2640193326Sed			 * from XChannel and the guard interval
2641193326Sed			 * information from Flags, at least on
2642193326Sed			 * FreeBSD?
2643193326Sed			 */
2644193326Sed			ND_PRINT((ndo, "MCS %u ", rate & 0x7f));
2645193326Sed		} else
2646193576Sed			ND_PRINT((ndo, "%2.1f Mb/s ", .5 * rate));
2647193326Sed		break;
2648193326Sed		}
2649193326Sed
2650193326Sed	case IEEE80211_RADIOTAP_CHANNEL: {
2651193326Sed		uint16_t frequency;
2652193326Sed		uint16_t flags;
2653193326Sed
2654193326Sed		rc = cpack_uint16(s, &frequency);
2655193326Sed		if (rc != 0)
2656193326Sed			goto trunc;
2657193326Sed		rc = cpack_uint16(s, &flags);
2658193326Sed		if (rc != 0)
2659193326Sed			goto trunc;
2660193326Sed		/*
2661193576Sed		 * If CHANNEL and XCHANNEL are both present, skip
2662193326Sed		 * CHANNEL.
2663193326Sed		 */
2664193326Sed		if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL))
2665193326Sed			break;
2666193326Sed		print_chaninfo(ndo, frequency, flags, presentflags);
2667193326Sed		break;
2668193326Sed		}
2669193326Sed
2670193326Sed	case IEEE80211_RADIOTAP_FHSS: {
2671193326Sed		uint8_t hopset;
2672193326Sed		uint8_t hoppat;
2673193326Sed
2674193326Sed		rc = cpack_uint8(s, &hopset);
2675193326Sed		if (rc != 0)
2676193326Sed			goto trunc;
2677193326Sed		rc = cpack_uint8(s, &hoppat);
2678193326Sed		if (rc != 0)
2679193326Sed			goto trunc;
2680193326Sed		ND_PRINT((ndo, "fhset %d fhpat %d ", hopset, hoppat));
2681193326Sed		break;
2682193326Sed		}
2683193326Sed
2684193326Sed	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: {
2685193326Sed		int8_t dbm_antsignal;
2686193326Sed
2687193326Sed		rc = cpack_int8(s, &dbm_antsignal);
2688193326Sed		if (rc != 0)
2689193326Sed			goto trunc;
2690193326Sed		ND_PRINT((ndo, "%ddBm signal ", dbm_antsignal));
2691193326Sed		break;
2692193326Sed		}
2693193326Sed
2694193326Sed	case IEEE80211_RADIOTAP_DBM_ANTNOISE: {
2695193326Sed		int8_t dbm_antnoise;
2696193326Sed
2697193326Sed		rc = cpack_int8(s, &dbm_antnoise);
2698193326Sed		if (rc != 0)
2699193326Sed			goto trunc;
2700193326Sed		ND_PRINT((ndo, "%ddBm noise ", dbm_antnoise));
2701193326Sed		break;
2702193326Sed		}
2703193326Sed
2704193326Sed	case IEEE80211_RADIOTAP_LOCK_QUALITY: {
2705193326Sed		uint16_t lock_quality;
2706193326Sed
2707193326Sed		rc = cpack_uint16(s, &lock_quality);
2708193326Sed		if (rc != 0)
2709193326Sed			goto trunc;
2710193326Sed		ND_PRINT((ndo, "%u sq ", lock_quality));
2711193326Sed		break;
2712193326Sed		}
2713193326Sed
2714193326Sed	case IEEE80211_RADIOTAP_TX_ATTENUATION: {
2715193326Sed		uint16_t tx_attenuation;
2716193326Sed
2717193326Sed		rc = cpack_uint16(s, &tx_attenuation);
2718193326Sed		if (rc != 0)
2719193326Sed			goto trunc;
2720193326Sed		ND_PRINT((ndo, "%d tx power ", -(int)tx_attenuation));
2721193326Sed		break;
2722193326Sed		}
2723193326Sed
2724193326Sed	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: {
2725193326Sed		uint8_t db_tx_attenuation;
2726193326Sed
2727193326Sed		rc = cpack_uint8(s, &db_tx_attenuation);
2728193326Sed		if (rc != 0)
2729193326Sed			goto trunc;
2730193326Sed		ND_PRINT((ndo, "%ddB tx attenuation ", -(int)db_tx_attenuation));
2731193326Sed		break;
2732193326Sed		}
2733193326Sed
2734193326Sed	case IEEE80211_RADIOTAP_DBM_TX_POWER: {
2735193326Sed		int8_t dbm_tx_power;
2736193326Sed
2737193326Sed		rc = cpack_int8(s, &dbm_tx_power);
2738193326Sed		if (rc != 0)
2739193326Sed			goto trunc;
2740193326Sed		ND_PRINT((ndo, "%ddBm tx power ", dbm_tx_power));
2741193326Sed		break;
2742193326Sed		}
2743193326Sed
2744193326Sed	case IEEE80211_RADIOTAP_ANTENNA: {
2745193326Sed		uint8_t antenna;
2746193326Sed
2747193326Sed		rc = cpack_uint8(s, &antenna);
2748193326Sed		if (rc != 0)
2749193326Sed			goto trunc;
2750193326Sed		ND_PRINT((ndo, "antenna %u ", antenna));
2751193326Sed		break;
2752193326Sed		}
2753193326Sed
2754193326Sed	case IEEE80211_RADIOTAP_DB_ANTSIGNAL: {
2755193326Sed		uint8_t db_antsignal;
2756193326Sed
2757193326Sed		rc = cpack_uint8(s, &db_antsignal);
2758193326Sed		if (rc != 0)
2759193326Sed			goto trunc;
2760193326Sed		ND_PRINT((ndo, "%ddB signal ", db_antsignal));
2761193326Sed		break;
2762193326Sed		}
2763193326Sed
2764193326Sed	case IEEE80211_RADIOTAP_DB_ANTNOISE: {
2765193326Sed		uint8_t db_antnoise;
2766193326Sed
2767193326Sed		rc = cpack_uint8(s, &db_antnoise);
2768193326Sed		if (rc != 0)
2769193326Sed			goto trunc;
2770193326Sed		ND_PRINT((ndo, "%ddB noise ", db_antnoise));
2771193326Sed		break;
2772193326Sed		}
2773193326Sed
2774193326Sed	case IEEE80211_RADIOTAP_RX_FLAGS: {
2775193326Sed		uint16_t rx_flags;
2776193326Sed
2777193326Sed		rc = cpack_uint16(s, &rx_flags);
2778193326Sed		if (rc != 0)
2779193326Sed			goto trunc;
2780193326Sed		/* Do nothing for now */
2781193326Sed		break;
2782193326Sed		}
2783193326Sed
2784193326Sed	case IEEE80211_RADIOTAP_XCHANNEL: {
2785193326Sed		uint32_t flags;
2786193326Sed		uint16_t frequency;
2787193326Sed		uint8_t channel;
2788193326Sed		uint8_t maxpower;
2789193326Sed
2790193326Sed		rc = cpack_uint32(s, &flags);
2791193326Sed		if (rc != 0)
2792193326Sed			goto trunc;
2793193326Sed		rc = cpack_uint16(s, &frequency);
2794193326Sed		if (rc != 0)
2795193326Sed			goto trunc;
2796193326Sed		rc = cpack_uint8(s, &channel);
2797193326Sed		if (rc != 0)
2798193326Sed			goto trunc;
2799193326Sed		rc = cpack_uint8(s, &maxpower);
2800193326Sed		if (rc != 0)
2801193326Sed			goto trunc;
2802193326Sed		print_chaninfo(ndo, frequency, flags, presentflags);
2803193326Sed		break;
2804193326Sed		}
2805193326Sed
2806193326Sed	case IEEE80211_RADIOTAP_MCS: {
2807193326Sed		uint8_t known;
2808193326Sed		uint8_t flags;
2809193326Sed		uint8_t mcs_index;
2810193326Sed		static const char *ht_bandwidth[4] = {
2811193326Sed			"20 MHz",
2812193326Sed			"40 MHz",
2813193326Sed			"20 MHz (L)",
2814193326Sed			"20 MHz (U)"
2815193326Sed		};
2816193326Sed		float htrate;
2817193326Sed
2818193326Sed		rc = cpack_uint8(s, &known);
2819193326Sed		if (rc != 0)
2820193326Sed			goto trunc;
2821193326Sed		rc = cpack_uint8(s, &flags);
2822193326Sed		if (rc != 0)
2823193326Sed			goto trunc;
2824193326Sed		rc = cpack_uint8(s, &mcs_index);
2825193326Sed		if (rc != 0)
2826193326Sed			goto trunc;
2827193326Sed		if (known & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) {
2828193326Sed			/*
2829193326Sed			 * We know the MCS index.
2830193326Sed			 */
2831193326Sed			if (mcs_index <= MAX_MCS_INDEX) {
2832193326Sed				/*
2833193326Sed				 * And it's in-range.
2834193326Sed				 */
2835193326Sed				if (known & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) {
2836193326Sed					/*
2837193326Sed					 * And we know both the bandwidth and
2838193326Sed					 * the guard interval, so we can look
2839193326Sed					 * up the rate.
2840193326Sed					 */
2841193326Sed					htrate =
2842193326Sed						ieee80211_float_htrates \
2843193326Sed							[mcs_index] \
2844193326Sed							[((flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)] \
2845193326Sed							[((flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)];
2846193326Sed				} else {
2847193326Sed					/*
2848193326Sed					 * We don't know both the bandwidth
2849193326Sed					 * and the guard interval, so we can
2850193326Sed					 * only report the MCS index.
2851193326Sed					 */
2852193326Sed					htrate = 0.0;
2853193326Sed				}
2854193326Sed			} else {
2855193326Sed				/*
2856193326Sed				 * The MCS value is out of range.
2857193326Sed				 */
2858193326Sed				htrate = 0.0;
2859193326Sed			}
2860193326Sed			if (htrate != 0.0) {
2861193326Sed				/*
2862193326Sed				 * We have the rate.
2863193326Sed				 * Print it.
2864193326Sed				 */
2865193326Sed				ND_PRINT((ndo, "%.1f Mb/s MCS %u ", htrate, mcs_index));
2866193326Sed			} else {
2867				/*
2868				 * We at least have the MCS index.
2869				 * Print it.
2870				 */
2871				ND_PRINT((ndo, "MCS %u ", mcs_index));
2872			}
2873		}
2874		if (known & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) {
2875			ND_PRINT((ndo, "%s ",
2876				ht_bandwidth[flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK]));
2877		}
2878		if (known & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) {
2879			ND_PRINT((ndo, "%s GI ",
2880				(flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ?
2881				"short" : "long"));
2882		}
2883		if (known & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) {
2884			ND_PRINT((ndo, "%s ",
2885				(flags & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ?
2886				"greenfield" : "mixed"));
2887		}
2888		if (known & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) {
2889			ND_PRINT((ndo, "%s FEC ",
2890				(flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ?
2891				"LDPC" : "BCC"));
2892		}
2893		if (known & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) {
2894			ND_PRINT((ndo, "RX-STBC%u ",
2895				(flags & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT));
2896		}
2897		break;
2898		}
2899
2900	case IEEE80211_RADIOTAP_AMPDU_STATUS: {
2901		uint32_t reference_num;
2902		uint16_t flags;
2903		uint8_t delim_crc;
2904		uint8_t reserved;
2905
2906		rc = cpack_uint32(s, &reference_num);
2907		if (rc != 0)
2908			goto trunc;
2909		rc = cpack_uint16(s, &flags);
2910		if (rc != 0)
2911			goto trunc;
2912		rc = cpack_uint8(s, &delim_crc);
2913		if (rc != 0)
2914			goto trunc;
2915		rc = cpack_uint8(s, &reserved);
2916		if (rc != 0)
2917			goto trunc;
2918		/* Do nothing for now */
2919		break;
2920		}
2921
2922	case IEEE80211_RADIOTAP_VHT: {
2923		uint16_t known;
2924		uint8_t flags;
2925		uint8_t bandwidth;
2926		uint8_t mcs_nss[4];
2927		uint8_t coding;
2928		uint8_t group_id;
2929		uint16_t partial_aid;
2930		static const char *vht_bandwidth[32] = {
2931			"20 MHz",
2932			"40 MHz",
2933			"20 MHz (L)",
2934			"20 MHz (U)",
2935			"80 MHz",
2936			"80 MHz (L)",
2937			"80 MHz (U)",
2938			"80 MHz (LL)",
2939			"80 MHz (LU)",
2940			"80 MHz (UL)",
2941			"80 MHz (UU)",
2942			"160 MHz",
2943			"160 MHz (L)",
2944			"160 MHz (U)",
2945			"160 MHz (LL)",
2946			"160 MHz (LU)",
2947			"160 MHz (UL)",
2948			"160 MHz (UU)",
2949			"160 MHz (LLL)",
2950			"160 MHz (LLU)",
2951			"160 MHz (LUL)",
2952			"160 MHz (UUU)",
2953			"160 MHz (ULL)",
2954			"160 MHz (ULU)",
2955			"160 MHz (UUL)",
2956			"160 MHz (UUU)",
2957			"unknown (26)",
2958			"unknown (27)",
2959			"unknown (28)",
2960			"unknown (29)",
2961			"unknown (30)",
2962			"unknown (31)"
2963		};
2964
2965		rc = cpack_uint16(s, &known);
2966		if (rc != 0)
2967			goto trunc;
2968		rc = cpack_uint8(s, &flags);
2969		if (rc != 0)
2970			goto trunc;
2971		rc = cpack_uint8(s, &bandwidth);
2972		if (rc != 0)
2973			goto trunc;
2974		for (i = 0; i < 4; i++) {
2975			rc = cpack_uint8(s, &mcs_nss[i]);
2976			if (rc != 0)
2977				goto trunc;
2978		}
2979		rc = cpack_uint8(s, &coding);
2980		if (rc != 0)
2981			goto trunc;
2982		rc = cpack_uint8(s, &group_id);
2983		if (rc != 0)
2984			goto trunc;
2985		rc = cpack_uint16(s, &partial_aid);
2986		if (rc != 0)
2987			goto trunc;
2988		for (i = 0; i < 4; i++) {
2989			u_int nss, mcs;
2990			nss = mcs_nss[i] & IEEE80211_RADIOTAP_VHT_NSS_MASK;
2991			mcs = (mcs_nss[i] & IEEE80211_RADIOTAP_VHT_MCS_MASK) >> IEEE80211_RADIOTAP_VHT_MCS_SHIFT;
2992
2993			if (nss == 0)
2994				continue;
2995
2996			ND_PRINT((ndo, "User %u MCS %u ", i, mcs));
2997			ND_PRINT((ndo, "%s FEC ",
2998				(coding & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ?
2999				"LDPC" : "BCC"));
3000		}
3001		if (known & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) {
3002			ND_PRINT((ndo, "%s ",
3003				vht_bandwidth[bandwidth & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK]));
3004		}
3005		if (known & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) {
3006			ND_PRINT((ndo, "%s GI ",
3007				(flags & IEEE80211_RADIOTAP_VHT_SHORT_GI) ?
3008				"short" : "long"));
3009		}
3010		break;
3011		}
3012
3013	default:
3014		/* this bit indicates a field whose
3015		 * size we do not know, so we cannot
3016		 * proceed.  Just print the bit number.
3017		 */
3018		ND_PRINT((ndo, "[bit %u] ", bit));
3019		return -1;
3020	}
3021
3022	return 0;
3023
3024trunc:
3025	ND_PRINT((ndo, "%s", tstr));
3026	return rc;
3027}
3028
3029
3030static int
3031print_in_radiotap_namespace(netdissect_options *ndo,
3032                            struct cpack_state *s, uint8_t *flags,
3033                            uint32_t presentflags, int bit0)
3034{
3035#define	BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
3036#define	BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
3037#define	BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
3038#define	BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
3039#define	BITNO_2(x) (((x) & 2) ? 1 : 0)
3040	uint32_t present, next_present;
3041	int bitno;
3042	enum ieee80211_radiotap_type bit;
3043	int rc;
3044
3045	for (present = presentflags; present; present = next_present) {
3046		/*
3047		 * Clear the least significant bit that is set.
3048		 */
3049		next_present = present & (present - 1);
3050
3051		/*
3052		 * Get the bit number, within this presence word,
3053		 * of the remaining least significant bit that
3054		 * is set.
3055		 */
3056		bitno = BITNO_32(present ^ next_present);
3057
3058		/*
3059		 * Stop if this is one of the "same meaning
3060		 * in all presence flags" bits.
3061		 */
3062		if (bitno >= IEEE80211_RADIOTAP_NAMESPACE)
3063			break;
3064
3065		/*
3066		 * Get the radiotap bit number of that bit.
3067		 */
3068		bit = (enum ieee80211_radiotap_type)(bit0 + bitno);
3069
3070		rc = print_radiotap_field(ndo, s, bit, flags, presentflags);
3071		if (rc != 0)
3072			return rc;
3073	}
3074
3075	return 0;
3076}
3077
3078u_int
3079ieee802_11_radio_print(netdissect_options *ndo,
3080                       const u_char *p, u_int length, u_int caplen)
3081{
3082#define	BIT(n)	(1U << n)
3083#define	IS_EXTENDED(__p)	\
3084	    (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
3085
3086	struct cpack_state cpacker;
3087	const struct ieee80211_radiotap_header *hdr;
3088	uint32_t presentflags;
3089	const uint32_t *presentp, *last_presentp;
3090	int vendor_namespace;
3091	uint8_t vendor_oui[3];
3092	uint8_t vendor_subnamespace;
3093	uint16_t skip_length;
3094	int bit0;
3095	u_int len;
3096	uint8_t flags;
3097	int pad;
3098	u_int fcslen;
3099
3100	if (caplen < sizeof(*hdr)) {
3101		ND_PRINT((ndo, "%s", tstr));
3102		return caplen;
3103	}
3104
3105	hdr = (const struct ieee80211_radiotap_header *)p;
3106
3107	len = EXTRACT_LE_16BITS(&hdr->it_len);
3108	if (len < sizeof(*hdr)) {
3109		/*
3110		 * The length is the length of the entire header, so
3111		 * it must be as large as the fixed-length part of
3112		 * the header.
3113		 */
3114		ND_PRINT((ndo, "%s", tstr));
3115		return caplen;
3116	}
3117
3118	/*
3119	 * If we don't have the entire radiotap header, just give up.
3120	 */
3121	if (caplen < len) {
3122		ND_PRINT((ndo, "%s", tstr));
3123		return caplen;
3124	}
3125	cpack_init(&cpacker, (const uint8_t *)hdr, len); /* align against header start */
3126	cpack_advance(&cpacker, sizeof(*hdr)); /* includes the 1st bitmap */
3127	for (last_presentp = &hdr->it_present;
3128	     (const u_char*)(last_presentp + 1) <= p + len &&
3129	     IS_EXTENDED(last_presentp);
3130	     last_presentp++)
3131	  cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */
3132
3133	/* are there more bitmap extensions than bytes in header? */
3134	if ((const u_char*)(last_presentp + 1) > p + len) {
3135		ND_PRINT((ndo, "%s", tstr));
3136		return caplen;
3137	}
3138
3139	/*
3140	 * Start out at the beginning of the default radiotap namespace.
3141	 */
3142	bit0 = 0;
3143	vendor_namespace = 0;
3144	memset(vendor_oui, 0, 3);
3145	vendor_subnamespace = 0;
3146	skip_length = 0;
3147	/* Assume no flags */
3148	flags = 0;
3149	/* Assume no Atheros padding between 802.11 header and body */
3150	pad = 0;
3151	/* Assume no FCS at end of frame */
3152	fcslen = 0;
3153	for (presentp = &hdr->it_present; presentp <= last_presentp;
3154	    presentp++) {
3155		presentflags = EXTRACT_LE_32BITS(presentp);
3156
3157		/*
3158		 * If this is a vendor namespace, we don't handle it.
3159		 */
3160		if (vendor_namespace) {
3161			/*
3162			 * Skip past the stuff we don't understand.
3163			 * If we add support for any vendor namespaces,
3164			 * it'd be added here; use vendor_oui and
3165			 * vendor_subnamespace to interpret the fields.
3166			 */
3167			if (cpack_advance(&cpacker, skip_length) != 0) {
3168				/*
3169				 * Ran out of space in the packet.
3170				 */
3171				break;
3172			}
3173
3174			/*
3175			 * We've skipped it all; nothing more to
3176			 * skip.
3177			 */
3178			skip_length = 0;
3179		} else {
3180			if (print_in_radiotap_namespace(ndo, &cpacker,
3181			    &flags, presentflags, bit0) != 0) {
3182				/*
3183				 * Fatal error - can't process anything
3184				 * more in the radiotap header.
3185				 */
3186				break;
3187			}
3188		}
3189
3190		/*
3191		 * Handle the namespace switch bits; we've already handled
3192		 * the extension bit in all but the last word above.
3193		 */
3194		switch (presentflags &
3195		    (BIT(IEEE80211_RADIOTAP_NAMESPACE)|BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE))) {
3196
3197		case 0:
3198			/*
3199			 * We're not changing namespaces.
3200			 * advance to the next 32 bits in the current
3201			 * namespace.
3202			 */
3203			bit0 += 32;
3204			break;
3205
3206		case BIT(IEEE80211_RADIOTAP_NAMESPACE):
3207			/*
3208			 * We're switching to the radiotap namespace.
3209			 * Reset the presence-bitmap index to 0, and
3210			 * reset the namespace to the default radiotap
3211			 * namespace.
3212			 */
3213			bit0 = 0;
3214			vendor_namespace = 0;
3215			memset(vendor_oui, 0, 3);
3216			vendor_subnamespace = 0;
3217			skip_length = 0;
3218			break;
3219
3220		case BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE):
3221			/*
3222			 * We're switching to a vendor namespace.
3223			 * Reset the presence-bitmap index to 0,
3224			 * note that we're in a vendor namespace,
3225			 * and fetch the fields of the Vendor Namespace
3226			 * item.
3227			 */
3228			bit0 = 0;
3229			vendor_namespace = 1;
3230			if ((cpack_align_and_reserve(&cpacker, 2)) == NULL) {
3231				ND_PRINT((ndo, "%s", tstr));
3232				break;
3233			}
3234			if (cpack_uint8(&cpacker, &vendor_oui[0]) != 0) {
3235				ND_PRINT((ndo, "%s", tstr));
3236				break;
3237			}
3238			if (cpack_uint8(&cpacker, &vendor_oui[1]) != 0) {
3239				ND_PRINT((ndo, "%s", tstr));
3240				break;
3241			}
3242			if (cpack_uint8(&cpacker, &vendor_oui[2]) != 0) {
3243				ND_PRINT((ndo, "%s", tstr));
3244				break;
3245			}
3246			if (cpack_uint8(&cpacker, &vendor_subnamespace) != 0) {
3247				ND_PRINT((ndo, "%s", tstr));
3248				break;
3249			}
3250			if (cpack_uint16(&cpacker, &skip_length) != 0) {
3251				ND_PRINT((ndo, "%s", tstr));
3252				break;
3253			}
3254			break;
3255
3256		default:
3257			/*
3258			 * Illegal combination.  The behavior in this
3259			 * case is undefined by the radiotap spec; we
3260			 * just ignore both bits.
3261			 */
3262			break;
3263		}
3264	}
3265
3266	if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
3267		pad = 1;	/* Atheros padding */
3268	if (flags & IEEE80211_RADIOTAP_F_FCS)
3269		fcslen = 4;	/* FCS at end of packet */
3270	return len + ieee802_11_print(ndo, p + len, length - len, caplen - len, pad,
3271	    fcslen);
3272#undef BITNO_32
3273#undef BITNO_16
3274#undef BITNO_8
3275#undef BITNO_4
3276#undef BITNO_2
3277#undef BIT
3278}
3279
3280static u_int
3281ieee802_11_avs_radio_print(netdissect_options *ndo,
3282                           const u_char *p, u_int length, u_int caplen)
3283{
3284	uint32_t caphdr_len;
3285
3286	if (caplen < 8) {
3287		ND_PRINT((ndo, "%s", tstr));
3288		return caplen;
3289	}
3290
3291	caphdr_len = EXTRACT_32BITS(p + 4);
3292	if (caphdr_len < 8) {
3293		/*
3294		 * Yow!  The capture header length is claimed not
3295		 * to be large enough to include even the version
3296		 * cookie or capture header length!
3297		 */
3298		ND_PRINT((ndo, "%s", tstr));
3299		return caplen;
3300	}
3301
3302	if (caplen < caphdr_len) {
3303		ND_PRINT((ndo, "%s", tstr));
3304		return caplen;
3305	}
3306
3307	return caphdr_len + ieee802_11_print(ndo, p + caphdr_len,
3308	    length - caphdr_len, caplen - caphdr_len, 0, 0);
3309}
3310
3311#define PRISM_HDR_LEN		144
3312
3313#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
3314#define WLANCAP_MAGIC_COOKIE_V1	0x80211001
3315#define WLANCAP_MAGIC_COOKIE_V2	0x80211002
3316
3317/*
3318 * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
3319 * containing information such as radio information, which we
3320 * currently ignore.
3321 *
3322 * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or
3323 * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS
3324 * (currently, on Linux, there's no ARPHRD_ type for
3325 * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM
3326 * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for
3327 * the AVS header, and the first 4 bytes of the header are used to
3328 * indicate whether it's a Prism header or an AVS header).
3329 */
3330u_int
3331prism_if_print(netdissect_options *ndo,
3332               const struct pcap_pkthdr *h, const u_char *p)
3333{
3334	u_int caplen = h->caplen;
3335	u_int length = h->len;
3336	uint32_t msgcode;
3337
3338	if (caplen < 4) {
3339		ND_PRINT((ndo, "%s", tstr));
3340		return caplen;
3341	}
3342
3343	msgcode = EXTRACT_32BITS(p);
3344	if (msgcode == WLANCAP_MAGIC_COOKIE_V1 ||
3345	    msgcode == WLANCAP_MAGIC_COOKIE_V2)
3346		return ieee802_11_avs_radio_print(ndo, p, length, caplen);
3347
3348	if (caplen < PRISM_HDR_LEN) {
3349		ND_PRINT((ndo, "%s", tstr));
3350		return caplen;
3351	}
3352
3353	return PRISM_HDR_LEN + ieee802_11_print(ndo, p + PRISM_HDR_LEN,
3354	    length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0, 0);
3355}
3356
3357/*
3358 * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra
3359 * header, containing information such as radio information.
3360 */
3361u_int
3362ieee802_11_radio_if_print(netdissect_options *ndo,
3363                          const struct pcap_pkthdr *h, const u_char *p)
3364{
3365	return ieee802_11_radio_print(ndo, p, h->len, h->caplen);
3366}
3367
3368/*
3369 * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an
3370 * extra header, containing information such as radio information,
3371 * which we currently ignore.
3372 */
3373u_int
3374ieee802_11_radio_avs_if_print(netdissect_options *ndo,
3375                              const struct pcap_pkthdr *h, const u_char *p)
3376{
3377	return ieee802_11_avs_radio_print(ndo, p, h->len, h->caplen);
3378}
3379