print-802_11.c revision 214478
198524Sfenner/*
298524Sfenner * Copyright (c) 2001
398524Sfenner *	Fortress Technologies, Inc.  All rights reserved.
498524Sfenner *      Charlie Lenahan (clenahan@fortresstech.com)
598524Sfenner *
698524Sfenner * Redistribution and use in source and binary forms, with or without
798524Sfenner * modification, are permitted provided that: (1) source code distributions
898524Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
998524Sfenner * distributions including binary code include the above copyright notice and
1098524Sfenner * this paragraph in its entirety in the documentation or other materials
1198524Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1298524Sfenner * features or use of this software display the following acknowledgement:
1398524Sfenner * ``This product includes software developed by the University of California,
1498524Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1598524Sfenner * the University nor the names of its contributors may be used to endorse
1698524Sfenner * or promote products derived from this software without specific prior
1798524Sfenner * written permission.
1898524Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1998524Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2098524Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2198524Sfenner */
2298524Sfenner
2398524Sfenner#ifndef lint
24127668Sbmsstatic const char rcsid[] _U_ =
25214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.49 2007-12-29 23:25:02 guy Exp $ (LBL)";
2698524Sfenner#endif
2798524Sfenner
2898524Sfenner#ifdef HAVE_CONFIG_H
2998524Sfenner#include "config.h"
3098524Sfenner#endif
3198524Sfenner
32127668Sbms#include <tcpdump-stdinc.h>
3398524Sfenner
3498524Sfenner#include <stdio.h>
3598524Sfenner#include <pcap.h>
3698524Sfenner#include <string.h>
3798524Sfenner
3898524Sfenner#include "interface.h"
3998524Sfenner#include "addrtoname.h"
4098524Sfenner#include "ethertype.h"
4198524Sfenner
4298524Sfenner#include "extract.h"
4398524Sfenner
44146773Ssam#include "cpack.h"
45146773Ssam
4698524Sfenner#include "ieee802_11.h"
47146773Ssam#include "ieee802_11_radio.h"
4898524Sfenner
49172686Smlaier#define PRINT_SSID(p) \
50214478Srpaulo	if (p.ssid_present) { \
51172686Smlaier		printf(" ("); \
52172686Smlaier		fn_print(p.ssid.ssid, NULL); \
53172686Smlaier		printf(")"); \
54172686Smlaier	}
55172686Smlaier
56146773Ssam#define PRINT_RATE(_sep, _r, _suf) \
57146773Ssam	printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
58111726Sfenner#define PRINT_RATES(p) \
59214478Srpaulo	if (p.rates_present) { \
60214478Srpaulo		int z; \
61214478Srpaulo		const char *sep = " ["; \
62214478Srpaulo		for (z = 0; z < p.rates.length ; z++) { \
63214478Srpaulo			PRINT_RATE(sep, p.rates.rate[z], \
64214478Srpaulo				(p.rates.rate[z] & 0x80 ? "*" : "")); \
65214478Srpaulo			sep = " "; \
66214478Srpaulo		} \
67214478Srpaulo		if (p.rates.length != 0) \
68214478Srpaulo			printf(" Mbit]"); \
69172686Smlaier	}
70172686Smlaier
71172686Smlaier#define PRINT_DS_CHANNEL(p) \
72214478Srpaulo	if (p.ds_present) \
73172686Smlaier		printf(" CH: %u", p.ds.channel); \
74172686Smlaier	printf("%s", \
75172686Smlaier	    CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" );
7698524Sfenner
77170533Ssamstatic const int ieee80211_htrates[16] = {
78170533Ssam	13,		/* IFM_IEEE80211_MCS0 */
79170533Ssam	26,		/* IFM_IEEE80211_MCS1 */
80170533Ssam	39,		/* IFM_IEEE80211_MCS2 */
81170533Ssam	52,		/* IFM_IEEE80211_MCS3 */
82170533Ssam	78,		/* IFM_IEEE80211_MCS4 */
83170533Ssam	104,		/* IFM_IEEE80211_MCS5 */
84170533Ssam	117,		/* IFM_IEEE80211_MCS6 */
85170533Ssam	130,		/* IFM_IEEE80211_MCS7 */
86170533Ssam	26,		/* IFM_IEEE80211_MCS8 */
87170533Ssam	52,		/* IFM_IEEE80211_MCS9 */
88170533Ssam	78,		/* IFM_IEEE80211_MCS10 */
89170533Ssam	104,		/* IFM_IEEE80211_MCS11 */
90170533Ssam	156,		/* IFM_IEEE80211_MCS12 */
91170533Ssam	208,		/* IFM_IEEE80211_MCS13 */
92170533Ssam	234,		/* IFM_IEEE80211_MCS14 */
93170533Ssam	260,		/* IFM_IEEE80211_MCS15 */
94170533Ssam};
95170533Ssam#define PRINT_HT_RATE(_sep, _r, _suf) \
96170533Ssam	printf("%s%.1f%s", _sep, (.5 * ieee80211_htrates[(_r) & 0xf]), _suf)
97170533Ssam
9898524Sfennerstatic const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
99162017Ssam#define NUM_AUTH_ALGS	(sizeof auth_alg_text / sizeof auth_alg_text[0])
10098524Sfenner
10198524Sfennerstatic const char *status_text[] = {
102195684Ssam	"Succesful",						/*  0 */
103195684Ssam	"Unspecified failure",					/*  1 */
104195684Ssam	"Reserved",						/*  2 */
105195684Ssam	"Reserved",						/*  3 */
106195684Ssam	"Reserved",						/*  4 */
107195684Ssam	"Reserved",						/*  5 */
108195684Ssam	"Reserved",						/*  6 */
109195684Ssam	"Reserved",						/*  7 */
110195684Ssam	"Reserved",						/*  8 */
111195684Ssam	"Reserved",						/*  9 */
112195684Ssam	"Cannot Support all requested capabilities in the Capability "
113195684Ssam	  "Information field",	  				/* 10 */
114195684Ssam	"Reassociation denied due to inability to confirm that association "
115195684Ssam	  "exists",						/* 11 */
116195684Ssam	"Association denied due to reason outside the scope of the "
117195684Ssam	  "standard",						/* 12 */
118195684Ssam	"Responding station does not support the specified authentication "
119195684Ssam	  "algorithm ",						/* 13 */
120195684Ssam	"Received an Authentication frame with authentication transaction "
121195684Ssam	  "sequence number out of expected sequence",		/* 14 */
122195684Ssam	"Authentication rejected because of challenge failure",	/* 15 */
123195684Ssam	"Authentication rejected due to timeout waiting for next frame in "
124195684Ssam	  "sequence",	  					/* 16 */
125195684Ssam	"Association denied because AP is unable to handle additional"
126195684Ssam	  "associated stations",	  			/* 17 */
127195684Ssam	"Association denied due to requesting station not supporting all of "
128195684Ssam	  "the data rates in BSSBasicRateSet parameter",	/* 18 */
129195684Ssam	"Association denied due to requesting station not supporting "
130195684Ssam	  "short preamble operation",				/* 19 */
131195684Ssam	"Association denied due to requesting station not supporting "
132195684Ssam	  "PBCC encoding",					/* 20 */
133195684Ssam	"Association denied due to requesting station not supporting "
134195684Ssam	  "channel agility",					/* 21 */
135195684Ssam	"Association request rejected because Spectrum Management "
136195684Ssam	  "capability is required",				/* 22 */
137195684Ssam	"Association request rejected because the information in the "
138195684Ssam	  "Power Capability element is unacceptable",		/* 23 */
139195684Ssam	"Association request rejected because the information in the "
140195684Ssam	  "Supported Channels element is unacceptable",		/* 24 */
141195684Ssam	"Association denied due to requesting station not supporting "
142195684Ssam	  "short slot operation",				/* 25 */
143195684Ssam	"Association denied due to requesting station not supporting "
144195684Ssam	  "DSSS-OFDM operation",				/* 26 */
145195684Ssam	"Association denied because the requested STA does not support HT "
146195684Ssam	  "features",						/* 27 */
147195684Ssam	"Reserved",						/* 28 */
148195684Ssam	"Association denied because the requested STA does not support "
149195684Ssam	  "the PCO transition time required by the AP",		/* 29 */
150195684Ssam	"Reserved",						/* 30 */
151195684Ssam	"Reserved",						/* 31 */
152195684Ssam	"Unspecified, QoS-related failure",			/* 32 */
153195684Ssam	"Association denied due to QAP having insufficient bandwidth "
154195684Ssam	  "to handle another QSTA",				/* 33 */
155195684Ssam	"Association denied due to excessive frame loss rates and/or "
156195684Ssam	  "poor conditions on current operating channel",	/* 34 */
157195684Ssam	"Association (with QBSS) denied due to requesting station not "
158195684Ssam	  "supporting the QoS facility",			/* 35 */
159195684Ssam	"Association denied due to requesting station not supporting "
160195684Ssam	  "Block Ack",						/* 36 */
161195684Ssam	"The request has been declined",			/* 37 */
162195684Ssam	"The request has not been successful as one or more parameters "
163195684Ssam	  "have invalid values",				/* 38 */
164195684Ssam	"The TS has not been created because the request cannot be honored. "
165195684Ssam	  "However, a suggested TSPEC is provided so that the initiating QSTA"
166195684Ssam	  "may attempt to set another TS with the suggested changes to the "
167195684Ssam	  "TSPEC",						/* 39 */
168195684Ssam	"Invalid Information Element",				/* 40 */
169195684Ssam	"Group Cipher is not valid",				/* 41 */
170195684Ssam	"Pairwise Cipher is not valid",				/* 42 */
171195684Ssam	"AKMP is not valid",					/* 43 */
172195684Ssam	"Unsupported RSN IE version",				/* 44 */
173195684Ssam	"Invalid RSN IE Capabilities",				/* 45 */
174195684Ssam	"Cipher suite is rejected per security policy",		/* 46 */
175195684Ssam	"The TS has not been created. However, the HC may be capable of "
176195684Ssam	  "creating a TS, in response to a request, after the time indicated "
177195684Ssam	  "in the TS Delay element",				/* 47 */
178195684Ssam	"Direct Link is not allowed in the BSS by policy",	/* 48 */
179195684Ssam	"Destination STA is not present within this QBSS.",	/* 49 */
180195684Ssam	"The Destination STA is not a QSTA.",			/* 50 */
181195684Ssam
18298524Sfenner};
183162017Ssam#define NUM_STATUSES	(sizeof status_text / sizeof status_text[0])
18498524Sfenner
18598524Sfennerstatic const char *reason_text[] = {
186195684Ssam	"Reserved",						/* 0 */
187195684Ssam	"Unspecified reason",					/* 1 */
188195684Ssam	"Previous authentication no longer valid",  		/* 2 */
189195684Ssam	"Deauthenticated because sending station is leaving (or has left) "
190195684Ssam	  "IBSS or ESS",					/* 3 */
191195684Ssam	"Disassociated due to inactivity",			/* 4 */
192195684Ssam	"Disassociated because AP is unable to handle all currently "
193195684Ssam	  " associated stations",				/* 5 */
194162017Ssam	"Class 2 frame received from nonauthenticated station", /* 6 */
195195684Ssam	"Class 3 frame received from nonassociated station",	/* 7 */
196195684Ssam	"Disassociated because sending station is leaving "
197195684Ssam	  "(or has left) BSS",					/* 8 */
198195684Ssam	"Station requesting (re)association is not authenticated with "
199195684Ssam	  "responding station",					/* 9 */
200195684Ssam	"Disassociated because the information in the Power Capability "
201195684Ssam	  "element is unacceptable",				/* 10 */
202195684Ssam	"Disassociated because the information in the SupportedChannels "
203195684Ssam	  "element is unacceptable",				/* 11 */
204195684Ssam	"Invalid Information Element",				/* 12 */
205195684Ssam	"Reserved",						/* 13 */
206195684Ssam	"Michael MIC failure",					/* 14 */
207195684Ssam	"4-Way Handshake timeout",				/* 15 */
208195684Ssam	"Group key update timeout",				/* 16 */
209195684Ssam	"Information element in 4-Way Handshake different from (Re)Association"
210195684Ssam	  "Request/Probe Response/Beacon",			/* 17 */
211195684Ssam	"Group Cipher is not valid",				/* 18 */
212195684Ssam	"AKMP is not valid",					/* 20 */
213195684Ssam	"Unsupported RSN IE version",				/* 21 */
214195684Ssam	"Invalid RSN IE Capabilities",				/* 22 */
215195684Ssam	"IEEE 802.1X Authentication failed",			/* 23 */
216195684Ssam	"Cipher suite is rejected per security policy",		/* 24 */
217195684Ssam	"Reserved",						/* 25 */
218195684Ssam	"Reserved",						/* 26 */
219195684Ssam	"Reserved",						/* 27 */
220195684Ssam	"Reserved",						/* 28 */
221195684Ssam	"Reserved",						/* 29 */
222195684Ssam	"Reserved",						/* 30 */
223195684Ssam	"TS deleted because QoS AP lacks sufficient bandwidth for this "
224195684Ssam	  "QoS STA due to a change in BSS service characteristics or "
225195684Ssam	  "operational mode (e.g. an HT BSS change from 40 MHz channel "
226195684Ssam	  "to 20 MHz channel)",					/* 31 */
227195684Ssam	"Disassociated for unspecified, QoS-related reason",	/* 32 */
228195684Ssam	"Disassociated because QoS AP lacks sufficient bandwidth for this "
229195684Ssam	  "QoS STA",						/* 33 */
230195684Ssam	"Disassociated because of excessive number of frames that need to be "
231195684Ssam          "acknowledged, but are not acknowledged for AP transmissions "
232195684Ssam	  "and/or poor channel conditions",			/* 34 */
233195684Ssam	"Disassociated because STA is transmitting outside the limits "
234195684Ssam	  "of its TXOPs",					/* 35 */
235195684Ssam	"Requested from peer STA as the STA is leaving the BSS "
236195684Ssam	  "(or resetting)",					/* 36 */
237195684Ssam	"Requested from peer STA as it does not want to use the "
238195684Ssam	  "mechanism",						/* 37 */
239195684Ssam	"Requested from peer STA as the STA received frames using the "
240195684Ssam	  "mechanism for which a set up is required",		/* 38 */
241195684Ssam	"Requested from peer STA due to time out",		/* 39 */
242195684Ssam	"Reserved",						/* 40 */
243195684Ssam	"Reserved",						/* 41 */
244195684Ssam	"Reserved",						/* 42 */
245195684Ssam	"Reserved",						/* 43 */
246195684Ssam	"Reserved",						/* 44 */
247195684Ssam	"Peer STA does not support the requested cipher suite",	/* 45 */
248195684Ssam	"Association denied due to requesting STA not supporting HT "
249195684Ssam	  "features",						/* 46 */
25098524Sfenner};
251162017Ssam#define NUM_REASONS	(sizeof reason_text / sizeof reason_text[0])
25298524Sfenner
253127668Sbmsstatic int
254127668Sbmswep_print(const u_char *p)
25598524Sfenner{
25698524Sfenner	u_int32_t iv;
25798524Sfenner
258127668Sbms	if (!TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN))
25998524Sfenner		return 0;
26098524Sfenner	iv = EXTRACT_LE_32BITS(p);
26198524Sfenner
26298524Sfenner	printf("Data IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
26398524Sfenner	    IV_KEYID(iv));
26498524Sfenner
26598524Sfenner	return 1;
26698524Sfenner}
26798524Sfenner
268214478Srpaulostatic int
269214478Srpauloparse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset,
270214478Srpaulo    u_int length)
27198524Sfenner{
272214478Srpaulo	struct ssid_t ssid;
273214478Srpaulo	struct challenge_t challenge;
274214478Srpaulo	struct rates_t rates;
275214478Srpaulo	struct ds_t ds;
276214478Srpaulo	struct cf_t cf;
277214478Srpaulo	struct tim_t tim;
278214478Srpaulo
279172686Smlaier	/*
280172686Smlaier	 * We haven't seen any elements yet.
281172686Smlaier	 */
282214478Srpaulo	pbody->challenge_present = 0;
283214478Srpaulo	pbody->ssid_present = 0;
284214478Srpaulo	pbody->rates_present = 0;
285214478Srpaulo	pbody->ds_present = 0;
286214478Srpaulo	pbody->cf_present = 0;
287214478Srpaulo	pbody->tim_present = 0;
288172686Smlaier
289214478Srpaulo	while (length != 0) {
29098524Sfenner		if (!TTEST2(*(p + offset), 1))
291214478Srpaulo			return 0;
292214478Srpaulo		if (length < 1)
293214478Srpaulo			return 0;
29498524Sfenner		switch (*(p + offset)) {
29598524Sfenner		case E_SSID:
296127668Sbms			if (!TTEST2(*(p + offset), 2))
297214478Srpaulo				return 0;
298214478Srpaulo			if (length < 2)
299214478Srpaulo				return 0;
300214478Srpaulo			memcpy(&ssid, p + offset, 2);
301127668Sbms			offset += 2;
302214478Srpaulo			length -= 2;
303214478Srpaulo			if (ssid.length != 0) {
304214478Srpaulo				if (ssid.length > sizeof(ssid.ssid) - 1)
305214478Srpaulo					return 0;
306214478Srpaulo				if (!TTEST2(*(p + offset), ssid.length))
307214478Srpaulo					return 0;
308214478Srpaulo				if (length < ssid.length)
309214478Srpaulo					return 0;
310214478Srpaulo				memcpy(&ssid.ssid, p + offset, ssid.length);
311214478Srpaulo				offset += ssid.length;
312214478Srpaulo				length -= ssid.length;
313172686Smlaier			}
314214478Srpaulo			ssid.ssid[ssid.length] = '\0';
315214478Srpaulo			/*
316214478Srpaulo			 * Present and not truncated.
317214478Srpaulo			 *
318214478Srpaulo			 * If we haven't already seen an SSID IE,
319214478Srpaulo			 * copy this one, otherwise ignore this one,
320214478Srpaulo			 * so we later report the first one we saw.
321214478Srpaulo			 */
322214478Srpaulo			if (!pbody->ssid_present) {
323214478Srpaulo				pbody->ssid = ssid;
324214478Srpaulo				pbody->ssid_present = 1;
325214478Srpaulo			}
32698524Sfenner			break;
32798524Sfenner		case E_CHALLENGE:
328127668Sbms			if (!TTEST2(*(p + offset), 2))
329214478Srpaulo				return 0;
330214478Srpaulo			if (length < 2)
331214478Srpaulo				return 0;
332214478Srpaulo			memcpy(&challenge, p + offset, 2);
333127668Sbms			offset += 2;
334214478Srpaulo			length -= 2;
335214478Srpaulo			if (challenge.length != 0) {
336214478Srpaulo				if (challenge.length >
337214478Srpaulo				    sizeof(challenge.text) - 1)
338214478Srpaulo					return 0;
339214478Srpaulo				if (!TTEST2(*(p + offset), challenge.length))
340214478Srpaulo					return 0;
341214478Srpaulo				if (length < challenge.length)
342214478Srpaulo					return 0;
343214478Srpaulo				memcpy(&challenge.text, p + offset,
344214478Srpaulo				    challenge.length);
345214478Srpaulo				offset += challenge.length;
346214478Srpaulo				length -= challenge.length;
347172686Smlaier			}
348214478Srpaulo			challenge.text[challenge.length] = '\0';
349214478Srpaulo			/*
350214478Srpaulo			 * Present and not truncated.
351214478Srpaulo			 *
352214478Srpaulo			 * If we haven't already seen a challenge IE,
353214478Srpaulo			 * copy this one, otherwise ignore this one,
354214478Srpaulo			 * so we later report the first one we saw.
355214478Srpaulo			 */
356214478Srpaulo			if (!pbody->challenge_present) {
357214478Srpaulo				pbody->challenge = challenge;
358214478Srpaulo				pbody->challenge_present = 1;
359214478Srpaulo			}
36098524Sfenner			break;
36198524Sfenner		case E_RATES:
362127668Sbms			if (!TTEST2(*(p + offset), 2))
363214478Srpaulo				return 0;
364214478Srpaulo			if (length < 2)
365214478Srpaulo				return 0;
366214478Srpaulo			memcpy(&rates, p + offset, 2);
367127668Sbms			offset += 2;
368214478Srpaulo			length -= 2;
369214478Srpaulo			if (rates.length != 0) {
370214478Srpaulo				if (rates.length > sizeof rates.rate)
371214478Srpaulo					return 0;
372214478Srpaulo				if (!TTEST2(*(p + offset), rates.length))
373214478Srpaulo					return 0;
374214478Srpaulo				if (length < rates.length)
375214478Srpaulo					return 0;
376214478Srpaulo				memcpy(&rates.rate, p + offset, rates.length);
377214478Srpaulo				offset += rates.length;
378214478Srpaulo				length -= rates.length;
379172686Smlaier			}
380214478Srpaulo			/*
381214478Srpaulo			 * Present and not truncated.
382214478Srpaulo			 *
383214478Srpaulo			 * If we haven't already seen a rates IE,
384214478Srpaulo			 * copy this one if it's not zero-length,
385214478Srpaulo			 * otherwise ignore this one, so we later
386214478Srpaulo			 * report the first one we saw.
387214478Srpaulo			 *
388214478Srpaulo			 * We ignore zero-length rates IEs as some
389214478Srpaulo			 * devices seem to put a zero-length rates
390214478Srpaulo			 * IE, followed by an SSID IE, followed by
391214478Srpaulo			 * a non-zero-length rates IE into frames,
392214478Srpaulo			 * even though IEEE Std 802.11-2007 doesn't
393214478Srpaulo			 * seem to indicate that a zero-length rates
394214478Srpaulo			 * IE is valid.
395214478Srpaulo			 */
396214478Srpaulo			if (!pbody->rates_present && rates.length != 0) {
397214478Srpaulo				pbody->rates = rates;
398214478Srpaulo				pbody->rates_present = 1;
399214478Srpaulo			}
40098524Sfenner			break;
40198524Sfenner		case E_DS:
402127668Sbms			if (!TTEST2(*(p + offset), 3))
403214478Srpaulo				return 0;
404214478Srpaulo			if (length < 3)
405214478Srpaulo				return 0;
406214478Srpaulo			memcpy(&ds, p + offset, 3);
407127668Sbms			offset += 3;
408214478Srpaulo			length -= 3;
409214478Srpaulo			/*
410214478Srpaulo			 * Present and not truncated.
411214478Srpaulo			 *
412214478Srpaulo			 * If we haven't already seen a DS IE,
413214478Srpaulo			 * copy this one, otherwise ignore this one,
414214478Srpaulo			 * so we later report the first one we saw.
415214478Srpaulo			 */
416214478Srpaulo			if (!pbody->ds_present) {
417214478Srpaulo				pbody->ds = ds;
418214478Srpaulo				pbody->ds_present = 1;
419214478Srpaulo			}
42098524Sfenner			break;
42198524Sfenner		case E_CF:
422127668Sbms			if (!TTEST2(*(p + offset), 8))
423214478Srpaulo				return 0;
424214478Srpaulo			if (length < 8)
425214478Srpaulo				return 0;
426214478Srpaulo			memcpy(&cf, p + offset, 8);
427127668Sbms			offset += 8;
428214478Srpaulo			length -= 8;
429214478Srpaulo			/*
430214478Srpaulo			 * Present and not truncated.
431214478Srpaulo			 *
432214478Srpaulo			 * If we haven't already seen a CF IE,
433214478Srpaulo			 * copy this one, otherwise ignore this one,
434214478Srpaulo			 * so we later report the first one we saw.
435214478Srpaulo			 */
436214478Srpaulo			if (!pbody->cf_present) {
437214478Srpaulo				pbody->cf = cf;
438214478Srpaulo				pbody->cf_present = 1;
439214478Srpaulo			}
44098524Sfenner			break;
44198524Sfenner		case E_TIM:
442127668Sbms			if (!TTEST2(*(p + offset), 2))
443214478Srpaulo				return 0;
444214478Srpaulo			if (length < 2)
445214478Srpaulo				return 0;
446214478Srpaulo			memcpy(&tim, p + offset, 2);
447127668Sbms			offset += 2;
448214478Srpaulo			length -= 2;
449127668Sbms			if (!TTEST2(*(p + offset), 3))
450214478Srpaulo				return 0;
451214478Srpaulo			if (length < 3)
452214478Srpaulo				return 0;
453214478Srpaulo			memcpy(&tim.count, p + offset, 3);
454127668Sbms			offset += 3;
455214478Srpaulo			length -= 3;
45698524Sfenner
457214478Srpaulo			if (tim.length <= 3)
458127668Sbms				break;
459214478Srpaulo			if (tim.length - 3 > (int)sizeof tim.bitmap)
460214478Srpaulo				return 0;
461214478Srpaulo			if (!TTEST2(*(p + offset), tim.length - 3))
462214478Srpaulo				return 0;
463214478Srpaulo			if (length < (u_int)(tim.length - 3))
464214478Srpaulo				return 0;
465214478Srpaulo			memcpy(tim.bitmap, p + (tim.length - 3),
466214478Srpaulo			    (tim.length - 3));
467214478Srpaulo			offset += tim.length - 3;
468214478Srpaulo			length -= tim.length - 3;
469214478Srpaulo			/*
470214478Srpaulo			 * Present and not truncated.
471214478Srpaulo			 *
472214478Srpaulo			 * If we haven't already seen a TIM IE,
473214478Srpaulo			 * copy this one, otherwise ignore this one,
474214478Srpaulo			 * so we later report the first one we saw.
475214478Srpaulo			 */
476214478Srpaulo			if (!pbody->tim_present) {
477214478Srpaulo				pbody->tim = tim;
478214478Srpaulo				pbody->tim_present = 1;
479214478Srpaulo			}
48098524Sfenner			break;
48198524Sfenner		default:
48298524Sfenner#if 0
483127668Sbms			printf("(1) unhandled element_id (%d)  ",
484214478Srpaulo			    *(p + offset));
48598524Sfenner#endif
486172686Smlaier			if (!TTEST2(*(p + offset), 2))
487214478Srpaulo				return 0;
488214478Srpaulo			if (length < 2)
489214478Srpaulo				return 0;
490172686Smlaier			if (!TTEST2(*(p + offset + 2), *(p + offset + 1)))
491214478Srpaulo				return 0;
492214478Srpaulo			if (length < (u_int)(*(p + offset + 1) + 2))
493214478Srpaulo				return 0;
494127668Sbms			offset += *(p + offset + 1) + 2;
495214478Srpaulo			length -= *(p + offset + 1) + 2;
49698524Sfenner			break;
49798524Sfenner		}
49898524Sfenner	}
499214478Srpaulo
500214478Srpaulo	/* No problems found. */
501214478Srpaulo	return 1;
50298524Sfenner}
50398524Sfenner
50498524Sfenner/*********************************************************************************
50598524Sfenner * Print Handle functions for the management frame types
50698524Sfenner *********************************************************************************/
50798524Sfenner
508127668Sbmsstatic int
509214478Srpaulohandle_beacon(const u_char *p, u_int length)
51098524Sfenner{
51198524Sfenner	struct mgmt_body_t pbody;
51298524Sfenner	int offset = 0;
513214478Srpaulo	int ret;
51498524Sfenner
51598524Sfenner	memset(&pbody, 0, sizeof(pbody));
51698524Sfenner
517127668Sbms	if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
518127668Sbms	    IEEE802_11_CAPINFO_LEN))
51998524Sfenner		return 0;
520214478Srpaulo	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
521214478Srpaulo	    IEEE802_11_CAPINFO_LEN)
522214478Srpaulo		return 0;
523172686Smlaier	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
524127668Sbms	offset += IEEE802_11_TSTAMP_LEN;
525214478Srpaulo	length -= IEEE802_11_TSTAMP_LEN;
52698524Sfenner	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
527127668Sbms	offset += IEEE802_11_BCNINT_LEN;
528214478Srpaulo	length -= IEEE802_11_BCNINT_LEN;
52998524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
530127668Sbms	offset += IEEE802_11_CAPINFO_LEN;
531214478Srpaulo	length -= IEEE802_11_CAPINFO_LEN;
53298524Sfenner
533214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
53498524Sfenner
535172686Smlaier	PRINT_SSID(pbody);
536111726Sfenner	PRINT_RATES(pbody);
537172686Smlaier	printf(" %s",
538172686Smlaier	    CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
539172686Smlaier	PRINT_DS_CHANNEL(pbody);
54098524Sfenner
541214478Srpaulo	return ret;
54298524Sfenner}
54398524Sfenner
544127668Sbmsstatic int
545214478Srpaulohandle_assoc_request(const u_char *p, u_int length)
54698524Sfenner{
54798524Sfenner	struct mgmt_body_t pbody;
54898524Sfenner	int offset = 0;
549214478Srpaulo	int ret;
55098524Sfenner
55198524Sfenner	memset(&pbody, 0, sizeof(pbody));
55298524Sfenner
553127668Sbms	if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
55498524Sfenner		return 0;
555214478Srpaulo	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
556214478Srpaulo		return 0;
55798524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p);
558127668Sbms	offset += IEEE802_11_CAPINFO_LEN;
559214478Srpaulo	length -= IEEE802_11_CAPINFO_LEN;
56098524Sfenner	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
561127668Sbms	offset += IEEE802_11_LISTENINT_LEN;
562214478Srpaulo	length -= IEEE802_11_LISTENINT_LEN;
56398524Sfenner
564214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
56598524Sfenner
566172686Smlaier	PRINT_SSID(pbody);
567111726Sfenner	PRINT_RATES(pbody);
568214478Srpaulo	return ret;
56998524Sfenner}
57098524Sfenner
571127668Sbmsstatic int
572214478Srpaulohandle_assoc_response(const u_char *p, u_int length)
57398524Sfenner{
57498524Sfenner	struct mgmt_body_t pbody;
57598524Sfenner	int offset = 0;
576214478Srpaulo	int ret;
57798524Sfenner
57898524Sfenner	memset(&pbody, 0, sizeof(pbody));
57998524Sfenner
580127668Sbms	if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
581127668Sbms	    IEEE802_11_AID_LEN))
58298524Sfenner		return 0;
583214478Srpaulo	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
584214478Srpaulo	    IEEE802_11_AID_LEN)
585214478Srpaulo		return 0;
58698524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p);
587127668Sbms	offset += IEEE802_11_CAPINFO_LEN;
588214478Srpaulo	length -= IEEE802_11_CAPINFO_LEN;
58998524Sfenner	pbody.status_code = EXTRACT_LE_16BITS(p+offset);
590127668Sbms	offset += IEEE802_11_STATUS_LEN;
591214478Srpaulo	length -= IEEE802_11_STATUS_LEN;
59298524Sfenner	pbody.aid = EXTRACT_LE_16BITS(p+offset);
593127668Sbms	offset += IEEE802_11_AID_LEN;
594214478Srpaulo	length -= IEEE802_11_AID_LEN;
59598524Sfenner
596214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
59798524Sfenner
598127668Sbms	printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
59998524Sfenner	    CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
600162017Ssam	    (pbody.status_code < NUM_STATUSES
601162017Ssam		? status_text[pbody.status_code]
602162017Ssam		: "n/a"));
60398524Sfenner
604214478Srpaulo	return ret;
60598524Sfenner}
60698524Sfenner
607127668Sbmsstatic int
608214478Srpaulohandle_reassoc_request(const u_char *p, u_int length)
60998524Sfenner{
61098524Sfenner	struct mgmt_body_t pbody;
61198524Sfenner	int offset = 0;
612214478Srpaulo	int ret;
61398524Sfenner
61498524Sfenner	memset(&pbody, 0, sizeof(pbody));
61598524Sfenner
616127668Sbms	if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
617127668Sbms	    IEEE802_11_AP_LEN))
61898524Sfenner		return 0;
619214478Srpaulo	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
620214478Srpaulo	    IEEE802_11_AP_LEN)
621214478Srpaulo		return 0;
62298524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p);
623127668Sbms	offset += IEEE802_11_CAPINFO_LEN;
624214478Srpaulo	length -= IEEE802_11_CAPINFO_LEN;
62598524Sfenner	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
626127668Sbms	offset += IEEE802_11_LISTENINT_LEN;
627214478Srpaulo	length -= IEEE802_11_LISTENINT_LEN;
628127668Sbms	memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
629127668Sbms	offset += IEEE802_11_AP_LEN;
630214478Srpaulo	length -= IEEE802_11_AP_LEN;
63198524Sfenner
632214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
63398524Sfenner
634172686Smlaier	PRINT_SSID(pbody);
635172686Smlaier	printf(" AP : %s", etheraddr_string( pbody.ap ));
63698524Sfenner
637214478Srpaulo	return ret;
63898524Sfenner}
63998524Sfenner
640127668Sbmsstatic int
641214478Srpaulohandle_reassoc_response(const u_char *p, u_int length)
64298524Sfenner{
64398524Sfenner	/* Same as a Association Reponse */
644214478Srpaulo	return handle_assoc_response(p, length);
64598524Sfenner}
64698524Sfenner
647127668Sbmsstatic int
648214478Srpaulohandle_probe_request(const u_char *p, u_int length)
64998524Sfenner{
65098524Sfenner	struct mgmt_body_t  pbody;
65198524Sfenner	int offset = 0;
652214478Srpaulo	int ret;
65398524Sfenner
65498524Sfenner	memset(&pbody, 0, sizeof(pbody));
65598524Sfenner
656214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
65798524Sfenner
658172686Smlaier	PRINT_SSID(pbody);
659111726Sfenner	PRINT_RATES(pbody);
66098524Sfenner
661214478Srpaulo	return ret;
66298524Sfenner}
66398524Sfenner
664127668Sbmsstatic int
665214478Srpaulohandle_probe_response(const u_char *p, u_int length)
66698524Sfenner{
66798524Sfenner	struct mgmt_body_t  pbody;
66898524Sfenner	int offset = 0;
669214478Srpaulo	int ret;
67098524Sfenner
67198524Sfenner	memset(&pbody, 0, sizeof(pbody));
67298524Sfenner
673127668Sbms	if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
674127668Sbms	    IEEE802_11_CAPINFO_LEN))
67598524Sfenner		return 0;
676214478Srpaulo	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
677214478Srpaulo	    IEEE802_11_CAPINFO_LEN)
678214478Srpaulo		return 0;
679127668Sbms	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
680127668Sbms	offset += IEEE802_11_TSTAMP_LEN;
681214478Srpaulo	length -= IEEE802_11_TSTAMP_LEN;
68298524Sfenner	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
683127668Sbms	offset += IEEE802_11_BCNINT_LEN;
684214478Srpaulo	length -= IEEE802_11_BCNINT_LEN;
68598524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
686127668Sbms	offset += IEEE802_11_CAPINFO_LEN;
687214478Srpaulo	length -= IEEE802_11_CAPINFO_LEN;
68898524Sfenner
689214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
69098524Sfenner
691172686Smlaier	PRINT_SSID(pbody);
692111726Sfenner	PRINT_RATES(pbody);
693172686Smlaier	PRINT_DS_CHANNEL(pbody);
69498524Sfenner
695214478Srpaulo	return ret;
69698524Sfenner}
69798524Sfenner
698127668Sbmsstatic int
699127668Sbmshandle_atim(void)
70098524Sfenner{
70198524Sfenner	/* the frame body for ATIM is null. */
70298524Sfenner	return 1;
70398524Sfenner}
70498524Sfenner
705127668Sbmsstatic int
706214478Srpaulohandle_disassoc(const u_char *p, u_int length)
70798524Sfenner{
70898524Sfenner	struct mgmt_body_t  pbody;
70998524Sfenner
71098524Sfenner	memset(&pbody, 0, sizeof(pbody));
71198524Sfenner
712127668Sbms	if (!TTEST2(*p, IEEE802_11_REASON_LEN))
71398524Sfenner		return 0;
714214478Srpaulo	if (length < IEEE802_11_REASON_LEN)
715214478Srpaulo		return 0;
71698524Sfenner	pbody.reason_code = EXTRACT_LE_16BITS(p);
71798524Sfenner
718127668Sbms	printf(": %s",
719162017Ssam	    (pbody.reason_code < NUM_REASONS)
720162017Ssam		? reason_text[pbody.reason_code]
721162017Ssam		: "Reserved" );
72298524Sfenner
72398524Sfenner	return 1;
72498524Sfenner}
72598524Sfenner
726127668Sbmsstatic int
727214478Srpaulohandle_auth(const u_char *p, u_int length)
72898524Sfenner{
72998524Sfenner	struct mgmt_body_t  pbody;
73098524Sfenner	int offset = 0;
731214478Srpaulo	int ret;
73298524Sfenner
73398524Sfenner	memset(&pbody, 0, sizeof(pbody));
73498524Sfenner
73598524Sfenner	if (!TTEST2(*p, 6))
73698524Sfenner		return 0;
737214478Srpaulo	if (length < 6)
738214478Srpaulo		return 0;
73998524Sfenner	pbody.auth_alg = EXTRACT_LE_16BITS(p);
74098524Sfenner	offset += 2;
741214478Srpaulo	length -= 2;
74298524Sfenner	pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
74398524Sfenner	offset += 2;
744214478Srpaulo	length -= 2;
74598524Sfenner	pbody.status_code = EXTRACT_LE_16BITS(p + offset);
74698524Sfenner	offset += 2;
747214478Srpaulo	length -= 2;
74898524Sfenner
749214478Srpaulo	ret = parse_elements(&pbody, p, offset, length);
75098524Sfenner
75198524Sfenner	if ((pbody.auth_alg == 1) &&
752127668Sbms	    ((pbody.auth_trans_seq_num == 2) ||
753127668Sbms	     (pbody.auth_trans_seq_num == 3))) {
754127668Sbms		printf(" (%s)-%x [Challenge Text] %s",
755162017Ssam		    (pbody.auth_alg < NUM_AUTH_ALGS)
756162017Ssam			? auth_alg_text[pbody.auth_alg]
757162017Ssam			: "Reserved",
75898524Sfenner		    pbody.auth_trans_seq_num,
759127668Sbms		    ((pbody.auth_trans_seq_num % 2)
760162017Ssam		        ? ((pbody.status_code < NUM_STATUSES)
761127668Sbms			       ? status_text[pbody.status_code]
762127668Sbms			       : "n/a") : ""));
763214478Srpaulo		return ret;
76498524Sfenner	}
765127668Sbms	printf(" (%s)-%x: %s",
766162017Ssam	    (pbody.auth_alg < NUM_AUTH_ALGS)
767162017Ssam		? auth_alg_text[pbody.auth_alg]
768162017Ssam		: "Reserved",
769127668Sbms	    pbody.auth_trans_seq_num,
770127668Sbms	    (pbody.auth_trans_seq_num % 2)
771162017Ssam	        ? ((pbody.status_code < NUM_STATUSES)
772162017Ssam		    ? status_text[pbody.status_code]
773162017Ssam	            : "n/a")
774127668Sbms	        : "");
77598524Sfenner
776214478Srpaulo	return ret;
77798524Sfenner}
77898524Sfenner
779127668Sbmsstatic int
780214478Srpaulohandle_deauth(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
78198524Sfenner{
78298524Sfenner	struct mgmt_body_t  pbody;
78398524Sfenner	int offset = 0;
784127668Sbms	const char *reason = NULL;
78598524Sfenner
78698524Sfenner	memset(&pbody, 0, sizeof(pbody));
78798524Sfenner
788127668Sbms	if (!TTEST2(*p, IEEE802_11_REASON_LEN))
78998524Sfenner		return 0;
790214478Srpaulo	if (length < IEEE802_11_REASON_LEN)
791214478Srpaulo		return 0;
79298524Sfenner	pbody.reason_code = EXTRACT_LE_16BITS(p);
793127668Sbms	offset += IEEE802_11_REASON_LEN;
794214478Srpaulo	length -= IEEE802_11_REASON_LEN;
79598524Sfenner
796162017Ssam	reason = (pbody.reason_code < NUM_REASONS)
797162017Ssam			? reason_text[pbody.reason_code]
798162017Ssam			: "Reserved";
799127668Sbms
80098524Sfenner	if (eflag) {
801127668Sbms		printf(": %s", reason);
80298524Sfenner	} else {
803127668Sbms		printf(" (%s): %s", etheraddr_string(pmh->sa), reason);
80498524Sfenner	}
80598524Sfenner	return 1;
80698524Sfenner}
80798524Sfenner
808195684Ssam#define	PRINT_HT_ACTION(v) (\
809195684Ssam	(v) == 0 ? printf("TxChWidth") : \
810195684Ssam	(v) == 1 ? printf("MIMOPwrSave") : \
811195684Ssam		   printf("Act#%d", (v)) \
812195684Ssam)
813195684Ssam#define	PRINT_BA_ACTION(v) (\
814195684Ssam	(v) == 0 ? printf("ADDBA Request") : \
815195684Ssam	(v) == 1 ? printf("ADDBA Response") : \
816195684Ssam	(v) == 2 ? printf("DELBA") : \
817195684Ssam		   printf("Act#%d", (v)) \
818195684Ssam)
819195684Ssam#define	PRINT_MESHLINK_ACTION(v) (\
820195684Ssam	(v) == 0 ? printf("Request") : \
821195684Ssam	(v) == 1 ? printf("Report") : \
822195684Ssam		   printf("Act#%d", (v)) \
823195684Ssam)
824195684Ssam#define	PRINT_MESHPEERING_ACTION(v) (\
825195684Ssam	(v) == 0 ? printf("Open") : \
826195684Ssam	(v) == 1 ? printf("Confirm") : \
827195684Ssam	(v) == 2 ? printf("Close") : \
828195684Ssam		   printf("Act#%d", (v)) \
829195684Ssam)
830195684Ssam#define	PRINT_MESHPATH_ACTION(v) (\
831195684Ssam	(v) == 0 ? printf("Request") : \
832195684Ssam	(v) == 1 ? printf("Report") : \
833195684Ssam	(v) == 2 ? printf("Error") : \
834195684Ssam	(v) == 3 ? printf("RootAnnouncement") : \
835195684Ssam		   printf("Act#%d", (v)) \
836195684Ssam)
83798524Sfenner
838195684Ssamstatic int
839214478Srpaulohandle_action(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
840195684Ssam{
841195684Ssam	if (!TTEST2(*p, 2))
842195684Ssam		return 0;
843214478Srpaulo	if (length < 2)
844214478Srpaulo		return 0;
845195684Ssam	if (eflag) {
846195684Ssam		printf(": ");
847195684Ssam	} else {
848195684Ssam		printf(" (%s): ", etheraddr_string(pmh->sa));
849195684Ssam	}
850195684Ssam	switch (p[0]) {
851195684Ssam	case 0: printf("Spectrum Management Act#%d", p[1]); break;
852195684Ssam	case 1: printf("QoS Act#%d", p[1]); break;
853195684Ssam	case 2: printf("DLS Act#%d", p[1]); break;
854195684Ssam	case 3: printf("BA "); PRINT_BA_ACTION(p[1]); break;
855195684Ssam	case 7: printf("HT "); PRINT_HT_ACTION(p[1]); break;
856195684Ssam	case 13: printf("MeshLMetric "); PRINT_MESHLINK_ACTION(p[1]); break;
857195684Ssam	case 15: printf("Interwork Act#%d", p[1]); break;
858195684Ssam	case 16: printf("Resource Act#%d", p[1]); break;
859195684Ssam	case 17: printf("Proxy Act#%d", p[1]); break;
860195684Ssam	case 30: printf("MeshPeering "); PRINT_MESHPEERING_ACTION(p[1]); break;
861195684Ssam	case 32: printf("MeshPath "); PRINT_MESHPATH_ACTION(p[1]); break;
862195684Ssam	case 127: printf("Vendor Act#%d", p[1]); break;
863195684Ssam	default:
864195684Ssam		printf("Reserved(%d) Act#%d", p[0], p[1]);
865195684Ssam		break;
866195684Ssam	}
867195684Ssam	return 1;
868195684Ssam}
869195684Ssam
870195684Ssam
87198524Sfenner/*********************************************************************************
87298524Sfenner * Print Body funcs
87398524Sfenner *********************************************************************************/
87498524Sfenner
87598524Sfenner
876127668Sbmsstatic int
877127668Sbmsmgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
878214478Srpaulo    const u_char *p, u_int length)
87998524Sfenner{
88098524Sfenner	switch (FC_SUBTYPE(fc)) {
88198524Sfenner	case ST_ASSOC_REQUEST:
882162017Ssam		printf("Assoc Request");
883214478Srpaulo		return handle_assoc_request(p, length);
88498524Sfenner	case ST_ASSOC_RESPONSE:
885162017Ssam		printf("Assoc Response");
886214478Srpaulo		return handle_assoc_response(p, length);
88798524Sfenner	case ST_REASSOC_REQUEST:
888162017Ssam		printf("ReAssoc Request");
889214478Srpaulo		return handle_reassoc_request(p, length);
89098524Sfenner	case ST_REASSOC_RESPONSE:
891162017Ssam		printf("ReAssoc Response");
892214478Srpaulo		return handle_reassoc_response(p, length);
89398524Sfenner	case ST_PROBE_REQUEST:
894162017Ssam		printf("Probe Request");
895214478Srpaulo		return handle_probe_request(p, length);
89698524Sfenner	case ST_PROBE_RESPONSE:
897162017Ssam		printf("Probe Response");
898214478Srpaulo		return handle_probe_response(p, length);
89998524Sfenner	case ST_BEACON:
900162017Ssam		printf("Beacon");
901214478Srpaulo		return handle_beacon(p, length);
90298524Sfenner	case ST_ATIM:
903162017Ssam		printf("ATIM");
904127668Sbms		return handle_atim();
90598524Sfenner	case ST_DISASSOC:
906162017Ssam		printf("Disassociation");
907214478Srpaulo		return handle_disassoc(p, length);
90898524Sfenner	case ST_AUTH:
909162017Ssam		printf("Authentication");
91098524Sfenner		if (!TTEST2(*p, 3))
91198524Sfenner			return 0;
91298524Sfenner		if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) {
91398524Sfenner			printf("Authentication (Shared-Key)-3 ");
914127668Sbms			return wep_print(p);
91598524Sfenner		}
916214478Srpaulo		return handle_auth(p, length);
91798524Sfenner	case ST_DEAUTH:
918162017Ssam		printf("DeAuthentication");
919214478Srpaulo		return handle_deauth(pmh, p, length);
92098524Sfenner		break;
921195684Ssam	case ST_ACTION:
922195684Ssam		printf("Action");
923214478Srpaulo		return handle_action(pmh, p, length);
924195684Ssam		break;
92598524Sfenner	default:
926127668Sbms		printf("Unhandled Management subtype(%x)",
92798524Sfenner		    FC_SUBTYPE(fc));
92898524Sfenner		return 1;
92998524Sfenner	}
93098524Sfenner}
93198524Sfenner
93298524Sfenner
93398524Sfenner/*********************************************************************************
93498524Sfenner * Handles printing all the control frame types
93598524Sfenner *********************************************************************************/
93698524Sfenner
937127668Sbmsstatic int
938127668Sbmsctrl_body_print(u_int16_t fc, const u_char *p)
93998524Sfenner{
94098524Sfenner	switch (FC_SUBTYPE(fc)) {
941214478Srpaulo	case CTRL_CONTROL_WRAPPER:
942214478Srpaulo		printf("Control Wrapper");
943214478Srpaulo		/* XXX - requires special handling */
944214478Srpaulo		break;
945170533Ssam	case CTRL_BAR:
946170533Ssam		printf("BAR");
947170533Ssam		if (!TTEST2(*p, CTRL_BAR_HDRLEN))
948170533Ssam			return 0;
949170533Ssam		if (!eflag)
950170533Ssam			printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
951170533Ssam			    etheraddr_string(((const struct ctrl_bar_t *)p)->ra),
952170533Ssam			    etheraddr_string(((const struct ctrl_bar_t *)p)->ta),
953170533Ssam			    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)),
954170533Ssam			    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq)));
955170533Ssam		break;
956195684Ssam	case CTRL_BA:
957195684Ssam		printf("BA");
958195684Ssam		if (!TTEST2(*p, CTRL_BA_HDRLEN))
959195684Ssam			return 0;
960195684Ssam		if (!eflag)
961195684Ssam			printf(" RA:%s ",
962195684Ssam			    etheraddr_string(((const struct ctrl_ba_t *)p)->ra));
963195684Ssam		break;
96498524Sfenner	case CTRL_PS_POLL:
965127668Sbms		printf("Power Save-Poll");
966127668Sbms		if (!TTEST2(*p, CTRL_PS_POLL_HDRLEN))
96798524Sfenner			return 0;
968127668Sbms		printf(" AID(%x)",
96998524Sfenner		    EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid)));
97098524Sfenner		break;
97198524Sfenner	case CTRL_RTS:
972127668Sbms		printf("Request-To-Send");
973127668Sbms		if (!TTEST2(*p, CTRL_RTS_HDRLEN))
97498524Sfenner			return 0;
975127668Sbms		if (!eflag)
976127668Sbms			printf(" TA:%s ",
97798524Sfenner			    etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
97898524Sfenner		break;
97998524Sfenner	case CTRL_CTS:
980127668Sbms		printf("Clear-To-Send");
981127668Sbms		if (!TTEST2(*p, CTRL_CTS_HDRLEN))
98298524Sfenner			return 0;
983127668Sbms		if (!eflag)
984127668Sbms			printf(" RA:%s ",
98598524Sfenner			    etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
98698524Sfenner		break;
98798524Sfenner	case CTRL_ACK:
988127668Sbms		printf("Acknowledgment");
989127668Sbms		if (!TTEST2(*p, CTRL_ACK_HDRLEN))
99098524Sfenner			return 0;
991127668Sbms		if (!eflag)
992127668Sbms			printf(" RA:%s ",
99398524Sfenner			    etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
99498524Sfenner		break;
99598524Sfenner	case CTRL_CF_END:
996127668Sbms		printf("CF-End");
997127668Sbms		if (!TTEST2(*p, CTRL_END_HDRLEN))
99898524Sfenner			return 0;
999127668Sbms		if (!eflag)
1000127668Sbms			printf(" RA:%s ",
100198524Sfenner			    etheraddr_string(((const struct ctrl_end_t *)p)->ra));
100298524Sfenner		break;
100398524Sfenner	case CTRL_END_ACK:
1004127668Sbms		printf("CF-End+CF-Ack");
1005127668Sbms		if (!TTEST2(*p, CTRL_END_ACK_HDRLEN))
100698524Sfenner			return 0;
1007127668Sbms		if (!eflag)
1008127668Sbms			printf(" RA:%s ",
100998524Sfenner			    etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra));
101098524Sfenner		break;
101198524Sfenner	default:
1012127668Sbms		printf("Unknown Ctrl Subtype");
101398524Sfenner	}
101498524Sfenner	return 1;
101598524Sfenner}
101698524Sfenner
101798524Sfenner/*
101898524Sfenner * Print Header funcs
101998524Sfenner */
102098524Sfenner
102198524Sfenner/*
102298524Sfenner *  Data Frame - Address field contents
102398524Sfenner *
102498524Sfenner *  To Ds  | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
102598524Sfenner *    0    |  0      |  DA    | SA     | BSSID  | n/a
102698524Sfenner *    0    |  1      |  DA    | BSSID  | SA     | n/a
102798524Sfenner *    1    |  0      |  BSSID | SA     | DA     | n/a
102898524Sfenner *    1    |  1      |  RA    | TA     | DA     | SA
102998524Sfenner */
103098524Sfenner
1031127668Sbmsstatic void
1032127668Sbmsdata_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
1033127668Sbms    const u_int8_t **dstp)
103498524Sfenner{
1035172686Smlaier	u_int subtype = FC_SUBTYPE(fc);
1036172686Smlaier
1037172686Smlaier	if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) ||
1038172686Smlaier	    DATA_FRAME_IS_QOS(subtype)) {
1039172686Smlaier		printf("CF ");
1040172686Smlaier		if (DATA_FRAME_IS_CF_ACK(subtype)) {
1041172686Smlaier			if (DATA_FRAME_IS_CF_POLL(subtype))
1042172686Smlaier				printf("Ack/Poll");
1043172686Smlaier			else
1044172686Smlaier				printf("Ack");
1045172686Smlaier		} else {
1046172686Smlaier			if (DATA_FRAME_IS_CF_POLL(subtype))
1047172686Smlaier				printf("Poll");
1048172686Smlaier		}
1049172686Smlaier		if (DATA_FRAME_IS_QOS(subtype))
1050172686Smlaier			printf("+QoS");
1051172686Smlaier		printf(" ");
1052127668Sbms	}
1053127668Sbms
105498524Sfenner#define ADDR1  (p + 4)
105598524Sfenner#define ADDR2  (p + 10)
105698524Sfenner#define ADDR3  (p + 16)
105798524Sfenner#define ADDR4  (p + 24)
105898524Sfenner
1059127668Sbms	if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1060127668Sbms		if (srcp != NULL)
1061127668Sbms			*srcp = ADDR2;
1062127668Sbms		if (dstp != NULL)
1063127668Sbms			*dstp = ADDR1;
1064127668Sbms		if (!eflag)
1065127668Sbms			return;
1066127668Sbms		printf("DA:%s SA:%s BSSID:%s ",
1067127668Sbms		    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
1068127668Sbms		    etheraddr_string(ADDR3));
1069127668Sbms	} else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1070127668Sbms		if (srcp != NULL)
1071127668Sbms			*srcp = ADDR3;
1072127668Sbms		if (dstp != NULL)
1073127668Sbms			*dstp = ADDR1;
1074127668Sbms		if (!eflag)
1075127668Sbms			return;
1076127668Sbms		printf("DA:%s BSSID:%s SA:%s ",
1077127668Sbms		    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
1078127668Sbms		    etheraddr_string(ADDR3));
1079127668Sbms	} else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
1080127668Sbms		if (srcp != NULL)
1081127668Sbms			*srcp = ADDR2;
1082127668Sbms		if (dstp != NULL)
1083127668Sbms			*dstp = ADDR3;
1084127668Sbms		if (!eflag)
1085127668Sbms			return;
1086127668Sbms		printf("BSSID:%s SA:%s DA:%s ",
1087127668Sbms		    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
1088127668Sbms		    etheraddr_string(ADDR3));
1089127668Sbms	} else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
1090127668Sbms		if (srcp != NULL)
1091127668Sbms			*srcp = ADDR4;
1092127668Sbms		if (dstp != NULL)
1093127668Sbms			*dstp = ADDR3;
1094127668Sbms		if (!eflag)
1095127668Sbms			return;
1096127668Sbms		printf("RA:%s TA:%s DA:%s SA:%s ",
1097127668Sbms		    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
1098127668Sbms		    etheraddr_string(ADDR3), etheraddr_string(ADDR4));
109998524Sfenner	}
110098524Sfenner
110198524Sfenner#undef ADDR1
110298524Sfenner#undef ADDR2
110398524Sfenner#undef ADDR3
110498524Sfenner#undef ADDR4
110598524Sfenner}
110698524Sfenner
1107127668Sbmsstatic void
1108127668Sbmsmgmt_header_print(const u_char *p, const u_int8_t **srcp,
1109127668Sbms    const u_int8_t **dstp)
111098524Sfenner{
111198524Sfenner	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
111298524Sfenner
1113127668Sbms	if (srcp != NULL)
1114127668Sbms		*srcp = hp->sa;
1115127668Sbms	if (dstp != NULL)
1116127668Sbms		*dstp = hp->da;
1117127668Sbms	if (!eflag)
1118127668Sbms		return;
1119127668Sbms
112098524Sfenner	printf("BSSID:%s DA:%s SA:%s ",
112198524Sfenner	    etheraddr_string((hp)->bssid), etheraddr_string((hp)->da),
112298524Sfenner	    etheraddr_string((hp)->sa));
112398524Sfenner}
112498524Sfenner
1125127668Sbmsstatic void
1126127668Sbmsctrl_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
1127127668Sbms    const u_int8_t **dstp)
112898524Sfenner{
1129127668Sbms	if (srcp != NULL)
1130127668Sbms		*srcp = NULL;
1131127668Sbms	if (dstp != NULL)
1132127668Sbms		*dstp = NULL;
1133127668Sbms	if (!eflag)
1134127668Sbms		return;
1135127668Sbms
113698524Sfenner	switch (FC_SUBTYPE(fc)) {
1137170533Ssam	case CTRL_BAR:
1138170533Ssam		printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
1139170533Ssam		    etheraddr_string(((const struct ctrl_bar_t *)p)->ra),
1140170533Ssam		    etheraddr_string(((const struct ctrl_bar_t *)p)->ta),
1141170533Ssam		    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)),
1142170533Ssam		    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq)));
1143170533Ssam		break;
1144195684Ssam	case CTRL_BA:
1145195684Ssam		printf("RA:%s ",
1146195684Ssam		    etheraddr_string(((const struct ctrl_ba_t *)p)->ra));
1147195684Ssam		break;
114898524Sfenner	case CTRL_PS_POLL:
114998524Sfenner		printf("BSSID:%s TA:%s ",
115098524Sfenner		    etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid),
115198524Sfenner		    etheraddr_string(((const struct ctrl_ps_poll_t *)p)->ta));
115298524Sfenner		break;
115398524Sfenner	case CTRL_RTS:
115498524Sfenner		printf("RA:%s TA:%s ",
115598524Sfenner		    etheraddr_string(((const struct ctrl_rts_t *)p)->ra),
115698524Sfenner		    etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
115798524Sfenner		break;
115898524Sfenner	case CTRL_CTS:
115998524Sfenner		printf("RA:%s ",
116098524Sfenner		    etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
116198524Sfenner		break;
116298524Sfenner	case CTRL_ACK:
116398524Sfenner		printf("RA:%s ",
116498524Sfenner		    etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
116598524Sfenner		break;
116698524Sfenner	case CTRL_CF_END:
116798524Sfenner		printf("RA:%s BSSID:%s ",
116898524Sfenner		    etheraddr_string(((const struct ctrl_end_t *)p)->ra),
116998524Sfenner		    etheraddr_string(((const struct ctrl_end_t *)p)->bssid));
117098524Sfenner		break;
117198524Sfenner	case CTRL_END_ACK:
117298524Sfenner		printf("RA:%s BSSID:%s ",
117398524Sfenner		    etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra),
117498524Sfenner		    etheraddr_string(((const struct ctrl_end_ack_t *)p)->bssid));
117598524Sfenner		break;
117698524Sfenner	default:
117798524Sfenner		printf("(H) Unknown Ctrl Subtype");
1178127668Sbms		break;
117998524Sfenner	}
118098524Sfenner}
118198524Sfenner
1182127668Sbmsstatic int
1183127668Sbmsextract_header_length(u_int16_t fc)
118498524Sfenner{
1185172686Smlaier	int len;
1186172686Smlaier
118798524Sfenner	switch (FC_TYPE(fc)) {
118898524Sfenner	case T_MGMT:
1189127668Sbms		return MGMT_HDRLEN;
119098524Sfenner	case T_CTRL:
119198524Sfenner		switch (FC_SUBTYPE(fc)) {
1192170533Ssam		case CTRL_BAR:
1193170533Ssam			return CTRL_BAR_HDRLEN;
119498524Sfenner		case CTRL_PS_POLL:
1195127668Sbms			return CTRL_PS_POLL_HDRLEN;
119698524Sfenner		case CTRL_RTS:
1197127668Sbms			return CTRL_RTS_HDRLEN;
119898524Sfenner		case CTRL_CTS:
1199127668Sbms			return CTRL_CTS_HDRLEN;
120098524Sfenner		case CTRL_ACK:
1201127668Sbms			return CTRL_ACK_HDRLEN;
120298524Sfenner		case CTRL_CF_END:
1203127668Sbms			return CTRL_END_HDRLEN;
120498524Sfenner		case CTRL_END_ACK:
1205127668Sbms			return CTRL_END_ACK_HDRLEN;
120698524Sfenner		default:
1207127668Sbms			return 0;
120898524Sfenner		}
120998524Sfenner	case T_DATA:
1210172686Smlaier		len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
1211172686Smlaier		if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
1212172686Smlaier			len += 2;
1213172686Smlaier		return len;
121498524Sfenner	default:
1215127668Sbms		printf("unknown IEEE802.11 frame type (%d)", FC_TYPE(fc));
1216127668Sbms		return 0;
121798524Sfenner	}
121898524Sfenner}
121998524Sfenner
1220195684Ssamstatic int
1221195684Ssamextract_mesh_header_length(const u_char *p)
1222195684Ssam{
1223195684Ssam	return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3));
1224195684Ssam}
1225195684Ssam
122698524Sfenner/*
1227127668Sbms * Print the 802.11 MAC header if eflag is set, and set "*srcp" and "*dstp"
1228127668Sbms * to point to the source and destination MAC addresses in any case if
1229127668Sbms * "srcp" and "dstp" aren't null.
123098524Sfenner */
1231195684Ssamstatic void
1232195684Ssamieee_802_11_hdr_print(u_int16_t fc, const u_char *p, u_int hdrlen,
1233195684Ssam    u_int meshdrlen, const u_int8_t **srcp, const u_int8_t **dstp)
123498524Sfenner{
1235127668Sbms	if (vflag) {
1236127668Sbms		if (FC_MORE_DATA(fc))
1237127668Sbms			printf("More Data ");
1238127668Sbms		if (FC_MORE_FLAG(fc))
1239127668Sbms			printf("More Fragments ");
1240127668Sbms		if (FC_POWER_MGMT(fc))
1241127668Sbms			printf("Pwr Mgmt ");
1242127668Sbms		if (FC_RETRY(fc))
1243127668Sbms			printf("Retry ");
1244127668Sbms		if (FC_ORDER(fc))
1245127668Sbms			printf("Strictly Ordered ");
1246127668Sbms		if (FC_WEP(fc))
1247127668Sbms			printf("WEP Encrypted ");
1248127668Sbms		if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL)
1249127668Sbms			printf("%dus ",
1250127668Sbms			    EXTRACT_LE_16BITS(
1251127668Sbms			        &((const struct mgmt_header_t *)p)->duration));
1252127668Sbms	}
1253195684Ssam	if (meshdrlen != 0) {
1254195684Ssam		const struct meshcntl_t *mc =
1255195684Ssam		    (const struct meshcntl_t *)&p[hdrlen - meshdrlen];
1256195684Ssam		int ae = mc->flags & 3;
1257127668Sbms
1258195684Ssam		printf("MeshData (AE %d TTL %u seq %u", ae, mc->ttl,
1259195684Ssam		    EXTRACT_LE_32BITS(mc->seq));
1260195684Ssam		if (ae > 0)
1261195684Ssam			printf(" A4:%s", etheraddr_string(mc->addr4));
1262195684Ssam		if (ae > 1)
1263195684Ssam			printf(" A5:%s", etheraddr_string(mc->addr5));
1264195684Ssam		if (ae > 2)
1265195684Ssam			printf(" A6:%s", etheraddr_string(mc->addr6));
1266195684Ssam		printf(") ");
1267195684Ssam	}
1268195684Ssam
126998524Sfenner	switch (FC_TYPE(fc)) {
127098524Sfenner	case T_MGMT:
1271127668Sbms		mgmt_header_print(p, srcp, dstp);
127298524Sfenner		break;
127398524Sfenner	case T_CTRL:
1274127668Sbms		ctrl_header_print(fc, p, srcp, dstp);
127598524Sfenner		break;
127698524Sfenner	case T_DATA:
1277127668Sbms		data_header_print(fc, p, srcp, dstp);
127898524Sfenner		break;
127998524Sfenner	default:
128098524Sfenner		printf("(header) unknown IEEE802.11 frame type (%d)",
128198524Sfenner		    FC_TYPE(fc));
1282127668Sbms		*srcp = NULL;
1283127668Sbms		*dstp = NULL;
128498524Sfenner		break;
128598524Sfenner	}
128698524Sfenner}
128798524Sfenner
1288172686Smlaier#ifndef roundup2
1289172686Smlaier#define	roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
1290172686Smlaier#endif
1291172686Smlaier
1292127668Sbmsstatic u_int
1293214478Srpauloieee802_11_print(const u_char *p, u_int length, u_int orig_caplen, int pad,
1294214478Srpaulo    u_int fcslen)
129598524Sfenner{
129698524Sfenner	u_int16_t fc;
1297214478Srpaulo	u_int caplen, hdrlen, meshdrlen;
1298127668Sbms	const u_int8_t *src, *dst;
129998524Sfenner	u_short extracted_ethertype;
130098524Sfenner
1301214478Srpaulo	caplen = orig_caplen;
1302214478Srpaulo	/* Remove FCS, if present */
1303214478Srpaulo	if (length < fcslen) {
130498524Sfenner		printf("[|802.11]");
1305127668Sbms		return caplen;
130698524Sfenner	}
1307214478Srpaulo	length -= fcslen;
1308214478Srpaulo	if (caplen > length) {
1309214478Srpaulo		/* Amount of FCS in actual packet data, if any */
1310214478Srpaulo		fcslen = caplen - length;
1311214478Srpaulo		caplen -= fcslen;
1312214478Srpaulo		snapend -= fcslen;
1313214478Srpaulo	}
131498524Sfenner
1315214478Srpaulo	if (caplen < IEEE802_11_FC_LEN) {
1316214478Srpaulo		printf("[|802.11]");
1317214478Srpaulo		return orig_caplen;
1318214478Srpaulo	}
1319214478Srpaulo
1320127668Sbms	fc = EXTRACT_LE_16BITS(p);
1321127668Sbms	hdrlen = extract_header_length(fc);
1322172686Smlaier	if (pad)
1323172686Smlaier		hdrlen = roundup2(hdrlen, 4);
1324195684Ssam	if (FC_TYPE(fc) == T_DATA && DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
1325195684Ssam		meshdrlen = extract_mesh_header_length(p+hdrlen);
1326195684Ssam		hdrlen += meshdrlen;
1327195684Ssam	} else
1328195684Ssam		meshdrlen = 0;
132998524Sfenner
1330195684Ssam
1331127668Sbms	if (caplen < hdrlen) {
1332127668Sbms		printf("[|802.11]");
1333127668Sbms		return hdrlen;
1334127668Sbms	}
133598524Sfenner
1336195684Ssam	ieee_802_11_hdr_print(fc, p, hdrlen, meshdrlen, &src, &dst);
1337127668Sbms
133898524Sfenner	/*
1339127668Sbms	 * Go past the 802.11 header.
134098524Sfenner	 */
1341127668Sbms	length -= hdrlen;
1342127668Sbms	caplen -= hdrlen;
1343127668Sbms	p += hdrlen;
134498524Sfenner
134598524Sfenner	switch (FC_TYPE(fc)) {
134698524Sfenner	case T_MGMT:
1347127668Sbms		if (!mgmt_body_print(fc,
1348214478Srpaulo		    (const struct mgmt_header_t *)(p - hdrlen), p, length)) {
134998524Sfenner			printf("[|802.11]");
1350127668Sbms			return hdrlen;
135198524Sfenner		}
135298524Sfenner		break;
135398524Sfenner	case T_CTRL:
1354127668Sbms		if (!ctrl_body_print(fc, p - hdrlen)) {
135598524Sfenner			printf("[|802.11]");
1356127668Sbms			return hdrlen;
135798524Sfenner		}
135898524Sfenner		break;
135998524Sfenner	case T_DATA:
1360172686Smlaier		if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
1361172686Smlaier			return hdrlen;	/* no-data frame */
136298524Sfenner		/* There may be a problem w/ AP not having this bit set */
1363127668Sbms		if (FC_WEP(fc)) {
1364127668Sbms			if (!wep_print(p)) {
136598524Sfenner				printf("[|802.11]");
1366127668Sbms				return hdrlen;
136798524Sfenner			}
1368127668Sbms		} else if (llc_print(p, length, caplen, dst, src,
1369127668Sbms		    &extracted_ethertype) == 0) {
1370127668Sbms			/*
1371127668Sbms			 * Some kinds of LLC packet we cannot
1372127668Sbms			 * handle intelligently
1373127668Sbms			 */
1374127668Sbms			if (!eflag)
1375195684Ssam				ieee_802_11_hdr_print(fc, p - hdrlen, hdrlen,
1376195684Ssam				    meshdrlen, NULL, NULL);
1377127668Sbms			if (extracted_ethertype)
1378127668Sbms				printf("(LLC %s) ",
1379127668Sbms				    etherproto_string(
1380127668Sbms				        htons(extracted_ethertype)));
1381162017Ssam			if (!suppress_default_print)
1382127668Sbms				default_print(p, caplen);
138398524Sfenner		}
138498524Sfenner		break;
138598524Sfenner	default:
1386127668Sbms		printf("unknown 802.11 frame type (%d)", FC_TYPE(fc));
138798524Sfenner		break;
138898524Sfenner	}
138998524Sfenner
1390127668Sbms	return hdrlen;
139198524Sfenner}
1392127668Sbms
1393127668Sbms/*
1394127668Sbms * This is the top level routine of the printer.  'p' points
1395127668Sbms * to the 802.11 header of the packet, 'h->ts' is the timestamp,
1396146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
1397127668Sbms * is the number of bytes actually captured.
1398127668Sbms */
1399127668Sbmsu_int
1400127668Sbmsieee802_11_if_print(const struct pcap_pkthdr *h, const u_char *p)
1401127668Sbms{
1402214478Srpaulo	return ieee802_11_print(p, h->len, h->caplen, 0, 0);
1403127668Sbms}
1404127668Sbms
1405170533Ssam#define	IEEE80211_CHAN_FHSS \
1406170533Ssam	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
1407170533Ssam#define	IEEE80211_CHAN_A \
1408170533Ssam	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
1409170533Ssam#define	IEEE80211_CHAN_B \
1410170533Ssam	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
1411170533Ssam#define	IEEE80211_CHAN_PUREG \
1412170533Ssam	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
1413170533Ssam#define	IEEE80211_CHAN_G \
1414170533Ssam	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
1415170533Ssam
1416170533Ssam#define	IS_CHAN_FHSS(flags) \
1417170533Ssam	((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
1418170533Ssam#define	IS_CHAN_A(flags) \
1419170533Ssam	((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
1420170533Ssam#define	IS_CHAN_B(flags) \
1421170533Ssam	((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
1422170533Ssam#define	IS_CHAN_PUREG(flags) \
1423170533Ssam	((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
1424170533Ssam#define	IS_CHAN_G(flags) \
1425170533Ssam	((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
1426170533Ssam#define	IS_CHAN_ANYG(flags) \
1427170533Ssam	(IS_CHAN_PUREG(flags) || IS_CHAN_G(flags))
1428170533Ssam
1429170533Ssamstatic void
1430170533Ssamprint_chaninfo(int freq, int flags)
1431170533Ssam{
1432170533Ssam	printf("%u MHz", freq);
1433170533Ssam	if (IS_CHAN_FHSS(flags))
1434170533Ssam		printf(" FHSS");
1435170533Ssam	if (IS_CHAN_A(flags)) {
1436170533Ssam		if (flags & IEEE80211_CHAN_HALF)
1437170533Ssam			printf(" 11a/10Mhz");
1438170533Ssam		else if (flags & IEEE80211_CHAN_QUARTER)
1439170533Ssam			printf(" 11a/5Mhz");
1440170533Ssam		else
1441170533Ssam			printf(" 11a");
1442170533Ssam	}
1443170533Ssam	if (IS_CHAN_ANYG(flags)) {
1444170533Ssam		if (flags & IEEE80211_CHAN_HALF)
1445170533Ssam			printf(" 11g/10Mhz");
1446170533Ssam		else if (flags & IEEE80211_CHAN_QUARTER)
1447170533Ssam			printf(" 11g/5Mhz");
1448170533Ssam		else
1449170533Ssam			printf(" 11g");
1450170533Ssam	} else if (IS_CHAN_B(flags))
1451170533Ssam		printf(" 11b");
1452170533Ssam	if (flags & IEEE80211_CHAN_TURBO)
1453170533Ssam		printf(" Turbo");
1454170533Ssam	if (flags & IEEE80211_CHAN_HT20)
1455170533Ssam		printf(" ht/20");
1456170533Ssam	else if (flags & IEEE80211_CHAN_HT40D)
1457170533Ssam		printf(" ht/40-");
1458170533Ssam	else if (flags & IEEE80211_CHAN_HT40U)
1459170533Ssam		printf(" ht/40+");
1460170533Ssam	printf(" ");
1461170533Ssam}
1462170533Ssam
1463146773Ssamstatic int
1464214478Srpauloprint_radiotap_field(struct cpack_state *s, u_int32_t bit, u_int8_t *flags)
1465146773Ssam{
1466146773Ssam	union {
1467146773Ssam		int8_t		i8;
1468146773Ssam		u_int8_t	u8;
1469146773Ssam		int16_t		i16;
1470146773Ssam		u_int16_t	u16;
1471146773Ssam		u_int32_t	u32;
1472146773Ssam		u_int64_t	u64;
1473170533Ssam	} u, u2, u3, u4;
1474146773Ssam	int rc;
1475146773Ssam
1476146773Ssam	switch (bit) {
1477146773Ssam	case IEEE80211_RADIOTAP_FLAGS:
1478172686Smlaier		rc = cpack_uint8(s, &u.u8);
1479214478Srpaulo		*flags = u.u8;
1480172686Smlaier		break;
1481146773Ssam	case IEEE80211_RADIOTAP_RATE:
1482146773Ssam	case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
1483146773Ssam	case IEEE80211_RADIOTAP_DB_ANTNOISE:
1484146773Ssam	case IEEE80211_RADIOTAP_ANTENNA:
1485146773Ssam		rc = cpack_uint8(s, &u.u8);
1486146773Ssam		break;
1487146773Ssam	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
1488146773Ssam	case IEEE80211_RADIOTAP_DBM_ANTNOISE:
1489146773Ssam		rc = cpack_int8(s, &u.i8);
1490146773Ssam		break;
1491146773Ssam	case IEEE80211_RADIOTAP_CHANNEL:
1492146773Ssam		rc = cpack_uint16(s, &u.u16);
1493146773Ssam		if (rc != 0)
1494146773Ssam			break;
1495146773Ssam		rc = cpack_uint16(s, &u2.u16);
1496146773Ssam		break;
1497146773Ssam	case IEEE80211_RADIOTAP_FHSS:
1498146773Ssam	case IEEE80211_RADIOTAP_LOCK_QUALITY:
1499146773Ssam	case IEEE80211_RADIOTAP_TX_ATTENUATION:
1500146773Ssam		rc = cpack_uint16(s, &u.u16);
1501146773Ssam		break;
1502146773Ssam	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
1503146773Ssam		rc = cpack_uint8(s, &u.u8);
1504146773Ssam		break;
1505146773Ssam	case IEEE80211_RADIOTAP_DBM_TX_POWER:
1506146773Ssam		rc = cpack_int8(s, &u.i8);
1507146773Ssam		break;
1508146773Ssam	case IEEE80211_RADIOTAP_TSFT:
1509146773Ssam		rc = cpack_uint64(s, &u.u64);
1510146773Ssam		break;
1511170533Ssam	case IEEE80211_RADIOTAP_XCHANNEL:
1512170533Ssam		rc = cpack_uint32(s, &u.u32);
1513170533Ssam		if (rc != 0)
1514170533Ssam			break;
1515170533Ssam		rc = cpack_uint16(s, &u2.u16);
1516170533Ssam		if (rc != 0)
1517170533Ssam			break;
1518170533Ssam		rc = cpack_uint8(s, &u3.u8);
1519170533Ssam		if (rc != 0)
1520170533Ssam			break;
1521170533Ssam		rc = cpack_uint8(s, &u4.u8);
1522170533Ssam		break;
1523146773Ssam	default:
1524146773Ssam		/* this bit indicates a field whose
1525146773Ssam		 * size we do not know, so we cannot
1526214478Srpaulo		 * proceed.  Just print the bit number.
1527146773Ssam		 */
1528214478Srpaulo		printf("[bit %u] ", bit);
1529146773Ssam		return -1;
1530146773Ssam	}
1531146773Ssam
1532146773Ssam	if (rc != 0) {
1533146773Ssam		printf("[|802.11]");
1534146773Ssam		return rc;
1535146773Ssam	}
1536146773Ssam
1537146773Ssam	switch (bit) {
1538146773Ssam	case IEEE80211_RADIOTAP_CHANNEL:
1539170533Ssam		print_chaninfo(u.u16, u2.u16);
1540146773Ssam		break;
1541146773Ssam	case IEEE80211_RADIOTAP_FHSS:
1542146773Ssam		printf("fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff);
1543146773Ssam		break;
1544146773Ssam	case IEEE80211_RADIOTAP_RATE:
1545170533Ssam		if (u.u8 & 0x80)
1546176535Ssam			PRINT_HT_RATE("", u.u8, " Mb/s ");
1547176535Ssam		else
1548170533Ssam			PRINT_RATE("", u.u8, " Mb/s ");
1549146773Ssam		break;
1550146773Ssam	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
1551146773Ssam		printf("%ddB signal ", u.i8);
1552146773Ssam		break;
1553146773Ssam	case IEEE80211_RADIOTAP_DBM_ANTNOISE:
1554146773Ssam		printf("%ddB noise ", u.i8);
1555146773Ssam		break;
1556146773Ssam	case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
1557146773Ssam		printf("%ddB signal ", u.u8);
1558146773Ssam		break;
1559146773Ssam	case IEEE80211_RADIOTAP_DB_ANTNOISE:
1560146773Ssam		printf("%ddB noise ", u.u8);
1561146773Ssam		break;
1562146773Ssam	case IEEE80211_RADIOTAP_LOCK_QUALITY:
1563146773Ssam		printf("%u sq ", u.u16);
1564146773Ssam		break;
1565146773Ssam	case IEEE80211_RADIOTAP_TX_ATTENUATION:
1566146773Ssam		printf("%d tx power ", -(int)u.u16);
1567146773Ssam		break;
1568146773Ssam	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
1569146773Ssam		printf("%ddB tx power ", -(int)u.u8);
1570146773Ssam		break;
1571146773Ssam	case IEEE80211_RADIOTAP_DBM_TX_POWER:
1572146773Ssam		printf("%ddBm tx power ", u.i8);
1573146773Ssam		break;
1574146773Ssam	case IEEE80211_RADIOTAP_FLAGS:
1575146773Ssam		if (u.u8 & IEEE80211_RADIOTAP_F_CFP)
1576146773Ssam			printf("cfp ");
1577146773Ssam		if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE)
1578146773Ssam			printf("short preamble ");
1579146773Ssam		if (u.u8 & IEEE80211_RADIOTAP_F_WEP)
1580146773Ssam			printf("wep ");
1581146773Ssam		if (u.u8 & IEEE80211_RADIOTAP_F_FRAG)
1582146773Ssam			printf("fragmented ");
1583170533Ssam		if (u.u8 & IEEE80211_RADIOTAP_F_BADFCS)
1584172686Smlaier			printf("bad-fcs ");
1585146773Ssam		break;
1586146773Ssam	case IEEE80211_RADIOTAP_ANTENNA:
1587146773Ssam		printf("antenna %d ", u.u8);
1588146773Ssam		break;
1589146773Ssam	case IEEE80211_RADIOTAP_TSFT:
1590146773Ssam		printf("%" PRIu64 "us tsft ", u.u64);
1591146773Ssam		break;
1592170533Ssam	case IEEE80211_RADIOTAP_XCHANNEL:
1593170533Ssam		print_chaninfo(u2.u16, u.u32);
1594170533Ssam		break;
1595146773Ssam	}
1596146773Ssam	return 0;
1597146773Ssam}
1598146773Ssam
1599127668Sbmsstatic u_int
1600127668Sbmsieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
1601127668Sbms{
1602146773Ssam#define	BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
1603146773Ssam#define	BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
1604146773Ssam#define	BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
1605146773Ssam#define	BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
1606146773Ssam#define	BITNO_2(x) (((x) & 2) ? 1 : 0)
1607214478Srpaulo#define	BIT(n)	(1U << n)
1608146773Ssam#define	IS_EXTENDED(__p)	\
1609146773Ssam	    (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
1610146773Ssam
1611146773Ssam	struct cpack_state cpacker;
1612146773Ssam	struct ieee80211_radiotap_header *hdr;
1613146773Ssam	u_int32_t present, next_present;
1614146773Ssam	u_int32_t *presentp, *last_presentp;
1615146773Ssam	enum ieee80211_radiotap_type bit;
1616146773Ssam	int bit0;
1617146773Ssam	const u_char *iter;
1618146773Ssam	u_int len;
1619214478Srpaulo	u_int8_t flags;
1620172686Smlaier	int pad;
1621214478Srpaulo	u_int fcslen;
1622146773Ssam
1623146773Ssam	if (caplen < sizeof(*hdr)) {
1624146773Ssam		printf("[|802.11]");
1625146773Ssam		return caplen;
1626146773Ssam	}
1627146773Ssam
1628146773Ssam	hdr = (struct ieee80211_radiotap_header *)p;
1629146773Ssam
1630146773Ssam	len = EXTRACT_LE_16BITS(&hdr->it_len);
1631146773Ssam
1632146773Ssam	if (caplen < len) {
1633146773Ssam		printf("[|802.11]");
1634146773Ssam		return caplen;
1635146773Ssam	}
1636146773Ssam	for (last_presentp = &hdr->it_present;
1637146773Ssam	     IS_EXTENDED(last_presentp) &&
1638146773Ssam	     (u_char*)(last_presentp + 1) <= p + len;
1639146773Ssam	     last_presentp++);
1640146773Ssam
1641146773Ssam	/* are there more bitmap extensions than bytes in header? */
1642146773Ssam	if (IS_EXTENDED(last_presentp)) {
1643146773Ssam		printf("[|802.11]");
1644146773Ssam		return caplen;
1645146773Ssam	}
1646146773Ssam
1647146773Ssam	iter = (u_char*)(last_presentp + 1);
1648146773Ssam
1649146773Ssam	if (cpack_init(&cpacker, (u_int8_t*)iter, len - (iter - p)) != 0) {
1650146773Ssam		/* XXX */
1651146773Ssam		printf("[|802.11]");
1652146773Ssam		return caplen;
1653146773Ssam	}
1654146773Ssam
1655214478Srpaulo	/* Assume no flags */
1656214478Srpaulo	flags = 0;
1657172686Smlaier	/* Assume no Atheros padding between 802.11 header and body */
1658172686Smlaier	pad = 0;
1659214478Srpaulo	/* Assume no FCS at end of frame */
1660214478Srpaulo	fcslen = 0;
1661146773Ssam	for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp;
1662146773Ssam	     presentp++, bit0 += 32) {
1663146773Ssam		for (present = EXTRACT_LE_32BITS(presentp); present;
1664146773Ssam		     present = next_present) {
1665146773Ssam			/* clear the least significant bit that is set */
1666146773Ssam			next_present = present & (present - 1);
1667146773Ssam
1668146773Ssam			/* extract the least significant bit that is set */
1669147899Ssam			bit = (enum ieee80211_radiotap_type)
1670147899Ssam			    (bit0 + BITNO_32(present ^ next_present));
1671146773Ssam
1672214478Srpaulo			if (print_radiotap_field(&cpacker, bit, &flags) != 0)
1673146773Ssam				goto out;
1674146773Ssam		}
1675146773Ssam	}
1676214478Srpaulo
1677214478Srpaulo	if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
1678214478Srpaulo		pad = 1;	/* Atheros padding */
1679214478Srpaulo	if (flags & IEEE80211_RADIOTAP_F_FCS)
1680214478Srpaulo		fcslen = 4;	/* FCS at end of packet */
1681146773Ssamout:
1682214478Srpaulo	return len + ieee802_11_print(p + len, length - len, caplen - len, pad,
1683214478Srpaulo	    fcslen);
1684146773Ssam#undef BITNO_32
1685146773Ssam#undef BITNO_16
1686146773Ssam#undef BITNO_8
1687146773Ssam#undef BITNO_4
1688146773Ssam#undef BITNO_2
1689146773Ssam#undef BIT
1690146773Ssam}
1691146773Ssam
1692146773Ssamstatic u_int
1693146773Ssamieee802_11_avs_radio_print(const u_char *p, u_int length, u_int caplen)
1694146773Ssam{
1695127668Sbms	u_int32_t caphdr_len;
1696127668Sbms
1697190207Srpaulo	if (caplen < 8) {
1698190207Srpaulo		printf("[|802.11]");
1699190207Srpaulo		return caplen;
1700190207Srpaulo	}
1701190207Srpaulo
1702127668Sbms	caphdr_len = EXTRACT_32BITS(p + 4);
1703127668Sbms	if (caphdr_len < 8) {
1704127668Sbms		/*
1705127668Sbms		 * Yow!  The capture header length is claimed not
1706127668Sbms		 * to be large enough to include even the version
1707127668Sbms		 * cookie or capture header length!
1708127668Sbms		 */
1709127668Sbms		printf("[|802.11]");
1710127668Sbms		return caplen;
1711127668Sbms	}
1712127668Sbms
1713127668Sbms	if (caplen < caphdr_len) {
1714127668Sbms		printf("[|802.11]");
1715127668Sbms		return caplen;
1716127668Sbms	}
1717127668Sbms
1718127668Sbms	return caphdr_len + ieee802_11_print(p + caphdr_len,
1719214478Srpaulo	    length - caphdr_len, caplen - caphdr_len, 0, 0);
1720127668Sbms}
1721127668Sbms
1722127668Sbms#define PRISM_HDR_LEN		144
1723127668Sbms
1724190207Srpaulo#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
1725127668Sbms#define WLANCAP_MAGIC_COOKIE_V1	0x80211001
1726190207Srpaulo#define WLANCAP_MAGIC_COOKIE_V2	0x80211002
1727127668Sbms
1728127668Sbms/*
1729127668Sbms * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
1730127668Sbms * containing information such as radio information, which we
1731127668Sbms * currently ignore.
1732127668Sbms *
1733190207Srpaulo * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or
1734190207Srpaulo * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS
1735190207Srpaulo * (currently, on Linux, there's no ARPHRD_ type for
1736190207Srpaulo * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM
1737190207Srpaulo * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for
1738190207Srpaulo * the AVS header, and the first 4 bytes of the header are used to
1739190207Srpaulo * indicate whether it's a Prism header or an AVS header).
1740127668Sbms */
1741127668Sbmsu_int
1742127668Sbmsprism_if_print(const struct pcap_pkthdr *h, const u_char *p)
1743127668Sbms{
1744127668Sbms	u_int caplen = h->caplen;
1745127668Sbms	u_int length = h->len;
1746190207Srpaulo	u_int32_t msgcode;
1747127668Sbms
1748127668Sbms	if (caplen < 4) {
1749127668Sbms		printf("[|802.11]");
1750127668Sbms		return caplen;
1751127668Sbms	}
1752127668Sbms
1753190207Srpaulo	msgcode = EXTRACT_32BITS(p);
1754190207Srpaulo	if (msgcode == WLANCAP_MAGIC_COOKIE_V1 ||
1755190207Srpaulo	    msgcode == WLANCAP_MAGIC_COOKIE_V2)
1756146773Ssam		return ieee802_11_avs_radio_print(p, length, caplen);
1757127668Sbms
1758127668Sbms	if (caplen < PRISM_HDR_LEN) {
1759127668Sbms		printf("[|802.11]");
1760127668Sbms		return caplen;
1761127668Sbms	}
1762127668Sbms
1763127668Sbms	return PRISM_HDR_LEN + ieee802_11_print(p + PRISM_HDR_LEN,
1764214478Srpaulo	    length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0, 0);
1765127668Sbms}
1766127668Sbms
1767127668Sbms/*
1768127668Sbms * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra
1769190207Srpaulo * header, containing information such as radio information.
1770127668Sbms */
1771127668Sbmsu_int
1772127668Sbmsieee802_11_radio_if_print(const struct pcap_pkthdr *h, const u_char *p)
1773127668Sbms{
1774190207Srpaulo	return ieee802_11_radio_print(p, h->len, h->caplen);
1775190207Srpaulo}
1776127668Sbms
1777190207Srpaulo/*
1778190207Srpaulo * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an
1779190207Srpaulo * extra header, containing information such as radio information,
1780190207Srpaulo * which we currently ignore.
1781190207Srpaulo */
1782190207Srpaulou_int
1783190207Srpauloieee802_11_radio_avs_if_print(const struct pcap_pkthdr *h, const u_char *p)
1784190207Srpaulo{
1785190207Srpaulo	return ieee802_11_avs_radio_print(p, h->len, h->caplen);
1786127668Sbms}
1787