xref: /dflybsd-src/sys/netproto/802_11/wlan/ieee80211_sta.c (revision 32176cfd8803dac7f65c423373f231a378375c86)
1*32176cfdSRui Paulo /*-
2*32176cfdSRui Paulo  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
3*32176cfdSRui Paulo  * All rights reserved.
4*32176cfdSRui Paulo  *
5*32176cfdSRui Paulo  * Redistribution and use in source and binary forms, with or without
6*32176cfdSRui Paulo  * modification, are permitted provided that the following conditions
7*32176cfdSRui Paulo  * are met:
8*32176cfdSRui Paulo  * 1. Redistributions of source code must retain the above copyright
9*32176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer.
10*32176cfdSRui Paulo  * 2. Redistributions in binary form must reproduce the above copyright
11*32176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer in the
12*32176cfdSRui Paulo  *    documentation and/or other materials provided with the distribution.
13*32176cfdSRui Paulo  *
14*32176cfdSRui Paulo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*32176cfdSRui Paulo  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*32176cfdSRui Paulo  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*32176cfdSRui Paulo  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*32176cfdSRui Paulo  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*32176cfdSRui Paulo  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*32176cfdSRui Paulo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*32176cfdSRui Paulo  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*32176cfdSRui Paulo  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*32176cfdSRui Paulo  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*32176cfdSRui Paulo  *
25*32176cfdSRui Paulo  * $FreeBSD: head/sys/net80211/ieee80211_sta.c 203422 2010-02-03 10:07:43Z rpaulo $
26*32176cfdSRui Paulo  * $DragonFly$
27*32176cfdSRui Paulo  */
28*32176cfdSRui Paulo 
29*32176cfdSRui Paulo /*
30*32176cfdSRui Paulo  * IEEE 802.11 Station mode support.
31*32176cfdSRui Paulo  */
32*32176cfdSRui Paulo #include "opt_inet.h"
33*32176cfdSRui Paulo #include "opt_wlan.h"
34*32176cfdSRui Paulo 
35*32176cfdSRui Paulo #include <sys/param.h>
36*32176cfdSRui Paulo #include <sys/systm.h>
37*32176cfdSRui Paulo #include <sys/mbuf.h>
38*32176cfdSRui Paulo #include <sys/malloc.h>
39*32176cfdSRui Paulo #include <sys/kernel.h>
40*32176cfdSRui Paulo 
41*32176cfdSRui Paulo #include <sys/socket.h>
42*32176cfdSRui Paulo #include <sys/sockio.h>
43*32176cfdSRui Paulo #include <sys/endian.h>
44*32176cfdSRui Paulo #include <sys/errno.h>
45*32176cfdSRui Paulo #include <sys/proc.h>
46*32176cfdSRui Paulo #include <sys/sysctl.h>
47*32176cfdSRui Paulo 
48*32176cfdSRui Paulo #include <net/if.h>
49*32176cfdSRui Paulo #include <net/if_media.h>
50*32176cfdSRui Paulo #include <net/if_llc.h>
51*32176cfdSRui Paulo #include <net/ethernet.h>
52*32176cfdSRui Paulo #include <net/route.h>
53*32176cfdSRui Paulo 
54*32176cfdSRui Paulo #include <net/bpf.h>
55*32176cfdSRui Paulo 
56*32176cfdSRui Paulo #include <netproto/802_11/ieee80211_var.h>
57*32176cfdSRui Paulo #include <netproto/802_11/ieee80211_sta.h>
58*32176cfdSRui Paulo #include <netproto/802_11/ieee80211_input.h>
59*32176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
60*32176cfdSRui Paulo #include <netproto/802_11/ieee80211_superg.h>
61*32176cfdSRui Paulo #endif
62*32176cfdSRui Paulo 
63*32176cfdSRui Paulo #define	IEEE80211_RATE2MBS(r)	(((r) & IEEE80211_RATE_VAL) / 2)
64*32176cfdSRui Paulo 
65*32176cfdSRui Paulo static	void sta_vattach(struct ieee80211vap *);
66*32176cfdSRui Paulo static	void sta_beacon_miss(struct ieee80211vap *);
67*32176cfdSRui Paulo static	int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int);
68*32176cfdSRui Paulo static	int sta_input(struct ieee80211_node *, struct mbuf *, int, int);
69*32176cfdSRui Paulo static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *,
70*32176cfdSRui Paulo 	    int subtype, int rssi, int nf);
71*32176cfdSRui Paulo static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
72*32176cfdSRui Paulo 
73*32176cfdSRui Paulo void
74*32176cfdSRui Paulo ieee80211_sta_attach(struct ieee80211com *ic)
75*32176cfdSRui Paulo {
76*32176cfdSRui Paulo 	ic->ic_vattach[IEEE80211_M_STA] = sta_vattach;
77*32176cfdSRui Paulo }
78*32176cfdSRui Paulo 
79*32176cfdSRui Paulo void
80*32176cfdSRui Paulo ieee80211_sta_detach(struct ieee80211com *ic)
81*32176cfdSRui Paulo {
82*32176cfdSRui Paulo }
83*32176cfdSRui Paulo 
84*32176cfdSRui Paulo static void
85*32176cfdSRui Paulo sta_vdetach(struct ieee80211vap *vap)
86*32176cfdSRui Paulo {
87*32176cfdSRui Paulo }
88*32176cfdSRui Paulo 
89*32176cfdSRui Paulo static void
90*32176cfdSRui Paulo sta_vattach(struct ieee80211vap *vap)
91*32176cfdSRui Paulo {
92*32176cfdSRui Paulo 	vap->iv_newstate = sta_newstate;
93*32176cfdSRui Paulo 	vap->iv_input = sta_input;
94*32176cfdSRui Paulo 	vap->iv_recv_mgmt = sta_recv_mgmt;
95*32176cfdSRui Paulo 	vap->iv_recv_ctl = sta_recv_ctl;
96*32176cfdSRui Paulo 	vap->iv_opdetach = sta_vdetach;
97*32176cfdSRui Paulo 	vap->iv_bmiss = sta_beacon_miss;
98*32176cfdSRui Paulo }
99*32176cfdSRui Paulo 
100*32176cfdSRui Paulo /*
101*32176cfdSRui Paulo  * Handle a beacon miss event.  The common code filters out
102*32176cfdSRui Paulo  * spurious events that can happen when scanning and/or before
103*32176cfdSRui Paulo  * reaching RUN state.
104*32176cfdSRui Paulo  */
105*32176cfdSRui Paulo static void
106*32176cfdSRui Paulo sta_beacon_miss(struct ieee80211vap *vap)
107*32176cfdSRui Paulo {
108*32176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
109*32176cfdSRui Paulo 
110*32176cfdSRui Paulo 	KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
111*32176cfdSRui Paulo 	KASSERT(vap->iv_state >= IEEE80211_S_RUN,
112*32176cfdSRui Paulo 	    ("wrong state %s", ieee80211_state_name[vap->iv_state]));
113*32176cfdSRui Paulo 
114*32176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
115*32176cfdSRui Paulo 	    "beacon miss, mode %s state %s\n",
116*32176cfdSRui Paulo 	    ieee80211_opmode_name[vap->iv_opmode],
117*32176cfdSRui Paulo 	    ieee80211_state_name[vap->iv_state]);
118*32176cfdSRui Paulo 
119*32176cfdSRui Paulo 	if (vap->iv_state == IEEE80211_S_CSA) {
120*32176cfdSRui Paulo 		/*
121*32176cfdSRui Paulo 		 * A Channel Switch is pending; assume we missed the
122*32176cfdSRui Paulo 		 * beacon that would've completed the process and just
123*32176cfdSRui Paulo 		 * force the switch.  If we made a mistake we'll not
124*32176cfdSRui Paulo 		 * find the AP on the new channel and fall back to a
125*32176cfdSRui Paulo 		 * normal scan.
126*32176cfdSRui Paulo 		 */
127*32176cfdSRui Paulo 		ieee80211_csa_completeswitch(ic);
128*32176cfdSRui Paulo 		return;
129*32176cfdSRui Paulo 	}
130*32176cfdSRui Paulo 	if (++vap->iv_bmiss_count < vap->iv_bmiss_max) {
131*32176cfdSRui Paulo 		/*
132*32176cfdSRui Paulo 		 * Send a directed probe req before falling back to a
133*32176cfdSRui Paulo 		 * scan; if we receive a response ic_bmiss_count will
134*32176cfdSRui Paulo 		 * be reset.  Some cards mistakenly report beacon miss
135*32176cfdSRui Paulo 		 * so this avoids the expensive scan if the ap is
136*32176cfdSRui Paulo 		 * still there.
137*32176cfdSRui Paulo 		 */
138*32176cfdSRui Paulo 		ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr,
139*32176cfdSRui Paulo 			vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid,
140*32176cfdSRui Paulo 			vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen);
141*32176cfdSRui Paulo 		return;
142*32176cfdSRui Paulo 	}
143*32176cfdSRui Paulo 	vap->iv_bmiss_count = 0;
144*32176cfdSRui Paulo 	vap->iv_stats.is_beacon_miss++;
145*32176cfdSRui Paulo 	if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
146*32176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
147*32176cfdSRui Paulo 		struct ieee80211com *ic = vap->iv_ic;
148*32176cfdSRui Paulo 
149*32176cfdSRui Paulo 		/*
150*32176cfdSRui Paulo 		 * If we receive a beacon miss interrupt when using
151*32176cfdSRui Paulo 		 * dynamic turbo, attempt to switch modes before
152*32176cfdSRui Paulo 		 * reassociating.
153*32176cfdSRui Paulo 		 */
154*32176cfdSRui Paulo 		if (IEEE80211_ATH_CAP(vap, vap->iv_bss, IEEE80211_NODE_TURBOP))
155*32176cfdSRui Paulo 			ieee80211_dturbo_switch(vap,
156*32176cfdSRui Paulo 			    ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO);
157*32176cfdSRui Paulo #endif
158*32176cfdSRui Paulo 		/*
159*32176cfdSRui Paulo 		 * Try to reassociate before scanning for a new ap.
160*32176cfdSRui Paulo 		 */
161*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
162*32176cfdSRui Paulo 	} else {
163*32176cfdSRui Paulo 		/*
164*32176cfdSRui Paulo 		 * Somebody else is controlling state changes (e.g.
165*32176cfdSRui Paulo 		 * a user-mode app) don't do anything that would
166*32176cfdSRui Paulo 		 * confuse them; just drop into scan mode so they'll
167*32176cfdSRui Paulo 		 * notified of the state change and given control.
168*32176cfdSRui Paulo 		 */
169*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
170*32176cfdSRui Paulo 	}
171*32176cfdSRui Paulo }
172*32176cfdSRui Paulo 
173*32176cfdSRui Paulo /*
174*32176cfdSRui Paulo  * Handle deauth with reason.  We retry only for
175*32176cfdSRui Paulo  * the cases where we might succeed.  Otherwise
176*32176cfdSRui Paulo  * we downgrade the ap and scan.
177*32176cfdSRui Paulo  */
178*32176cfdSRui Paulo static void
179*32176cfdSRui Paulo sta_authretry(struct ieee80211vap *vap, struct ieee80211_node *ni, int reason)
180*32176cfdSRui Paulo {
181*32176cfdSRui Paulo 	switch (reason) {
182*32176cfdSRui Paulo 	case IEEE80211_STATUS_SUCCESS:		/* NB: MLME assoc */
183*32176cfdSRui Paulo 	case IEEE80211_STATUS_TIMEOUT:
184*32176cfdSRui Paulo 	case IEEE80211_REASON_ASSOC_EXPIRE:
185*32176cfdSRui Paulo 	case IEEE80211_REASON_NOT_AUTHED:
186*32176cfdSRui Paulo 	case IEEE80211_REASON_NOT_ASSOCED:
187*32176cfdSRui Paulo 	case IEEE80211_REASON_ASSOC_LEAVE:
188*32176cfdSRui Paulo 	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
189*32176cfdSRui Paulo 		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1);
190*32176cfdSRui Paulo 		break;
191*32176cfdSRui Paulo 	default:
192*32176cfdSRui Paulo 		ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr, reason);
193*32176cfdSRui Paulo 		if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
194*32176cfdSRui Paulo 			ieee80211_check_scan_current(vap);
195*32176cfdSRui Paulo 		break;
196*32176cfdSRui Paulo 	}
197*32176cfdSRui Paulo }
198*32176cfdSRui Paulo 
199*32176cfdSRui Paulo /*
200*32176cfdSRui Paulo  * IEEE80211_M_STA vap state machine handler.
201*32176cfdSRui Paulo  * This routine handles the main states in the 802.11 protocol.
202*32176cfdSRui Paulo  */
203*32176cfdSRui Paulo static int
204*32176cfdSRui Paulo sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
205*32176cfdSRui Paulo {
206*32176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
207*32176cfdSRui Paulo 	struct ieee80211_node *ni;
208*32176cfdSRui Paulo 	enum ieee80211_state ostate;
209*32176cfdSRui Paulo 
210*32176cfdSRui Paulo 	IEEE80211_LOCK_ASSERT(ic);
211*32176cfdSRui Paulo 
212*32176cfdSRui Paulo 	ostate = vap->iv_state;
213*32176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
214*32176cfdSRui Paulo 	    __func__, ieee80211_state_name[ostate],
215*32176cfdSRui Paulo 	    ieee80211_state_name[nstate], arg);
216*32176cfdSRui Paulo 	vap->iv_state = nstate;			/* state transition */
217*32176cfdSRui Paulo 	callout_stop(&vap->iv_mgtsend);		/* XXX callout_drain */
218*32176cfdSRui Paulo 	if (ostate != IEEE80211_S_SCAN)
219*32176cfdSRui Paulo 		ieee80211_cancel_scan(vap);	/* background scan */
220*32176cfdSRui Paulo 	ni = vap->iv_bss;			/* NB: no reference held */
221*32176cfdSRui Paulo 	if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
222*32176cfdSRui Paulo 		callout_stop(&vap->iv_swbmiss);
223*32176cfdSRui Paulo 	switch (nstate) {
224*32176cfdSRui Paulo 	case IEEE80211_S_INIT:
225*32176cfdSRui Paulo 		switch (ostate) {
226*32176cfdSRui Paulo 		case IEEE80211_S_SLEEP:
227*32176cfdSRui Paulo 			/* XXX wakeup */
228*32176cfdSRui Paulo 		case IEEE80211_S_RUN:
229*32176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
230*32176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_DISASSOC,
231*32176cfdSRui Paulo 			    IEEE80211_REASON_ASSOC_LEAVE);
232*32176cfdSRui Paulo 			ieee80211_sta_leave(ni);
233*32176cfdSRui Paulo 			break;
234*32176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
235*32176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
236*32176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_DEAUTH,
237*32176cfdSRui Paulo 			    IEEE80211_REASON_AUTH_LEAVE);
238*32176cfdSRui Paulo 			break;
239*32176cfdSRui Paulo 		case IEEE80211_S_SCAN:
240*32176cfdSRui Paulo 			ieee80211_cancel_scan(vap);
241*32176cfdSRui Paulo 			break;
242*32176cfdSRui Paulo 		default:
243*32176cfdSRui Paulo 			goto invalid;
244*32176cfdSRui Paulo 		}
245*32176cfdSRui Paulo 		if (ostate != IEEE80211_S_INIT) {
246*32176cfdSRui Paulo 			/* NB: optimize INIT -> INIT case */
247*32176cfdSRui Paulo 			ieee80211_reset_bss(vap);
248*32176cfdSRui Paulo 		}
249*32176cfdSRui Paulo 		if (vap->iv_auth->ia_detach != NULL)
250*32176cfdSRui Paulo 			vap->iv_auth->ia_detach(vap);
251*32176cfdSRui Paulo 		break;
252*32176cfdSRui Paulo 	case IEEE80211_S_SCAN:
253*32176cfdSRui Paulo 		switch (ostate) {
254*32176cfdSRui Paulo 		case IEEE80211_S_INIT:
255*32176cfdSRui Paulo 			/*
256*32176cfdSRui Paulo 			 * Initiate a scan.  We can come here as a result
257*32176cfdSRui Paulo 			 * of an IEEE80211_IOC_SCAN_REQ too in which case
258*32176cfdSRui Paulo 			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
259*32176cfdSRui Paulo 			 * and the scan request parameters will be present
260*32176cfdSRui Paulo 			 * in iv_scanreq.  Otherwise we do the default.
261*32176cfdSRui Paulo 			 */
262*32176cfdSRui Paulo 			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
263*32176cfdSRui Paulo 				ieee80211_check_scan(vap,
264*32176cfdSRui Paulo 				    vap->iv_scanreq_flags,
265*32176cfdSRui Paulo 				    vap->iv_scanreq_duration,
266*32176cfdSRui Paulo 				    vap->iv_scanreq_mindwell,
267*32176cfdSRui Paulo 				    vap->iv_scanreq_maxdwell,
268*32176cfdSRui Paulo 				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
269*32176cfdSRui Paulo 				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
270*32176cfdSRui Paulo 			} else
271*32176cfdSRui Paulo 				ieee80211_check_scan_current(vap);
272*32176cfdSRui Paulo 			break;
273*32176cfdSRui Paulo 		case IEEE80211_S_SCAN:
274*32176cfdSRui Paulo 		case IEEE80211_S_AUTH:
275*32176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
276*32176cfdSRui Paulo 			/*
277*32176cfdSRui Paulo 			 * These can happen either because of a timeout
278*32176cfdSRui Paulo 			 * on an assoc/auth response or because of a
279*32176cfdSRui Paulo 			 * change in state that requires a reset.  For
280*32176cfdSRui Paulo 			 * the former we're called with a non-zero arg
281*32176cfdSRui Paulo 			 * that is the cause for the failure; pass this
282*32176cfdSRui Paulo 			 * to the scan code so it can update state.
283*32176cfdSRui Paulo 			 * Otherwise trigger a new scan unless we're in
284*32176cfdSRui Paulo 			 * manual roaming mode in which case an application
285*32176cfdSRui Paulo 			 * must issue an explicit scan request.
286*32176cfdSRui Paulo 			 */
287*32176cfdSRui Paulo 			if (arg != 0)
288*32176cfdSRui Paulo 				ieee80211_scan_assoc_fail(vap,
289*32176cfdSRui Paulo 					vap->iv_bss->ni_macaddr, arg);
290*32176cfdSRui Paulo 			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
291*32176cfdSRui Paulo 				ieee80211_check_scan_current(vap);
292*32176cfdSRui Paulo 			break;
293*32176cfdSRui Paulo 		case IEEE80211_S_RUN:		/* beacon miss */
294*32176cfdSRui Paulo 			/*
295*32176cfdSRui Paulo 			 * Beacon miss.  Notify user space and if not
296*32176cfdSRui Paulo 			 * under control of a user application (roaming
297*32176cfdSRui Paulo 			 * manual) kick off a scan to re-connect.
298*32176cfdSRui Paulo 			 */
299*32176cfdSRui Paulo 			ieee80211_sta_leave(ni);
300*32176cfdSRui Paulo 			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
301*32176cfdSRui Paulo 				ieee80211_check_scan_current(vap);
302*32176cfdSRui Paulo 			break;
303*32176cfdSRui Paulo 		default:
304*32176cfdSRui Paulo 			goto invalid;
305*32176cfdSRui Paulo 		}
306*32176cfdSRui Paulo 		break;
307*32176cfdSRui Paulo 	case IEEE80211_S_AUTH:
308*32176cfdSRui Paulo 		switch (ostate) {
309*32176cfdSRui Paulo 		case IEEE80211_S_INIT:
310*32176cfdSRui Paulo 		case IEEE80211_S_SCAN:
311*32176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
312*32176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_AUTH, 1);
313*32176cfdSRui Paulo 			break;
314*32176cfdSRui Paulo 		case IEEE80211_S_AUTH:
315*32176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
316*32176cfdSRui Paulo 			switch (arg & 0xff) {
317*32176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_AUTH:
318*32176cfdSRui Paulo 				/* ??? */
319*32176cfdSRui Paulo 				IEEE80211_SEND_MGMT(ni,
320*32176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
321*32176cfdSRui Paulo 				break;
322*32176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
323*32176cfdSRui Paulo 				sta_authretry(vap, ni, arg>>8);
324*32176cfdSRui Paulo 				break;
325*32176cfdSRui Paulo 			}
326*32176cfdSRui Paulo 			break;
327*32176cfdSRui Paulo 		case IEEE80211_S_RUN:
328*32176cfdSRui Paulo 			switch (arg & 0xff) {
329*32176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_AUTH:
330*32176cfdSRui Paulo 				IEEE80211_SEND_MGMT(ni,
331*32176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
332*32176cfdSRui Paulo 				vap->iv_state = ostate;	/* stay RUN */
333*32176cfdSRui Paulo 				break;
334*32176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
335*32176cfdSRui Paulo 				ieee80211_sta_leave(ni);
336*32176cfdSRui Paulo 				if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
337*32176cfdSRui Paulo 					/* try to reauth */
338*32176cfdSRui Paulo 					IEEE80211_SEND_MGMT(ni,
339*32176cfdSRui Paulo 					    IEEE80211_FC0_SUBTYPE_AUTH, 1);
340*32176cfdSRui Paulo 				}
341*32176cfdSRui Paulo 				break;
342*32176cfdSRui Paulo 			}
343*32176cfdSRui Paulo 			break;
344*32176cfdSRui Paulo 		default:
345*32176cfdSRui Paulo 			goto invalid;
346*32176cfdSRui Paulo 		}
347*32176cfdSRui Paulo 		break;
348*32176cfdSRui Paulo 	case IEEE80211_S_ASSOC:
349*32176cfdSRui Paulo 		switch (ostate) {
350*32176cfdSRui Paulo 		case IEEE80211_S_AUTH:
351*32176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
352*32176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
353*32176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
354*32176cfdSRui Paulo 			break;
355*32176cfdSRui Paulo 		case IEEE80211_S_SLEEP:		/* cannot happen */
356*32176cfdSRui Paulo 		case IEEE80211_S_RUN:
357*32176cfdSRui Paulo 			ieee80211_sta_leave(ni);
358*32176cfdSRui Paulo 			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
359*32176cfdSRui Paulo 				IEEE80211_SEND_MGMT(ni, arg ?
360*32176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_REASSOC_REQ :
361*32176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
362*32176cfdSRui Paulo 			}
363*32176cfdSRui Paulo 			break;
364*32176cfdSRui Paulo 		default:
365*32176cfdSRui Paulo 			goto invalid;
366*32176cfdSRui Paulo 		}
367*32176cfdSRui Paulo 		break;
368*32176cfdSRui Paulo 	case IEEE80211_S_RUN:
369*32176cfdSRui Paulo 		if (vap->iv_flags & IEEE80211_F_WPA) {
370*32176cfdSRui Paulo 			/* XXX validate prerequisites */
371*32176cfdSRui Paulo 		}
372*32176cfdSRui Paulo 		switch (ostate) {
373*32176cfdSRui Paulo 		case IEEE80211_S_RUN:
374*32176cfdSRui Paulo 		case IEEE80211_S_CSA:
375*32176cfdSRui Paulo 			break;
376*32176cfdSRui Paulo 		case IEEE80211_S_AUTH:		/* when join is done in fw */
377*32176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
378*32176cfdSRui Paulo #ifdef IEEE80211_DEBUG
379*32176cfdSRui Paulo 			if (ieee80211_msg_debug(vap)) {
380*32176cfdSRui Paulo 				ieee80211_note(vap, "%s with %s ssid ",
381*32176cfdSRui Paulo 				    (vap->iv_opmode == IEEE80211_M_STA ?
382*32176cfdSRui Paulo 				    "associated" : "synchronized"),
383*32176cfdSRui Paulo 				    ether_sprintf(ni->ni_bssid));
384*32176cfdSRui Paulo 				ieee80211_print_essid(vap->iv_bss->ni_essid,
385*32176cfdSRui Paulo 				    ni->ni_esslen);
386*32176cfdSRui Paulo 				/* XXX MCS/HT */
387*32176cfdSRui Paulo 				printf(" channel %d start %uMb\n",
388*32176cfdSRui Paulo 				    ieee80211_chan2ieee(ic, ic->ic_curchan),
389*32176cfdSRui Paulo 				    IEEE80211_RATE2MBS(ni->ni_txrate));
390*32176cfdSRui Paulo 			}
391*32176cfdSRui Paulo #endif
392*32176cfdSRui Paulo 			ieee80211_scan_assoc_success(vap, ni->ni_macaddr);
393*32176cfdSRui Paulo 			ieee80211_notify_node_join(ni,
394*32176cfdSRui Paulo 			    arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
395*32176cfdSRui Paulo 			break;
396*32176cfdSRui Paulo 		case IEEE80211_S_SLEEP:
397*32176cfdSRui Paulo 			ieee80211_sta_pwrsave(vap, 0);
398*32176cfdSRui Paulo 			break;
399*32176cfdSRui Paulo 		default:
400*32176cfdSRui Paulo 			goto invalid;
401*32176cfdSRui Paulo 		}
402*32176cfdSRui Paulo 		ieee80211_sync_curchan(ic);
403*32176cfdSRui Paulo 		if (ostate != IEEE80211_S_RUN &&
404*32176cfdSRui Paulo 		    (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
405*32176cfdSRui Paulo 			/*
406*32176cfdSRui Paulo 			 * Start s/w beacon miss timer for devices w/o
407*32176cfdSRui Paulo 			 * hardware support.  We fudge a bit here since
408*32176cfdSRui Paulo 			 * we're doing this in software.
409*32176cfdSRui Paulo 			 */
410*32176cfdSRui Paulo 			vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
411*32176cfdSRui Paulo 				2 * vap->iv_bmissthreshold * ni->ni_intval);
412*32176cfdSRui Paulo 			vap->iv_swbmiss_count = 0;
413*32176cfdSRui Paulo 			callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
414*32176cfdSRui Paulo 				ieee80211_swbmiss, vap);
415*32176cfdSRui Paulo 		}
416*32176cfdSRui Paulo 		/*
417*32176cfdSRui Paulo 		 * When 802.1x is not in use mark the port authorized
418*32176cfdSRui Paulo 		 * at this point so traffic can flow.
419*32176cfdSRui Paulo 		 */
420*32176cfdSRui Paulo 		if (ni->ni_authmode != IEEE80211_AUTH_8021X)
421*32176cfdSRui Paulo 			ieee80211_node_authorize(ni);
422*32176cfdSRui Paulo 		/*
423*32176cfdSRui Paulo 		 * Fake association when joining an existing bss.
424*32176cfdSRui Paulo 		 */
425*32176cfdSRui Paulo 		if (ic->ic_newassoc != NULL)
426*32176cfdSRui Paulo 			ic->ic_newassoc(vap->iv_bss, ostate != IEEE80211_S_RUN);
427*32176cfdSRui Paulo 		break;
428*32176cfdSRui Paulo 	case IEEE80211_S_CSA:
429*32176cfdSRui Paulo 		if (ostate != IEEE80211_S_RUN)
430*32176cfdSRui Paulo 			goto invalid;
431*32176cfdSRui Paulo 		break;
432*32176cfdSRui Paulo 	case IEEE80211_S_SLEEP:
433*32176cfdSRui Paulo 		ieee80211_sta_pwrsave(vap, 1);
434*32176cfdSRui Paulo 		break;
435*32176cfdSRui Paulo 	default:
436*32176cfdSRui Paulo 	invalid:
437*32176cfdSRui Paulo 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
438*32176cfdSRui Paulo 		    "%s: unexpected state transition %s -> %s\n", __func__,
439*32176cfdSRui Paulo 		    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
440*32176cfdSRui Paulo 		break;
441*32176cfdSRui Paulo 	}
442*32176cfdSRui Paulo 	return 0;
443*32176cfdSRui Paulo }
444*32176cfdSRui Paulo 
445*32176cfdSRui Paulo /*
446*32176cfdSRui Paulo  * Return non-zero if the frame is an echo of a multicast
447*32176cfdSRui Paulo  * frame sent by ourself.  The dir is known to be DSTODS.
448*32176cfdSRui Paulo  */
449*32176cfdSRui Paulo static __inline int
450*32176cfdSRui Paulo isdstods_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
451*32176cfdSRui Paulo {
452*32176cfdSRui Paulo #define	QWH4(wh)	((const struct ieee80211_qosframe_addr4 *)wh)
453*32176cfdSRui Paulo #define	WH4(wh)		((const struct ieee80211_frame_addr4 *)wh)
454*32176cfdSRui Paulo 	const uint8_t *sa;
455*32176cfdSRui Paulo 
456*32176cfdSRui Paulo 	KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode"));
457*32176cfdSRui Paulo 
458*32176cfdSRui Paulo 	if (!IEEE80211_IS_MULTICAST(wh->i_addr3))
459*32176cfdSRui Paulo 		return 0;
460*32176cfdSRui Paulo 	sa = IEEE80211_QOS_HAS_SEQ(wh) ? QWH4(wh)->i_addr4 : WH4(wh)->i_addr4;
461*32176cfdSRui Paulo 	return IEEE80211_ADDR_EQ(sa, vap->iv_myaddr);
462*32176cfdSRui Paulo #undef WH4
463*32176cfdSRui Paulo #undef QWH4
464*32176cfdSRui Paulo }
465*32176cfdSRui Paulo 
466*32176cfdSRui Paulo /*
467*32176cfdSRui Paulo  * Return non-zero if the frame is an echo of a multicast
468*32176cfdSRui Paulo  * frame sent by ourself.  The dir is known to be FROMDS.
469*32176cfdSRui Paulo  */
470*32176cfdSRui Paulo static __inline int
471*32176cfdSRui Paulo isfromds_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
472*32176cfdSRui Paulo {
473*32176cfdSRui Paulo 	KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode"));
474*32176cfdSRui Paulo 
475*32176cfdSRui Paulo 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
476*32176cfdSRui Paulo 		return 0;
477*32176cfdSRui Paulo 	return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
478*32176cfdSRui Paulo }
479*32176cfdSRui Paulo 
480*32176cfdSRui Paulo /*
481*32176cfdSRui Paulo  * Decide if a received management frame should be
482*32176cfdSRui Paulo  * printed when debugging is enabled.  This filters some
483*32176cfdSRui Paulo  * of the less interesting frames that come frequently
484*32176cfdSRui Paulo  * (e.g. beacons).
485*32176cfdSRui Paulo  */
486*32176cfdSRui Paulo static __inline int
487*32176cfdSRui Paulo doprint(struct ieee80211vap *vap, int subtype)
488*32176cfdSRui Paulo {
489*32176cfdSRui Paulo 	switch (subtype) {
490*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_BEACON:
491*32176cfdSRui Paulo 		return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN);
492*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
493*32176cfdSRui Paulo 		return 0;
494*32176cfdSRui Paulo 	}
495*32176cfdSRui Paulo 	return 1;
496*32176cfdSRui Paulo }
497*32176cfdSRui Paulo 
498*32176cfdSRui Paulo /*
499*32176cfdSRui Paulo  * Process a received frame.  The node associated with the sender
500*32176cfdSRui Paulo  * should be supplied.  If nothing was found in the node table then
501*32176cfdSRui Paulo  * the caller is assumed to supply a reference to iv_bss instead.
502*32176cfdSRui Paulo  * The RSSI and a timestamp are also supplied.  The RSSI data is used
503*32176cfdSRui Paulo  * during AP scanning to select a AP to associate with; it can have
504*32176cfdSRui Paulo  * any units so long as values have consistent units and higher values
505*32176cfdSRui Paulo  * mean ``better signal''.  The receive timestamp is currently not used
506*32176cfdSRui Paulo  * by the 802.11 layer.
507*32176cfdSRui Paulo  */
508*32176cfdSRui Paulo static int
509*32176cfdSRui Paulo sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
510*32176cfdSRui Paulo {
511*32176cfdSRui Paulo #define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
512*32176cfdSRui Paulo #define	HAS_SEQ(type)	((type & 0x4) == 0)
513*32176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
514*32176cfdSRui Paulo 	struct ieee80211com *ic = ni->ni_ic;
515*32176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
516*32176cfdSRui Paulo 	struct ieee80211_frame *wh;
517*32176cfdSRui Paulo 	struct ieee80211_key *key;
518*32176cfdSRui Paulo 	struct ether_header *eh;
519*32176cfdSRui Paulo 	int hdrspace, need_tap = 1;	/* mbuf need to be tapped. */
520*32176cfdSRui Paulo 	uint8_t dir, type, subtype, qos;
521*32176cfdSRui Paulo 	uint8_t *bssid;
522*32176cfdSRui Paulo 	uint16_t rxseq;
523*32176cfdSRui Paulo 
524*32176cfdSRui Paulo 	if (m->m_flags & M_AMPDU_MPDU) {
525*32176cfdSRui Paulo 		/*
526*32176cfdSRui Paulo 		 * Fastpath for A-MPDU reorder q resubmission.  Frames
527*32176cfdSRui Paulo 		 * w/ M_AMPDU_MPDU marked have already passed through
528*32176cfdSRui Paulo 		 * here but were received out of order and been held on
529*32176cfdSRui Paulo 		 * the reorder queue.  When resubmitted they are marked
530*32176cfdSRui Paulo 		 * with the M_AMPDU_MPDU flag and we can bypass most of
531*32176cfdSRui Paulo 		 * the normal processing.
532*32176cfdSRui Paulo 		 */
533*32176cfdSRui Paulo 		wh = mtod(m, struct ieee80211_frame *);
534*32176cfdSRui Paulo 		type = IEEE80211_FC0_TYPE_DATA;
535*32176cfdSRui Paulo 		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
536*32176cfdSRui Paulo 		subtype = IEEE80211_FC0_SUBTYPE_QOS;
537*32176cfdSRui Paulo 		hdrspace = ieee80211_hdrspace(ic, wh);	/* XXX optimize? */
538*32176cfdSRui Paulo 		goto resubmit_ampdu;
539*32176cfdSRui Paulo 	}
540*32176cfdSRui Paulo 
541*32176cfdSRui Paulo 	KASSERT(ni != NULL, ("null node"));
542*32176cfdSRui Paulo 	ni->ni_inact = ni->ni_inact_reload;
543*32176cfdSRui Paulo 
544*32176cfdSRui Paulo 	type = -1;			/* undefined */
545*32176cfdSRui Paulo 
546*32176cfdSRui Paulo 	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
547*32176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
548*32176cfdSRui Paulo 		    ni->ni_macaddr, NULL,
549*32176cfdSRui Paulo 		    "too short (1): len %u", m->m_pkthdr.len);
550*32176cfdSRui Paulo 		vap->iv_stats.is_rx_tooshort++;
551*32176cfdSRui Paulo 		goto out;
552*32176cfdSRui Paulo 	}
553*32176cfdSRui Paulo 	/*
554*32176cfdSRui Paulo 	 * Bit of a cheat here, we use a pointer for a 3-address
555*32176cfdSRui Paulo 	 * frame format but don't reference fields past outside
556*32176cfdSRui Paulo 	 * ieee80211_frame_min w/o first validating the data is
557*32176cfdSRui Paulo 	 * present.
558*32176cfdSRui Paulo 	 */
559*32176cfdSRui Paulo 	wh = mtod(m, struct ieee80211_frame *);
560*32176cfdSRui Paulo 
561*32176cfdSRui Paulo 	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
562*32176cfdSRui Paulo 	    IEEE80211_FC0_VERSION_0) {
563*32176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
564*32176cfdSRui Paulo 		    ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x",
565*32176cfdSRui Paulo 		    wh->i_fc[0], wh->i_fc[1]);
566*32176cfdSRui Paulo 		vap->iv_stats.is_rx_badversion++;
567*32176cfdSRui Paulo 		goto err;
568*32176cfdSRui Paulo 	}
569*32176cfdSRui Paulo 
570*32176cfdSRui Paulo 	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
571*32176cfdSRui Paulo 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
572*32176cfdSRui Paulo 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
573*32176cfdSRui Paulo 	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
574*32176cfdSRui Paulo 		bssid = wh->i_addr2;
575*32176cfdSRui Paulo 		if (!IEEE80211_ADDR_EQ(bssid, ni->ni_bssid)) {
576*32176cfdSRui Paulo 			/* not interested in */
577*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
578*32176cfdSRui Paulo 			    bssid, NULL, "%s", "not to bss");
579*32176cfdSRui Paulo 			vap->iv_stats.is_rx_wrongbss++;
580*32176cfdSRui Paulo 			goto out;
581*32176cfdSRui Paulo 		}
582*32176cfdSRui Paulo 		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
583*32176cfdSRui Paulo 		ni->ni_noise = nf;
584*32176cfdSRui Paulo 		if (HAS_SEQ(type)) {
585*32176cfdSRui Paulo 			uint8_t tid = ieee80211_gettid(wh);
586*32176cfdSRui Paulo 			if (IEEE80211_QOS_HAS_SEQ(wh) &&
587*32176cfdSRui Paulo 			    TID_TO_WME_AC(tid) >= WME_AC_VI)
588*32176cfdSRui Paulo 				ic->ic_wme.wme_hipri_traffic++;
589*32176cfdSRui Paulo 			rxseq = le16toh(*(uint16_t *)wh->i_seq);
590*32176cfdSRui Paulo 			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
591*32176cfdSRui Paulo 			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
592*32176cfdSRui Paulo 			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
593*32176cfdSRui Paulo 				/* duplicate, discard */
594*32176cfdSRui Paulo 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
595*32176cfdSRui Paulo 				    bssid, "duplicate",
596*32176cfdSRui Paulo 				    "seqno <%u,%u> fragno <%u,%u> tid %u",
597*32176cfdSRui Paulo 				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
598*32176cfdSRui Paulo 				    ni->ni_rxseqs[tid] >>
599*32176cfdSRui Paulo 					IEEE80211_SEQ_SEQ_SHIFT,
600*32176cfdSRui Paulo 				    rxseq & IEEE80211_SEQ_FRAG_MASK,
601*32176cfdSRui Paulo 				    ni->ni_rxseqs[tid] &
602*32176cfdSRui Paulo 					IEEE80211_SEQ_FRAG_MASK,
603*32176cfdSRui Paulo 				    tid);
604*32176cfdSRui Paulo 				vap->iv_stats.is_rx_dup++;
605*32176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_dup);
606*32176cfdSRui Paulo 				goto out;
607*32176cfdSRui Paulo 			}
608*32176cfdSRui Paulo 			ni->ni_rxseqs[tid] = rxseq;
609*32176cfdSRui Paulo 		}
610*32176cfdSRui Paulo 	}
611*32176cfdSRui Paulo 
612*32176cfdSRui Paulo 	switch (type) {
613*32176cfdSRui Paulo 	case IEEE80211_FC0_TYPE_DATA:
614*32176cfdSRui Paulo 		hdrspace = ieee80211_hdrspace(ic, wh);
615*32176cfdSRui Paulo 		if (m->m_len < hdrspace &&
616*32176cfdSRui Paulo 		    (m = m_pullup(m, hdrspace)) == NULL) {
617*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
618*32176cfdSRui Paulo 			    ni->ni_macaddr, NULL,
619*32176cfdSRui Paulo 			    "data too short: expecting %u", hdrspace);
620*32176cfdSRui Paulo 			vap->iv_stats.is_rx_tooshort++;
621*32176cfdSRui Paulo 			goto out;		/* XXX */
622*32176cfdSRui Paulo 		}
623*32176cfdSRui Paulo 		/*
624*32176cfdSRui Paulo 		 * Handle A-MPDU re-ordering.  If the frame is to be
625*32176cfdSRui Paulo 		 * processed directly then ieee80211_ampdu_reorder
626*32176cfdSRui Paulo 		 * will return 0; otherwise it has consumed the mbuf
627*32176cfdSRui Paulo 		 * and we should do nothing more with it.
628*32176cfdSRui Paulo 		 */
629*32176cfdSRui Paulo 		if ((m->m_flags & M_AMPDU) &&
630*32176cfdSRui Paulo 		    (dir == IEEE80211_FC1_DIR_FROMDS ||
631*32176cfdSRui Paulo 		     dir == IEEE80211_FC1_DIR_DSTODS) &&
632*32176cfdSRui Paulo 		    ieee80211_ampdu_reorder(ni, m) != 0) {
633*32176cfdSRui Paulo 			m = NULL;
634*32176cfdSRui Paulo 			goto out;
635*32176cfdSRui Paulo 		}
636*32176cfdSRui Paulo 	resubmit_ampdu:
637*32176cfdSRui Paulo 		if (dir == IEEE80211_FC1_DIR_FROMDS) {
638*32176cfdSRui Paulo 			if ((ifp->if_flags & IFF_SIMPLEX) &&
639*32176cfdSRui Paulo 			    isfromds_mcastecho(vap, wh)) {
640*32176cfdSRui Paulo 				/*
641*32176cfdSRui Paulo 				 * In IEEE802.11 network, multicast
642*32176cfdSRui Paulo 				 * packets sent from "me" are broadcast
643*32176cfdSRui Paulo 				 * from the AP; silently discard for
644*32176cfdSRui Paulo 				 * SIMPLEX interface.
645*32176cfdSRui Paulo 				 */
646*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
647*32176cfdSRui Paulo 				    wh, "data", "%s", "multicast echo");
648*32176cfdSRui Paulo 				vap->iv_stats.is_rx_mcastecho++;
649*32176cfdSRui Paulo 				goto out;
650*32176cfdSRui Paulo 			}
651*32176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_DWDS) &&
652*32176cfdSRui Paulo 			    IEEE80211_IS_MULTICAST(wh->i_addr1)) {
653*32176cfdSRui Paulo 				/*
654*32176cfdSRui Paulo 				 * DWDS sta's must drop 3-address mcast frames
655*32176cfdSRui Paulo 				 * as they will be sent separately as a 4-addr
656*32176cfdSRui Paulo 				 * frame.  Accepting the 3-addr frame will
657*32176cfdSRui Paulo 				 * confuse the bridge into thinking the sending
658*32176cfdSRui Paulo 				 * sta is located at the end of WDS link.
659*32176cfdSRui Paulo 				 */
660*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
661*32176cfdSRui Paulo 				    "3-address data", "%s", "DWDS enabled");
662*32176cfdSRui Paulo 				vap->iv_stats.is_rx_mcastecho++;
663*32176cfdSRui Paulo 				goto out;
664*32176cfdSRui Paulo 			}
665*32176cfdSRui Paulo 		} else if (dir == IEEE80211_FC1_DIR_DSTODS) {
666*32176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_DWDS) == 0) {
667*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap,
668*32176cfdSRui Paulo 				    IEEE80211_MSG_INPUT, wh, "4-address data",
669*32176cfdSRui Paulo 				    "%s", "DWDS not enabled");
670*32176cfdSRui Paulo 				vap->iv_stats.is_rx_wrongdir++;
671*32176cfdSRui Paulo 				goto out;
672*32176cfdSRui Paulo 			}
673*32176cfdSRui Paulo 			if ((ifp->if_flags & IFF_SIMPLEX) &&
674*32176cfdSRui Paulo 			    isdstods_mcastecho(vap, wh)) {
675*32176cfdSRui Paulo 				/*
676*32176cfdSRui Paulo 				 * In IEEE802.11 network, multicast
677*32176cfdSRui Paulo 				 * packets sent from "me" are broadcast
678*32176cfdSRui Paulo 				 * from the AP; silently discard for
679*32176cfdSRui Paulo 				 * SIMPLEX interface.
680*32176cfdSRui Paulo 				 */
681*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
682*32176cfdSRui Paulo 				    "4-address data", "%s", "multicast echo");
683*32176cfdSRui Paulo 				vap->iv_stats.is_rx_mcastecho++;
684*32176cfdSRui Paulo 				goto out;
685*32176cfdSRui Paulo 			}
686*32176cfdSRui Paulo 		} else {
687*32176cfdSRui Paulo 			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
688*32176cfdSRui Paulo 			    "data", "incorrect dir 0x%x", dir);
689*32176cfdSRui Paulo 			vap->iv_stats.is_rx_wrongdir++;
690*32176cfdSRui Paulo 			goto out;
691*32176cfdSRui Paulo 		}
692*32176cfdSRui Paulo 
693*32176cfdSRui Paulo 		/*
694*32176cfdSRui Paulo 		 * Handle privacy requirements.  Note that we
695*32176cfdSRui Paulo 		 * must not be preempted from here until after
696*32176cfdSRui Paulo 		 * we (potentially) call ieee80211_crypto_demic;
697*32176cfdSRui Paulo 		 * otherwise we may violate assumptions in the
698*32176cfdSRui Paulo 		 * crypto cipher modules used to do delayed update
699*32176cfdSRui Paulo 		 * of replay sequence numbers.
700*32176cfdSRui Paulo 		 */
701*32176cfdSRui Paulo 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
702*32176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
703*32176cfdSRui Paulo 				/*
704*32176cfdSRui Paulo 				 * Discard encrypted frames when privacy is off.
705*32176cfdSRui Paulo 				 */
706*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
707*32176cfdSRui Paulo 				    wh, "WEP", "%s", "PRIVACY off");
708*32176cfdSRui Paulo 				vap->iv_stats.is_rx_noprivacy++;
709*32176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_noprivacy);
710*32176cfdSRui Paulo 				goto out;
711*32176cfdSRui Paulo 			}
712*32176cfdSRui Paulo 			key = ieee80211_crypto_decap(ni, m, hdrspace);
713*32176cfdSRui Paulo 			if (key == NULL) {
714*32176cfdSRui Paulo 				/* NB: stats+msgs handled in crypto_decap */
715*32176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_wepfail);
716*32176cfdSRui Paulo 				goto out;
717*32176cfdSRui Paulo 			}
718*32176cfdSRui Paulo 			wh = mtod(m, struct ieee80211_frame *);
719*32176cfdSRui Paulo 			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
720*32176cfdSRui Paulo 		} else {
721*32176cfdSRui Paulo 			/* XXX M_WEP and IEEE80211_F_PRIVACY */
722*32176cfdSRui Paulo 			key = NULL;
723*32176cfdSRui Paulo 		}
724*32176cfdSRui Paulo 
725*32176cfdSRui Paulo 		/*
726*32176cfdSRui Paulo 		 * Save QoS bits for use below--before we strip the header.
727*32176cfdSRui Paulo 		 */
728*32176cfdSRui Paulo 		if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
729*32176cfdSRui Paulo 			qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
730*32176cfdSRui Paulo 			    ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
731*32176cfdSRui Paulo 			    ((struct ieee80211_qosframe *)wh)->i_qos[0];
732*32176cfdSRui Paulo 		} else
733*32176cfdSRui Paulo 			qos = 0;
734*32176cfdSRui Paulo 
735*32176cfdSRui Paulo 		/*
736*32176cfdSRui Paulo 		 * Next up, any fragmentation.
737*32176cfdSRui Paulo 		 */
738*32176cfdSRui Paulo 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
739*32176cfdSRui Paulo 			m = ieee80211_defrag(ni, m, hdrspace);
740*32176cfdSRui Paulo 			if (m == NULL) {
741*32176cfdSRui Paulo 				/* Fragment dropped or frame not complete yet */
742*32176cfdSRui Paulo 				goto out;
743*32176cfdSRui Paulo 			}
744*32176cfdSRui Paulo 		}
745*32176cfdSRui Paulo 		wh = NULL;		/* no longer valid, catch any uses */
746*32176cfdSRui Paulo 
747*32176cfdSRui Paulo 		/*
748*32176cfdSRui Paulo 		 * Next strip any MSDU crypto bits.
749*32176cfdSRui Paulo 		 */
750*32176cfdSRui Paulo 		if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) {
751*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
752*32176cfdSRui Paulo 			    ni->ni_macaddr, "data", "%s", "demic error");
753*32176cfdSRui Paulo 			vap->iv_stats.is_rx_demicfail++;
754*32176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_demicfail);
755*32176cfdSRui Paulo 			goto out;
756*32176cfdSRui Paulo 		}
757*32176cfdSRui Paulo 
758*32176cfdSRui Paulo 		/* copy to listener after decrypt */
759*32176cfdSRui Paulo 		if (ieee80211_radiotap_active_vap(vap))
760*32176cfdSRui Paulo 			ieee80211_radiotap_rx(vap, m);
761*32176cfdSRui Paulo 		need_tap = 0;
762*32176cfdSRui Paulo 
763*32176cfdSRui Paulo 		/*
764*32176cfdSRui Paulo 		 * Finally, strip the 802.11 header.
765*32176cfdSRui Paulo 		 */
766*32176cfdSRui Paulo 		m = ieee80211_decap(vap, m, hdrspace);
767*32176cfdSRui Paulo 		if (m == NULL) {
768*32176cfdSRui Paulo 			/* XXX mask bit to check for both */
769*32176cfdSRui Paulo 			/* don't count Null data frames as errors */
770*32176cfdSRui Paulo 			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA ||
771*32176cfdSRui Paulo 			    subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)
772*32176cfdSRui Paulo 				goto out;
773*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
774*32176cfdSRui Paulo 			    ni->ni_macaddr, "data", "%s", "decap error");
775*32176cfdSRui Paulo 			vap->iv_stats.is_rx_decap++;
776*32176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_decap);
777*32176cfdSRui Paulo 			goto err;
778*32176cfdSRui Paulo 		}
779*32176cfdSRui Paulo 		eh = mtod(m, struct ether_header *);
780*32176cfdSRui Paulo 		if (!ieee80211_node_is_authorized(ni)) {
781*32176cfdSRui Paulo 			/*
782*32176cfdSRui Paulo 			 * Deny any non-PAE frames received prior to
783*32176cfdSRui Paulo 			 * authorization.  For open/shared-key
784*32176cfdSRui Paulo 			 * authentication the port is mark authorized
785*32176cfdSRui Paulo 			 * after authentication completes.  For 802.1x
786*32176cfdSRui Paulo 			 * the port is not marked authorized by the
787*32176cfdSRui Paulo 			 * authenticator until the handshake has completed.
788*32176cfdSRui Paulo 			 */
789*32176cfdSRui Paulo 			if (eh->ether_type != htons(ETHERTYPE_PAE)) {
790*32176cfdSRui Paulo 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
791*32176cfdSRui Paulo 				    eh->ether_shost, "data",
792*32176cfdSRui Paulo 				    "unauthorized port: ether type 0x%x len %u",
793*32176cfdSRui Paulo 				    eh->ether_type, m->m_pkthdr.len);
794*32176cfdSRui Paulo 				vap->iv_stats.is_rx_unauth++;
795*32176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_unauth);
796*32176cfdSRui Paulo 				goto err;
797*32176cfdSRui Paulo 			}
798*32176cfdSRui Paulo 		} else {
799*32176cfdSRui Paulo 			/*
800*32176cfdSRui Paulo 			 * When denying unencrypted frames, discard
801*32176cfdSRui Paulo 			 * any non-PAE frames received without encryption.
802*32176cfdSRui Paulo 			 */
803*32176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
804*32176cfdSRui Paulo 			    (key == NULL && (m->m_flags & M_WEP) == 0) &&
805*32176cfdSRui Paulo 			    eh->ether_type != htons(ETHERTYPE_PAE)) {
806*32176cfdSRui Paulo 				/*
807*32176cfdSRui Paulo 				 * Drop unencrypted frames.
808*32176cfdSRui Paulo 				 */
809*32176cfdSRui Paulo 				vap->iv_stats.is_rx_unencrypted++;
810*32176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_unencrypted);
811*32176cfdSRui Paulo 				goto out;
812*32176cfdSRui Paulo 			}
813*32176cfdSRui Paulo 		}
814*32176cfdSRui Paulo 		/* XXX require HT? */
815*32176cfdSRui Paulo 		if (qos & IEEE80211_QOS_AMSDU) {
816*32176cfdSRui Paulo 			m = ieee80211_decap_amsdu(ni, m);
817*32176cfdSRui Paulo 			if (m == NULL)
818*32176cfdSRui Paulo 				return IEEE80211_FC0_TYPE_DATA;
819*32176cfdSRui Paulo 		} else {
820*32176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
821*32176cfdSRui Paulo 			m = ieee80211_decap_fastframe(vap, ni, m);
822*32176cfdSRui Paulo 			if (m == NULL)
823*32176cfdSRui Paulo 				return IEEE80211_FC0_TYPE_DATA;
824*32176cfdSRui Paulo #endif
825*32176cfdSRui Paulo 		}
826*32176cfdSRui Paulo 		ieee80211_deliver_data(vap, ni, m);
827*32176cfdSRui Paulo 		return IEEE80211_FC0_TYPE_DATA;
828*32176cfdSRui Paulo 
829*32176cfdSRui Paulo 	case IEEE80211_FC0_TYPE_MGT:
830*32176cfdSRui Paulo 		vap->iv_stats.is_rx_mgmt++;
831*32176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_mgmt);
832*32176cfdSRui Paulo 		if (dir != IEEE80211_FC1_DIR_NODS) {
833*32176cfdSRui Paulo 			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
834*32176cfdSRui Paulo 			    wh, "data", "incorrect dir 0x%x", dir);
835*32176cfdSRui Paulo 			vap->iv_stats.is_rx_wrongdir++;
836*32176cfdSRui Paulo 			goto err;
837*32176cfdSRui Paulo 		}
838*32176cfdSRui Paulo 		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
839*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
840*32176cfdSRui Paulo 			    ni->ni_macaddr, "mgt", "too short: len %u",
841*32176cfdSRui Paulo 			    m->m_pkthdr.len);
842*32176cfdSRui Paulo 			vap->iv_stats.is_rx_tooshort++;
843*32176cfdSRui Paulo 			goto out;
844*32176cfdSRui Paulo 		}
845*32176cfdSRui Paulo #ifdef IEEE80211_DEBUG
846*32176cfdSRui Paulo 		if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) ||
847*32176cfdSRui Paulo 		    ieee80211_msg_dumppkts(vap)) {
848*32176cfdSRui Paulo 			if_printf(ifp, "received %s from %s rssi %d\n",
849*32176cfdSRui Paulo 			    ieee80211_mgt_subtype_name[subtype >>
850*32176cfdSRui Paulo 				IEEE80211_FC0_SUBTYPE_SHIFT],
851*32176cfdSRui Paulo 			    ether_sprintf(wh->i_addr2), rssi);
852*32176cfdSRui Paulo 		}
853*32176cfdSRui Paulo #endif
854*32176cfdSRui Paulo 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
855*32176cfdSRui Paulo 			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
856*32176cfdSRui Paulo 				/*
857*32176cfdSRui Paulo 				 * Only shared key auth frames with a challenge
858*32176cfdSRui Paulo 				 * should be encrypted, discard all others.
859*32176cfdSRui Paulo 				 */
860*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
861*32176cfdSRui Paulo 				    wh, ieee80211_mgt_subtype_name[subtype >>
862*32176cfdSRui Paulo 					IEEE80211_FC0_SUBTYPE_SHIFT],
863*32176cfdSRui Paulo 				    "%s", "WEP set but not permitted");
864*32176cfdSRui Paulo 				vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
865*32176cfdSRui Paulo 				goto out;
866*32176cfdSRui Paulo 			}
867*32176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
868*32176cfdSRui Paulo 				/*
869*32176cfdSRui Paulo 				 * Discard encrypted frames when privacy is off.
870*32176cfdSRui Paulo 				 */
871*32176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
872*32176cfdSRui Paulo 				    wh, "mgt", "%s", "WEP set but PRIVACY off");
873*32176cfdSRui Paulo 				vap->iv_stats.is_rx_noprivacy++;
874*32176cfdSRui Paulo 				goto out;
875*32176cfdSRui Paulo 			}
876*32176cfdSRui Paulo 			hdrspace = ieee80211_hdrspace(ic, wh);
877*32176cfdSRui Paulo 			key = ieee80211_crypto_decap(ni, m, hdrspace);
878*32176cfdSRui Paulo 			if (key == NULL) {
879*32176cfdSRui Paulo 				/* NB: stats+msgs handled in crypto_decap */
880*32176cfdSRui Paulo 				goto out;
881*32176cfdSRui Paulo 			}
882*32176cfdSRui Paulo 			wh = mtod(m, struct ieee80211_frame *);
883*32176cfdSRui Paulo 			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
884*32176cfdSRui Paulo 		}
885*32176cfdSRui Paulo 		vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
886*32176cfdSRui Paulo 		goto out;
887*32176cfdSRui Paulo 
888*32176cfdSRui Paulo 	case IEEE80211_FC0_TYPE_CTL:
889*32176cfdSRui Paulo 		vap->iv_stats.is_rx_ctl++;
890*32176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_ctrl);
891*32176cfdSRui Paulo 		vap->iv_recv_ctl(ni, m, subtype);
892*32176cfdSRui Paulo 		goto out;
893*32176cfdSRui Paulo 
894*32176cfdSRui Paulo 	default:
895*32176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
896*32176cfdSRui Paulo 		    wh, NULL, "bad frame type 0x%x", type);
897*32176cfdSRui Paulo 		/* should not come here */
898*32176cfdSRui Paulo 		break;
899*32176cfdSRui Paulo 	}
900*32176cfdSRui Paulo err:
901*32176cfdSRui Paulo 	ifp->if_ierrors++;
902*32176cfdSRui Paulo out:
903*32176cfdSRui Paulo 	if (m != NULL) {
904*32176cfdSRui Paulo 		if (need_tap && ieee80211_radiotap_active_vap(vap))
905*32176cfdSRui Paulo 			ieee80211_radiotap_rx(vap, m);
906*32176cfdSRui Paulo 		m_freem(m);
907*32176cfdSRui Paulo 	}
908*32176cfdSRui Paulo 	return type;
909*32176cfdSRui Paulo #undef SEQ_LEQ
910*32176cfdSRui Paulo }
911*32176cfdSRui Paulo 
912*32176cfdSRui Paulo static void
913*32176cfdSRui Paulo sta_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
914*32176cfdSRui Paulo     int rssi, int nf, uint16_t seq, uint16_t status)
915*32176cfdSRui Paulo {
916*32176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
917*32176cfdSRui Paulo 
918*32176cfdSRui Paulo 	if (ni->ni_authmode == IEEE80211_AUTH_SHARED) {
919*32176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
920*32176cfdSRui Paulo 		    ni->ni_macaddr, "open auth",
921*32176cfdSRui Paulo 		    "bad sta auth mode %u", ni->ni_authmode);
922*32176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;	/* XXX */
923*32176cfdSRui Paulo 		return;
924*32176cfdSRui Paulo 	}
925*32176cfdSRui Paulo 	if (vap->iv_state != IEEE80211_S_AUTH ||
926*32176cfdSRui Paulo 	    seq != IEEE80211_AUTH_OPEN_RESPONSE) {
927*32176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;
928*32176cfdSRui Paulo 		return;
929*32176cfdSRui Paulo 	}
930*32176cfdSRui Paulo 	if (status != 0) {
931*32176cfdSRui Paulo 		IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
932*32176cfdSRui Paulo 		    ni, "open auth failed (reason %d)", status);
933*32176cfdSRui Paulo 		vap->iv_stats.is_rx_auth_fail++;
934*32176cfdSRui Paulo 		vap->iv_stats.is_rx_authfail_code = status;
935*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_SCAN,
936*32176cfdSRui Paulo 		    IEEE80211_SCAN_FAIL_STATUS);
937*32176cfdSRui Paulo 	} else
938*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
939*32176cfdSRui Paulo }
940*32176cfdSRui Paulo 
941*32176cfdSRui Paulo static void
942*32176cfdSRui Paulo sta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
943*32176cfdSRui Paulo     uint8_t *frm, uint8_t *efrm, int rssi, int nf,
944*32176cfdSRui Paulo     uint16_t seq, uint16_t status)
945*32176cfdSRui Paulo {
946*32176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
947*32176cfdSRui Paulo 	uint8_t *challenge;
948*32176cfdSRui Paulo 	int estatus;
949*32176cfdSRui Paulo 
950*32176cfdSRui Paulo 	/*
951*32176cfdSRui Paulo 	 * NB: this can happen as we allow pre-shared key
952*32176cfdSRui Paulo 	 * authentication to be enabled w/o wep being turned
953*32176cfdSRui Paulo 	 * on so that configuration of these can be done
954*32176cfdSRui Paulo 	 * in any order.  It may be better to enforce the
955*32176cfdSRui Paulo 	 * ordering in which case this check would just be
956*32176cfdSRui Paulo 	 * for sanity/consistency.
957*32176cfdSRui Paulo 	 */
958*32176cfdSRui Paulo 	if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
959*32176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
960*32176cfdSRui Paulo 		    ni->ni_macaddr, "shared key auth",
961*32176cfdSRui Paulo 		    "%s", " PRIVACY is disabled");
962*32176cfdSRui Paulo 		estatus = IEEE80211_STATUS_ALG;
963*32176cfdSRui Paulo 		goto bad;
964*32176cfdSRui Paulo 	}
965*32176cfdSRui Paulo 	/*
966*32176cfdSRui Paulo 	 * Pre-shared key authentication is evil; accept
967*32176cfdSRui Paulo 	 * it only if explicitly configured (it is supported
968*32176cfdSRui Paulo 	 * mainly for compatibility with clients like OS X).
969*32176cfdSRui Paulo 	 */
970*32176cfdSRui Paulo 	if (ni->ni_authmode != IEEE80211_AUTH_AUTO &&
971*32176cfdSRui Paulo 	    ni->ni_authmode != IEEE80211_AUTH_SHARED) {
972*32176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
973*32176cfdSRui Paulo 		    ni->ni_macaddr, "shared key auth",
974*32176cfdSRui Paulo 		    "bad sta auth mode %u", ni->ni_authmode);
975*32176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;	/* XXX maybe a unique error? */
976*32176cfdSRui Paulo 		estatus = IEEE80211_STATUS_ALG;
977*32176cfdSRui Paulo 		goto bad;
978*32176cfdSRui Paulo 	}
979*32176cfdSRui Paulo 
980*32176cfdSRui Paulo 	challenge = NULL;
981*32176cfdSRui Paulo 	if (frm + 1 < efrm) {
982*32176cfdSRui Paulo 		if ((frm[1] + 2) > (efrm - frm)) {
983*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
984*32176cfdSRui Paulo 			    ni->ni_macaddr, "shared key auth",
985*32176cfdSRui Paulo 			    "ie %d/%d too long",
986*32176cfdSRui Paulo 			    frm[0], (frm[1] + 2) - (efrm - frm));
987*32176cfdSRui Paulo 			vap->iv_stats.is_rx_bad_auth++;
988*32176cfdSRui Paulo 			estatus = IEEE80211_STATUS_CHALLENGE;
989*32176cfdSRui Paulo 			goto bad;
990*32176cfdSRui Paulo 		}
991*32176cfdSRui Paulo 		if (*frm == IEEE80211_ELEMID_CHALLENGE)
992*32176cfdSRui Paulo 			challenge = frm;
993*32176cfdSRui Paulo 		frm += frm[1] + 2;
994*32176cfdSRui Paulo 	}
995*32176cfdSRui Paulo 	switch (seq) {
996*32176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_CHALLENGE:
997*32176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_RESPONSE:
998*32176cfdSRui Paulo 		if (challenge == NULL) {
999*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
1000*32176cfdSRui Paulo 			    ni->ni_macaddr, "shared key auth",
1001*32176cfdSRui Paulo 			    "%s", "no challenge");
1002*32176cfdSRui Paulo 			vap->iv_stats.is_rx_bad_auth++;
1003*32176cfdSRui Paulo 			estatus = IEEE80211_STATUS_CHALLENGE;
1004*32176cfdSRui Paulo 			goto bad;
1005*32176cfdSRui Paulo 		}
1006*32176cfdSRui Paulo 		if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
1007*32176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
1008*32176cfdSRui Paulo 			    ni->ni_macaddr, "shared key auth",
1009*32176cfdSRui Paulo 			    "bad challenge len %d", challenge[1]);
1010*32176cfdSRui Paulo 			vap->iv_stats.is_rx_bad_auth++;
1011*32176cfdSRui Paulo 			estatus = IEEE80211_STATUS_CHALLENGE;
1012*32176cfdSRui Paulo 			goto bad;
1013*32176cfdSRui Paulo 		}
1014*32176cfdSRui Paulo 	default:
1015*32176cfdSRui Paulo 		break;
1016*32176cfdSRui Paulo 	}
1017*32176cfdSRui Paulo 	if (vap->iv_state != IEEE80211_S_AUTH)
1018*32176cfdSRui Paulo 		return;
1019*32176cfdSRui Paulo 	switch (seq) {
1020*32176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_PASS:
1021*32176cfdSRui Paulo 		if (ni->ni_challenge != NULL) {
1022*32176cfdSRui Paulo 			kfree(ni->ni_challenge, M_80211_NODE);
1023*32176cfdSRui Paulo 			ni->ni_challenge = NULL;
1024*32176cfdSRui Paulo 		}
1025*32176cfdSRui Paulo 		if (status != 0) {
1026*32176cfdSRui Paulo 			IEEE80211_NOTE_FRAME(vap,
1027*32176cfdSRui Paulo 			    IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, wh,
1028*32176cfdSRui Paulo 			    "shared key auth failed (reason %d)", status);
1029*32176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_fail++;
1030*32176cfdSRui Paulo 			vap->iv_stats.is_rx_authfail_code = status;
1031*32176cfdSRui Paulo 			return;
1032*32176cfdSRui Paulo 		}
1033*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
1034*32176cfdSRui Paulo 		break;
1035*32176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_CHALLENGE:
1036*32176cfdSRui Paulo 		if (!ieee80211_alloc_challenge(ni))
1037*32176cfdSRui Paulo 			return;
1038*32176cfdSRui Paulo 		/* XXX could optimize by passing recvd challenge */
1039*32176cfdSRui Paulo 		memcpy(ni->ni_challenge, &challenge[2], challenge[1]);
1040*32176cfdSRui Paulo 		IEEE80211_SEND_MGMT(ni,
1041*32176cfdSRui Paulo 			IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
1042*32176cfdSRui Paulo 		break;
1043*32176cfdSRui Paulo 	default:
1044*32176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_AUTH,
1045*32176cfdSRui Paulo 		    wh, "shared key auth", "bad seq %d", seq);
1046*32176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;
1047*32176cfdSRui Paulo 		return;
1048*32176cfdSRui Paulo 	}
1049*32176cfdSRui Paulo 	return;
1050*32176cfdSRui Paulo bad:
1051*32176cfdSRui Paulo 	/*
1052*32176cfdSRui Paulo 	 * Kick the state machine.  This short-circuits
1053*32176cfdSRui Paulo 	 * using the mgt frame timeout to trigger the
1054*32176cfdSRui Paulo 	 * state transition.
1055*32176cfdSRui Paulo 	 */
1056*32176cfdSRui Paulo 	if (vap->iv_state == IEEE80211_S_AUTH)
1057*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_SCAN,
1058*32176cfdSRui Paulo 		    IEEE80211_SCAN_FAIL_STATUS);
1059*32176cfdSRui Paulo }
1060*32176cfdSRui Paulo 
1061*32176cfdSRui Paulo static int
1062*32176cfdSRui Paulo ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
1063*32176cfdSRui Paulo 	const struct ieee80211_frame *wh)
1064*32176cfdSRui Paulo {
1065*32176cfdSRui Paulo #define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
1066*32176cfdSRui Paulo 	struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme;
1067*32176cfdSRui Paulo 	u_int len = frm[1], qosinfo;
1068*32176cfdSRui Paulo 	int i;
1069*32176cfdSRui Paulo 
1070*32176cfdSRui Paulo 	if (len < sizeof(struct ieee80211_wme_param)-2) {
1071*32176cfdSRui Paulo 		IEEE80211_DISCARD_IE(vap,
1072*32176cfdSRui Paulo 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
1073*32176cfdSRui Paulo 		    wh, "WME", "too short, len %u", len);
1074*32176cfdSRui Paulo 		return -1;
1075*32176cfdSRui Paulo 	}
1076*32176cfdSRui Paulo 	qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)];
1077*32176cfdSRui Paulo 	qosinfo &= WME_QOSINFO_COUNT;
1078*32176cfdSRui Paulo 	/* XXX do proper check for wraparound */
1079*32176cfdSRui Paulo 	if (qosinfo == wme->wme_wmeChanParams.cap_info)
1080*32176cfdSRui Paulo 		return 0;
1081*32176cfdSRui Paulo 	frm += __offsetof(struct ieee80211_wme_param, params_acParams);
1082*32176cfdSRui Paulo 	for (i = 0; i < WME_NUM_AC; i++) {
1083*32176cfdSRui Paulo 		struct wmeParams *wmep =
1084*32176cfdSRui Paulo 			&wme->wme_wmeChanParams.cap_wmeParams[i];
1085*32176cfdSRui Paulo 		/* NB: ACI not used */
1086*32176cfdSRui Paulo 		wmep->wmep_acm = MS(frm[0], WME_PARAM_ACM);
1087*32176cfdSRui Paulo 		wmep->wmep_aifsn = MS(frm[0], WME_PARAM_AIFSN);
1088*32176cfdSRui Paulo 		wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN);
1089*32176cfdSRui Paulo 		wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX);
1090*32176cfdSRui Paulo 		wmep->wmep_txopLimit = LE_READ_2(frm+2);
1091*32176cfdSRui Paulo 		frm += 4;
1092*32176cfdSRui Paulo 	}
1093*32176cfdSRui Paulo 	wme->wme_wmeChanParams.cap_info = qosinfo;
1094*32176cfdSRui Paulo 	return 1;
1095*32176cfdSRui Paulo #undef MS
1096*32176cfdSRui Paulo }
1097*32176cfdSRui Paulo 
1098*32176cfdSRui Paulo /*
1099*32176cfdSRui Paulo  * Process 11h Channel Switch Announcement (CSA) ie.  If this
1100*32176cfdSRui Paulo  * is the first CSA then initiate the switch.  Otherwise we
1101*32176cfdSRui Paulo  * track state and trigger completion and/or cancel of the switch.
1102*32176cfdSRui Paulo  * XXX should be public for IBSS use
1103*32176cfdSRui Paulo  */
1104*32176cfdSRui Paulo static void
1105*32176cfdSRui Paulo ieee80211_parse_csaparams(struct ieee80211vap *vap, uint8_t *frm,
1106*32176cfdSRui Paulo 	const struct ieee80211_frame *wh)
1107*32176cfdSRui Paulo {
1108*32176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
1109*32176cfdSRui Paulo 	const struct ieee80211_csa_ie *csa =
1110*32176cfdSRui Paulo 	    (const struct ieee80211_csa_ie *) frm;
1111*32176cfdSRui Paulo 
1112*32176cfdSRui Paulo 	KASSERT(vap->iv_state >= IEEE80211_S_RUN,
1113*32176cfdSRui Paulo 	    ("state %s", ieee80211_state_name[vap->iv_state]));
1114*32176cfdSRui Paulo 
1115*32176cfdSRui Paulo 	if (csa->csa_mode > 1) {
1116*32176cfdSRui Paulo 		IEEE80211_DISCARD_IE(vap,
1117*32176cfdSRui Paulo 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
1118*32176cfdSRui Paulo 		    wh, "CSA", "invalid mode %u", csa->csa_mode);
1119*32176cfdSRui Paulo 		return;
1120*32176cfdSRui Paulo 	}
1121*32176cfdSRui Paulo 	IEEE80211_LOCK(ic);
1122*32176cfdSRui Paulo 	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
1123*32176cfdSRui Paulo 		/*
1124*32176cfdSRui Paulo 		 * Convert the channel number to a channel reference.  We
1125*32176cfdSRui Paulo 		 * try first to preserve turbo attribute of the current
1126*32176cfdSRui Paulo 		 * channel then fallback.  Note this will not work if the
1127*32176cfdSRui Paulo 		 * CSA specifies a channel that requires a band switch (e.g.
1128*32176cfdSRui Paulo 		 * 11a => 11g).  This is intentional as 11h is defined only
1129*32176cfdSRui Paulo 		 * for 5GHz/11a and because the switch does not involve a
1130*32176cfdSRui Paulo 		 * reassociation, protocol state (capabilities, negotated
1131*32176cfdSRui Paulo 		 * rates, etc) may/will be wrong.
1132*32176cfdSRui Paulo 		 */
1133*32176cfdSRui Paulo 		struct ieee80211_channel *c =
1134*32176cfdSRui Paulo 		    ieee80211_find_channel_byieee(ic, csa->csa_newchan,
1135*32176cfdSRui Paulo 			(ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALLTURBO));
1136*32176cfdSRui Paulo 		if (c == NULL) {
1137*32176cfdSRui Paulo 			c = ieee80211_find_channel_byieee(ic,
1138*32176cfdSRui Paulo 			    csa->csa_newchan,
1139*32176cfdSRui Paulo 			    (ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALL));
1140*32176cfdSRui Paulo 			if (c == NULL) {
1141*32176cfdSRui Paulo 				IEEE80211_DISCARD_IE(vap,
1142*32176cfdSRui Paulo 				    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
1143*32176cfdSRui Paulo 				    wh, "CSA", "invalid channel %u",
1144*32176cfdSRui Paulo 				    csa->csa_newchan);
1145*32176cfdSRui Paulo 				goto done;
1146*32176cfdSRui Paulo 			}
1147*32176cfdSRui Paulo 		}
1148*32176cfdSRui Paulo #if IEEE80211_CSA_COUNT_MIN > 0
1149*32176cfdSRui Paulo 		if (csa->csa_count < IEEE80211_CSA_COUNT_MIN) {
1150*32176cfdSRui Paulo 			/*
1151*32176cfdSRui Paulo 			 * Require at least IEEE80211_CSA_COUNT_MIN count to
1152*32176cfdSRui Paulo 			 * reduce the risk of being redirected by a fabricated
1153*32176cfdSRui Paulo 			 * CSA.  If a valid CSA is dropped we'll still get a
1154*32176cfdSRui Paulo 			 * beacon miss when the AP leaves the channel so we'll
1155*32176cfdSRui Paulo 			 * eventually follow to the new channel.
1156*32176cfdSRui Paulo 			 *
1157*32176cfdSRui Paulo 			 * NOTE: this violates the 11h spec that states that
1158*32176cfdSRui Paulo 			 * count may be any value and if 0 then a switch
1159*32176cfdSRui Paulo 			 * should happen asap.
1160*32176cfdSRui Paulo 			 */
1161*32176cfdSRui Paulo 			IEEE80211_DISCARD_IE(vap,
1162*32176cfdSRui Paulo 			    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
1163*32176cfdSRui Paulo 			    wh, "CSA", "count %u too small, must be >= %u",
1164*32176cfdSRui Paulo 			    csa->csa_count, IEEE80211_CSA_COUNT_MIN);
1165*32176cfdSRui Paulo 			goto done;
1166*32176cfdSRui Paulo 		}
1167*32176cfdSRui Paulo #endif
1168*32176cfdSRui Paulo 		ieee80211_csa_startswitch(ic, c, csa->csa_mode, csa->csa_count);
1169*32176cfdSRui Paulo 	} else {
1170*32176cfdSRui Paulo 		/*
1171*32176cfdSRui Paulo 		 * Validate this ie against the initial CSA.  We require
1172*32176cfdSRui Paulo 		 * mode and channel not change and the count must be
1173*32176cfdSRui Paulo 		 * monotonically decreasing.  This may be pointless and
1174*32176cfdSRui Paulo 		 * canceling the switch as a result may be too paranoid but
1175*32176cfdSRui Paulo 		 * in the worst case if we drop out of CSA because of this
1176*32176cfdSRui Paulo 		 * and the AP does move then we'll just end up taking a
1177*32176cfdSRui Paulo 		 * beacon miss and scan to find the AP.
1178*32176cfdSRui Paulo 		 *
1179*32176cfdSRui Paulo 		 * XXX may want <= on count as we also process ProbeResp
1180*32176cfdSRui Paulo 		 * frames and those may come in w/ the same count as the
1181*32176cfdSRui Paulo 		 * previous beacon; but doing so leaves us open to a stuck
1182*32176cfdSRui Paulo 		 * count until we add a dead-man timer
1183*32176cfdSRui Paulo 		 */
1184*32176cfdSRui Paulo 		if (!(csa->csa_count < ic->ic_csa_count &&
1185*32176cfdSRui Paulo 		      csa->csa_mode == ic->ic_csa_mode &&
1186*32176cfdSRui Paulo 		      csa->csa_newchan == ieee80211_chan2ieee(ic, ic->ic_csa_newchan))) {
1187*32176cfdSRui Paulo 			IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_DOTH, wh,
1188*32176cfdSRui Paulo 			    "CSA ie mismatch, initial ie <%d,%d,%d>, "
1189*32176cfdSRui Paulo 			    "this ie <%d,%d,%d>", ic->ic_csa_mode,
1190*32176cfdSRui Paulo 			    ic->ic_csa_newchan, ic->ic_csa_count,
1191*32176cfdSRui Paulo 			    csa->csa_mode, csa->csa_newchan, csa->csa_count);
1192*32176cfdSRui Paulo 			ieee80211_csa_cancelswitch(ic);
1193*32176cfdSRui Paulo 		} else {
1194*32176cfdSRui Paulo 			if (csa->csa_count <= 1)
1195*32176cfdSRui Paulo 				ieee80211_csa_completeswitch(ic);
1196*32176cfdSRui Paulo 			else
1197*32176cfdSRui Paulo 				ic->ic_csa_count = csa->csa_count;
1198*32176cfdSRui Paulo 		}
1199*32176cfdSRui Paulo 	}
1200*32176cfdSRui Paulo done:
1201*32176cfdSRui Paulo 	IEEE80211_UNLOCK(ic);
1202*32176cfdSRui Paulo }
1203*32176cfdSRui Paulo 
1204*32176cfdSRui Paulo /*
1205*32176cfdSRui Paulo  * Return non-zero if a background scan may be continued:
1206*32176cfdSRui Paulo  * o bg scan is active
1207*32176cfdSRui Paulo  * o no channel switch is pending
1208*32176cfdSRui Paulo  * o there has not been any traffic recently
1209*32176cfdSRui Paulo  *
1210*32176cfdSRui Paulo  * Note we do not check if there is an administrative enable;
1211*32176cfdSRui Paulo  * this is only done to start the scan.  We assume that any
1212*32176cfdSRui Paulo  * change in state will be accompanied by a request to cancel
1213*32176cfdSRui Paulo  * active scans which will otherwise cause this test to fail.
1214*32176cfdSRui Paulo  */
1215*32176cfdSRui Paulo static __inline int
1216*32176cfdSRui Paulo contbgscan(struct ieee80211vap *vap)
1217*32176cfdSRui Paulo {
1218*32176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
1219*32176cfdSRui Paulo 
1220*32176cfdSRui Paulo 	return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
1221*32176cfdSRui Paulo 	    (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
1222*32176cfdSRui Paulo 	    vap->iv_state == IEEE80211_S_RUN &&		/* XXX? */
1223*32176cfdSRui Paulo 	    time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
1224*32176cfdSRui Paulo }
1225*32176cfdSRui Paulo 
1226*32176cfdSRui Paulo /*
1227*32176cfdSRui Paulo  * Return non-zero if a backgrond scan may be started:
1228*32176cfdSRui Paulo  * o bg scanning is administratively enabled
1229*32176cfdSRui Paulo  * o no channel switch is pending
1230*32176cfdSRui Paulo  * o we are not boosted on a dynamic turbo channel
1231*32176cfdSRui Paulo  * o there has not been a scan recently
1232*32176cfdSRui Paulo  * o there has not been any traffic recently
1233*32176cfdSRui Paulo  */
1234*32176cfdSRui Paulo static __inline int
1235*32176cfdSRui Paulo startbgscan(struct ieee80211vap *vap)
1236*32176cfdSRui Paulo {
1237*32176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
1238*32176cfdSRui Paulo 
1239*32176cfdSRui Paulo 	return ((vap->iv_flags & IEEE80211_F_BGSCAN) &&
1240*32176cfdSRui Paulo 	    (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
1241*32176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
1242*32176cfdSRui Paulo 	    !IEEE80211_IS_CHAN_DTURBO(ic->ic_curchan) &&
1243*32176cfdSRui Paulo #endif
1244*32176cfdSRui Paulo 	    time_after(ticks, ic->ic_lastscan + vap->iv_bgscanintvl) &&
1245*32176cfdSRui Paulo 	    time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
1246*32176cfdSRui Paulo }
1247*32176cfdSRui Paulo 
1248*32176cfdSRui Paulo static void
1249*32176cfdSRui Paulo sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
1250*32176cfdSRui Paulo 	int subtype, int rssi, int nf)
1251*32176cfdSRui Paulo {
1252*32176cfdSRui Paulo #define	ISPROBE(_st)	((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
1253*32176cfdSRui Paulo #define	ISREASSOC(_st)	((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
1254*32176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
1255*32176cfdSRui Paulo 	struct ieee80211com *ic = ni->ni_ic;
1256*32176cfdSRui Paulo 	struct ieee80211_frame *wh;
1257*32176cfdSRui Paulo 	uint8_t *frm, *efrm;
1258*32176cfdSRui Paulo 	uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
1259*32176cfdSRui Paulo 	uint8_t rate;
1260*32176cfdSRui Paulo 
1261*32176cfdSRui Paulo 	wh = mtod(m0, struct ieee80211_frame *);
1262*32176cfdSRui Paulo 	frm = (uint8_t *)&wh[1];
1263*32176cfdSRui Paulo 	efrm = mtod(m0, uint8_t *) + m0->m_len;
1264*32176cfdSRui Paulo 	switch (subtype) {
1265*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
1266*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_BEACON: {
1267*32176cfdSRui Paulo 		struct ieee80211_scanparams scan;
1268*32176cfdSRui Paulo 		/*
1269*32176cfdSRui Paulo 		 * We process beacon/probe response frames:
1270*32176cfdSRui Paulo 		 *    o when scanning, or
1271*32176cfdSRui Paulo 		 *    o station mode when associated (to collect state
1272*32176cfdSRui Paulo 		 *      updates such as 802.11g slot time)
1273*32176cfdSRui Paulo 		 * Frames otherwise received are discarded.
1274*32176cfdSRui Paulo 		 */
1275*32176cfdSRui Paulo 		if (!((ic->ic_flags & IEEE80211_F_SCAN) || ni->ni_associd)) {
1276*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1277*32176cfdSRui Paulo 			return;
1278*32176cfdSRui Paulo 		}
1279*32176cfdSRui Paulo 		/* XXX probe response in sta mode when !scanning? */
1280*32176cfdSRui Paulo 		if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
1281*32176cfdSRui Paulo 			return;
1282*32176cfdSRui Paulo 		/*
1283*32176cfdSRui Paulo 		 * Count frame now that we know it's to be processed.
1284*32176cfdSRui Paulo 		 */
1285*32176cfdSRui Paulo 		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
1286*32176cfdSRui Paulo 			vap->iv_stats.is_rx_beacon++;		/* XXX remove */
1287*32176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_beacons);
1288*32176cfdSRui Paulo 		} else
1289*32176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_proberesp);
1290*32176cfdSRui Paulo 		/*
1291*32176cfdSRui Paulo 		 * When operating in station mode, check for state updates.
1292*32176cfdSRui Paulo 		 * Be careful to ignore beacons received while doing a
1293*32176cfdSRui Paulo 		 * background scan.  We consider only 11g/WMM stuff right now.
1294*32176cfdSRui Paulo 		 */
1295*32176cfdSRui Paulo 		if (ni->ni_associd != 0 &&
1296*32176cfdSRui Paulo 		    ((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
1297*32176cfdSRui Paulo 		     IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) {
1298*32176cfdSRui Paulo 			/* record tsf of last beacon */
1299*32176cfdSRui Paulo 			memcpy(ni->ni_tstamp.data, scan.tstamp,
1300*32176cfdSRui Paulo 				sizeof(ni->ni_tstamp));
1301*32176cfdSRui Paulo 			/* count beacon frame for s/w bmiss handling */
1302*32176cfdSRui Paulo 			vap->iv_swbmiss_count++;
1303*32176cfdSRui Paulo 			vap->iv_bmiss_count = 0;
1304*32176cfdSRui Paulo 			if (ni->ni_erp != scan.erp) {
1305*32176cfdSRui Paulo 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1306*32176cfdSRui Paulo 				    wh->i_addr2,
1307*32176cfdSRui Paulo 				    "erp change: was 0x%x, now 0x%x",
1308*32176cfdSRui Paulo 				    ni->ni_erp, scan.erp);
1309*32176cfdSRui Paulo 				if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
1310*32176cfdSRui Paulo 				    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
1311*32176cfdSRui Paulo 					ic->ic_flags |= IEEE80211_F_USEPROT;
1312*32176cfdSRui Paulo 				else
1313*32176cfdSRui Paulo 					ic->ic_flags &= ~IEEE80211_F_USEPROT;
1314*32176cfdSRui Paulo 				ni->ni_erp = scan.erp;
1315*32176cfdSRui Paulo 				/* XXX statistic */
1316*32176cfdSRui Paulo 				/* XXX driver notification */
1317*32176cfdSRui Paulo 			}
1318*32176cfdSRui Paulo 			if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
1319*32176cfdSRui Paulo 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1320*32176cfdSRui Paulo 				    wh->i_addr2,
1321*32176cfdSRui Paulo 				    "capabilities change: was 0x%x, now 0x%x",
1322*32176cfdSRui Paulo 				    ni->ni_capinfo, scan.capinfo);
1323*32176cfdSRui Paulo 				/*
1324*32176cfdSRui Paulo 				 * NB: we assume short preamble doesn't
1325*32176cfdSRui Paulo 				 *     change dynamically
1326*32176cfdSRui Paulo 				 */
1327*32176cfdSRui Paulo 				ieee80211_set_shortslottime(ic,
1328*32176cfdSRui Paulo 					IEEE80211_IS_CHAN_A(ic->ic_bsschan) ||
1329*32176cfdSRui Paulo 					(scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
1330*32176cfdSRui Paulo 				ni->ni_capinfo = (ni->ni_capinfo &~ IEEE80211_CAPINFO_SHORT_SLOTTIME)
1331*32176cfdSRui Paulo 					       | (scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME);
1332*32176cfdSRui Paulo 				/* XXX statistic */
1333*32176cfdSRui Paulo 			}
1334*32176cfdSRui Paulo 			if (scan.wme != NULL &&
1335*32176cfdSRui Paulo 			    (ni->ni_flags & IEEE80211_NODE_QOS) &&
1336*32176cfdSRui Paulo 			    ieee80211_parse_wmeparams(vap, scan.wme, wh) > 0)
1337*32176cfdSRui Paulo 				ieee80211_wme_updateparams(vap);
1338*32176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
1339*32176cfdSRui Paulo 			if (scan.ath != NULL)
1340*32176cfdSRui Paulo 				ieee80211_parse_athparams(ni, scan.ath, wh);
1341*32176cfdSRui Paulo #endif
1342*32176cfdSRui Paulo 			if (scan.htcap != NULL && scan.htinfo != NULL &&
1343*32176cfdSRui Paulo 			    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1344*32176cfdSRui Paulo 				ieee80211_ht_updateparams(ni,
1345*32176cfdSRui Paulo 				    scan.htcap, scan.htinfo);
1346*32176cfdSRui Paulo 				/* XXX state changes? */
1347*32176cfdSRui Paulo 			}
1348*32176cfdSRui Paulo 			if (scan.tim != NULL) {
1349*32176cfdSRui Paulo 				struct ieee80211_tim_ie *tim =
1350*32176cfdSRui Paulo 				    (struct ieee80211_tim_ie *) scan.tim;
1351*32176cfdSRui Paulo #if 0
1352*32176cfdSRui Paulo 				int aid = IEEE80211_AID(ni->ni_associd);
1353*32176cfdSRui Paulo 				int ix = aid / NBBY;
1354*32176cfdSRui Paulo 				int min = tim->tim_bitctl &~ 1;
1355*32176cfdSRui Paulo 				int max = tim->tim_len + min - 4;
1356*32176cfdSRui Paulo 				if ((tim->tim_bitctl&1) ||
1357*32176cfdSRui Paulo 				    (min <= ix && ix <= max &&
1358*32176cfdSRui Paulo 				     isset(tim->tim_bitmap - min, aid))) {
1359*32176cfdSRui Paulo 					/*
1360*32176cfdSRui Paulo 					 * XXX Do not let bg scan kick off
1361*32176cfdSRui Paulo 					 * we are expecting data.
1362*32176cfdSRui Paulo 					 */
1363*32176cfdSRui Paulo 					ic->ic_lastdata = ticks;
1364*32176cfdSRui Paulo 					ieee80211_sta_pwrsave(vap, 0);
1365*32176cfdSRui Paulo 				}
1366*32176cfdSRui Paulo #endif
1367*32176cfdSRui Paulo 				ni->ni_dtim_count = tim->tim_count;
1368*32176cfdSRui Paulo 				ni->ni_dtim_period = tim->tim_period;
1369*32176cfdSRui Paulo 			}
1370*32176cfdSRui Paulo 			if (scan.csa != NULL &&
1371*32176cfdSRui Paulo 			    (vap->iv_flags & IEEE80211_F_DOTH))
1372*32176cfdSRui Paulo 				ieee80211_parse_csaparams(vap, scan.csa, wh);
1373*32176cfdSRui Paulo 			else if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
1374*32176cfdSRui Paulo 				/*
1375*32176cfdSRui Paulo 				 * No CSA ie or 11h disabled, but a channel
1376*32176cfdSRui Paulo 				 * switch is pending; drop out so we aren't
1377*32176cfdSRui Paulo 				 * stuck in CSA state.  If the AP really is
1378*32176cfdSRui Paulo 				 * moving we'll get a beacon miss and scan.
1379*32176cfdSRui Paulo 				 */
1380*32176cfdSRui Paulo 				IEEE80211_LOCK(ic);
1381*32176cfdSRui Paulo 				ieee80211_csa_cancelswitch(ic);
1382*32176cfdSRui Paulo 				IEEE80211_UNLOCK(ic);
1383*32176cfdSRui Paulo 			}
1384*32176cfdSRui Paulo 			/*
1385*32176cfdSRui Paulo 			 * If scanning, pass the info to the scan module.
1386*32176cfdSRui Paulo 			 * Otherwise, check if it's the right time to do
1387*32176cfdSRui Paulo 			 * a background scan.  Background scanning must
1388*32176cfdSRui Paulo 			 * be enabled and we must not be operating in the
1389*32176cfdSRui Paulo 			 * turbo phase of dynamic turbo mode.  Then,
1390*32176cfdSRui Paulo 			 * it's been a while since the last background
1391*32176cfdSRui Paulo 			 * scan and if no data frames have come through
1392*32176cfdSRui Paulo 			 * recently, kick off a scan.  Note that this
1393*32176cfdSRui Paulo 			 * is the mechanism by which a background scan
1394*32176cfdSRui Paulo 			 * is started _and_ continued each time we
1395*32176cfdSRui Paulo 			 * return on-channel to receive a beacon from
1396*32176cfdSRui Paulo 			 * our ap.
1397*32176cfdSRui Paulo 			 */
1398*32176cfdSRui Paulo 			if (ic->ic_flags & IEEE80211_F_SCAN) {
1399*32176cfdSRui Paulo 				ieee80211_add_scan(vap, &scan, wh,
1400*32176cfdSRui Paulo 					subtype, rssi, nf);
1401*32176cfdSRui Paulo 			} else if (contbgscan(vap)) {
1402*32176cfdSRui Paulo 				ieee80211_bg_scan(vap, 0);
1403*32176cfdSRui Paulo 			} else if (startbgscan(vap)) {
1404*32176cfdSRui Paulo 				vap->iv_stats.is_scan_bg++;
1405*32176cfdSRui Paulo #if 0
1406*32176cfdSRui Paulo 				/* wakeup if we are sleeing */
1407*32176cfdSRui Paulo 				ieee80211_set_pwrsave(vap, 0);
1408*32176cfdSRui Paulo #endif
1409*32176cfdSRui Paulo 				ieee80211_bg_scan(vap, 0);
1410*32176cfdSRui Paulo 			}
1411*32176cfdSRui Paulo 			return;
1412*32176cfdSRui Paulo 		}
1413*32176cfdSRui Paulo 		/*
1414*32176cfdSRui Paulo 		 * If scanning, just pass information to the scan module.
1415*32176cfdSRui Paulo 		 */
1416*32176cfdSRui Paulo 		if (ic->ic_flags & IEEE80211_F_SCAN) {
1417*32176cfdSRui Paulo 			if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
1418*32176cfdSRui Paulo 				/*
1419*32176cfdSRui Paulo 				 * Actively scanning a channel marked passive;
1420*32176cfdSRui Paulo 				 * send a probe request now that we know there
1421*32176cfdSRui Paulo 				 * is 802.11 traffic present.
1422*32176cfdSRui Paulo 				 *
1423*32176cfdSRui Paulo 				 * XXX check if the beacon we recv'd gives
1424*32176cfdSRui Paulo 				 * us what we need and suppress the probe req
1425*32176cfdSRui Paulo 				 */
1426*32176cfdSRui Paulo 				ieee80211_probe_curchan(vap, 1);
1427*32176cfdSRui Paulo 				ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
1428*32176cfdSRui Paulo 			}
1429*32176cfdSRui Paulo 			ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
1430*32176cfdSRui Paulo 			return;
1431*32176cfdSRui Paulo 		}
1432*32176cfdSRui Paulo 		break;
1433*32176cfdSRui Paulo 	}
1434*32176cfdSRui Paulo 
1435*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_AUTH: {
1436*32176cfdSRui Paulo 		uint16_t algo, seq, status;
1437*32176cfdSRui Paulo 		/*
1438*32176cfdSRui Paulo 		 * auth frame format
1439*32176cfdSRui Paulo 		 *	[2] algorithm
1440*32176cfdSRui Paulo 		 *	[2] sequence
1441*32176cfdSRui Paulo 		 *	[2] status
1442*32176cfdSRui Paulo 		 *	[tlv*] challenge
1443*32176cfdSRui Paulo 		 */
1444*32176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
1445*32176cfdSRui Paulo 		algo   = le16toh(*(uint16_t *)frm);
1446*32176cfdSRui Paulo 		seq    = le16toh(*(uint16_t *)(frm + 2));
1447*32176cfdSRui Paulo 		status = le16toh(*(uint16_t *)(frm + 4));
1448*32176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2,
1449*32176cfdSRui Paulo 		    "recv auth frame with algorithm %d seq %d", algo, seq);
1450*32176cfdSRui Paulo 
1451*32176cfdSRui Paulo 		if (vap->iv_flags & IEEE80211_F_COUNTERM) {
1452*32176cfdSRui Paulo 			IEEE80211_DISCARD(vap,
1453*32176cfdSRui Paulo 			    IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
1454*32176cfdSRui Paulo 			    wh, "auth", "%s", "TKIP countermeasures enabled");
1455*32176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_countermeasures++;
1456*32176cfdSRui Paulo 			if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
1457*32176cfdSRui Paulo 				ieee80211_send_error(ni, wh->i_addr2,
1458*32176cfdSRui Paulo 					IEEE80211_FC0_SUBTYPE_AUTH,
1459*32176cfdSRui Paulo 					IEEE80211_REASON_MIC_FAILURE);
1460*32176cfdSRui Paulo 			}
1461*32176cfdSRui Paulo 			return;
1462*32176cfdSRui Paulo 		}
1463*32176cfdSRui Paulo 		if (algo == IEEE80211_AUTH_ALG_SHARED)
1464*32176cfdSRui Paulo 			sta_auth_shared(ni, wh, frm + 6, efrm, rssi, nf,
1465*32176cfdSRui Paulo 			    seq, status);
1466*32176cfdSRui Paulo 		else if (algo == IEEE80211_AUTH_ALG_OPEN)
1467*32176cfdSRui Paulo 			sta_auth_open(ni, wh, rssi, nf, seq, status);
1468*32176cfdSRui Paulo 		else {
1469*32176cfdSRui Paulo 			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1470*32176cfdSRui Paulo 			    wh, "auth", "unsupported alg %d", algo);
1471*32176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_unsupported++;
1472*32176cfdSRui Paulo 			return;
1473*32176cfdSRui Paulo 		}
1474*32176cfdSRui Paulo 		break;
1475*32176cfdSRui Paulo 	}
1476*32176cfdSRui Paulo 
1477*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
1478*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: {
1479*32176cfdSRui Paulo 		uint16_t capinfo, associd;
1480*32176cfdSRui Paulo 		uint16_t status;
1481*32176cfdSRui Paulo 
1482*32176cfdSRui Paulo 		if (vap->iv_state != IEEE80211_S_ASSOC) {
1483*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1484*32176cfdSRui Paulo 			return;
1485*32176cfdSRui Paulo 		}
1486*32176cfdSRui Paulo 
1487*32176cfdSRui Paulo 		/*
1488*32176cfdSRui Paulo 		 * asresp frame format
1489*32176cfdSRui Paulo 		 *	[2] capability information
1490*32176cfdSRui Paulo 		 *	[2] status
1491*32176cfdSRui Paulo 		 *	[2] association ID
1492*32176cfdSRui Paulo 		 *	[tlv] supported rates
1493*32176cfdSRui Paulo 		 *	[tlv] extended supported rates
1494*32176cfdSRui Paulo 		 *	[tlv] WME
1495*32176cfdSRui Paulo 		 *	[tlv] HT capabilities
1496*32176cfdSRui Paulo 		 *	[tlv] HT info
1497*32176cfdSRui Paulo 		 */
1498*32176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
1499*32176cfdSRui Paulo 		ni = vap->iv_bss;
1500*32176cfdSRui Paulo 		capinfo = le16toh(*(uint16_t *)frm);
1501*32176cfdSRui Paulo 		frm += 2;
1502*32176cfdSRui Paulo 		status = le16toh(*(uint16_t *)frm);
1503*32176cfdSRui Paulo 		frm += 2;
1504*32176cfdSRui Paulo 		if (status != 0) {
1505*32176cfdSRui Paulo 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1506*32176cfdSRui Paulo 			    wh->i_addr2, "%sassoc failed (reason %d)",
1507*32176cfdSRui Paulo 			    ISREASSOC(subtype) ?  "re" : "", status);
1508*32176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_fail++;	/* XXX */
1509*32176cfdSRui Paulo 			return;
1510*32176cfdSRui Paulo 		}
1511*32176cfdSRui Paulo 		associd = le16toh(*(uint16_t *)frm);
1512*32176cfdSRui Paulo 		frm += 2;
1513*32176cfdSRui Paulo 
1514*32176cfdSRui Paulo 		rates = xrates = wme = htcap = htinfo = NULL;
1515*32176cfdSRui Paulo 		while (efrm - frm > 1) {
1516*32176cfdSRui Paulo 			IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
1517*32176cfdSRui Paulo 			switch (*frm) {
1518*32176cfdSRui Paulo 			case IEEE80211_ELEMID_RATES:
1519*32176cfdSRui Paulo 				rates = frm;
1520*32176cfdSRui Paulo 				break;
1521*32176cfdSRui Paulo 			case IEEE80211_ELEMID_XRATES:
1522*32176cfdSRui Paulo 				xrates = frm;
1523*32176cfdSRui Paulo 				break;
1524*32176cfdSRui Paulo 			case IEEE80211_ELEMID_HTCAP:
1525*32176cfdSRui Paulo 				htcap = frm;
1526*32176cfdSRui Paulo 				break;
1527*32176cfdSRui Paulo 			case IEEE80211_ELEMID_HTINFO:
1528*32176cfdSRui Paulo 				htinfo = frm;
1529*32176cfdSRui Paulo 				break;
1530*32176cfdSRui Paulo 			case IEEE80211_ELEMID_VENDOR:
1531*32176cfdSRui Paulo 				if (iswmeoui(frm))
1532*32176cfdSRui Paulo 					wme = frm;
1533*32176cfdSRui Paulo 				else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) {
1534*32176cfdSRui Paulo 					/*
1535*32176cfdSRui Paulo 					 * Accept pre-draft HT ie's if the
1536*32176cfdSRui Paulo 					 * standard ones have not been seen.
1537*32176cfdSRui Paulo 					 */
1538*32176cfdSRui Paulo 					if (ishtcapoui(frm)) {
1539*32176cfdSRui Paulo 						if (htcap == NULL)
1540*32176cfdSRui Paulo 							htcap = frm;
1541*32176cfdSRui Paulo 					} else if (ishtinfooui(frm)) {
1542*32176cfdSRui Paulo 						if (htinfo == NULL)
1543*32176cfdSRui Paulo 							htcap = frm;
1544*32176cfdSRui Paulo 					}
1545*32176cfdSRui Paulo 				}
1546*32176cfdSRui Paulo 				/* XXX Atheros OUI support */
1547*32176cfdSRui Paulo 				break;
1548*32176cfdSRui Paulo 			}
1549*32176cfdSRui Paulo 			frm += frm[1] + 2;
1550*32176cfdSRui Paulo 		}
1551*32176cfdSRui Paulo 
1552*32176cfdSRui Paulo 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return);
1553*32176cfdSRui Paulo 		if (xrates != NULL)
1554*32176cfdSRui Paulo 			IEEE80211_VERIFY_ELEMENT(xrates,
1555*32176cfdSRui Paulo 				IEEE80211_RATE_MAXSIZE - rates[1], return);
1556*32176cfdSRui Paulo 		rate = ieee80211_setup_rates(ni, rates, xrates,
1557*32176cfdSRui Paulo 				IEEE80211_F_JOIN |
1558*32176cfdSRui Paulo 				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1559*32176cfdSRui Paulo 				IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1560*32176cfdSRui Paulo 		if (rate & IEEE80211_RATE_BASIC) {
1561*32176cfdSRui Paulo 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1562*32176cfdSRui Paulo 			    wh->i_addr2,
1563*32176cfdSRui Paulo 			    "%sassoc failed (rate set mismatch)",
1564*32176cfdSRui Paulo 			    ISREASSOC(subtype) ?  "re" : "");
1565*32176cfdSRui Paulo 			vap->iv_stats.is_rx_assoc_norate++;
1566*32176cfdSRui Paulo 			ieee80211_new_state(vap, IEEE80211_S_SCAN,
1567*32176cfdSRui Paulo 			    IEEE80211_SCAN_FAIL_STATUS);
1568*32176cfdSRui Paulo 			return;
1569*32176cfdSRui Paulo 		}
1570*32176cfdSRui Paulo 
1571*32176cfdSRui Paulo 		ni->ni_capinfo = capinfo;
1572*32176cfdSRui Paulo 		ni->ni_associd = associd;
1573*32176cfdSRui Paulo 		if (ni->ni_jointime == 0)
1574*32176cfdSRui Paulo 			ni->ni_jointime = time_second;
1575*32176cfdSRui Paulo 		if (wme != NULL &&
1576*32176cfdSRui Paulo 		    ieee80211_parse_wmeparams(vap, wme, wh) >= 0) {
1577*32176cfdSRui Paulo 			ni->ni_flags |= IEEE80211_NODE_QOS;
1578*32176cfdSRui Paulo 			ieee80211_wme_updateparams(vap);
1579*32176cfdSRui Paulo 		} else
1580*32176cfdSRui Paulo 			ni->ni_flags &= ~IEEE80211_NODE_QOS;
1581*32176cfdSRui Paulo 		/*
1582*32176cfdSRui Paulo 		 * Setup HT state according to the negotiation.
1583*32176cfdSRui Paulo 		 *
1584*32176cfdSRui Paulo 		 * NB: shouldn't need to check if HT use is enabled but some
1585*32176cfdSRui Paulo 		 *     ap's send back HT ie's even when we don't indicate we
1586*32176cfdSRui Paulo 		 *     are HT capable in our AssocReq.
1587*32176cfdSRui Paulo 		 */
1588*32176cfdSRui Paulo 		if (htcap != NULL && htinfo != NULL &&
1589*32176cfdSRui Paulo 		    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1590*32176cfdSRui Paulo 			ieee80211_ht_node_init(ni);
1591*32176cfdSRui Paulo 			ieee80211_ht_updateparams(ni, htcap, htinfo);
1592*32176cfdSRui Paulo 			ieee80211_setup_htrates(ni, htcap,
1593*32176cfdSRui Paulo 			     IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
1594*32176cfdSRui Paulo 			ieee80211_setup_basic_htrates(ni, htinfo);
1595*32176cfdSRui Paulo 			ieee80211_node_setuptxparms(ni);
1596*32176cfdSRui Paulo 		} else {
1597*32176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
1598*32176cfdSRui Paulo 			if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_ATH))
1599*32176cfdSRui Paulo 				ieee80211_ff_node_init(ni);
1600*32176cfdSRui Paulo #endif
1601*32176cfdSRui Paulo 		}
1602*32176cfdSRui Paulo 		/*
1603*32176cfdSRui Paulo 		 * Configure state now that we are associated.
1604*32176cfdSRui Paulo 		 *
1605*32176cfdSRui Paulo 		 * XXX may need different/additional driver callbacks?
1606*32176cfdSRui Paulo 		 */
1607*32176cfdSRui Paulo 		if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
1608*32176cfdSRui Paulo 		    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
1609*32176cfdSRui Paulo 			ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
1610*32176cfdSRui Paulo 			ic->ic_flags &= ~IEEE80211_F_USEBARKER;
1611*32176cfdSRui Paulo 		} else {
1612*32176cfdSRui Paulo 			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
1613*32176cfdSRui Paulo 			ic->ic_flags |= IEEE80211_F_USEBARKER;
1614*32176cfdSRui Paulo 		}
1615*32176cfdSRui Paulo 		ieee80211_set_shortslottime(ic,
1616*32176cfdSRui Paulo 			IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
1617*32176cfdSRui Paulo 			(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
1618*32176cfdSRui Paulo 		/*
1619*32176cfdSRui Paulo 		 * Honor ERP protection.
1620*32176cfdSRui Paulo 		 *
1621*32176cfdSRui Paulo 		 * NB: ni_erp should zero for non-11g operation.
1622*32176cfdSRui Paulo 		 */
1623*32176cfdSRui Paulo 		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
1624*32176cfdSRui Paulo 		    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
1625*32176cfdSRui Paulo 			ic->ic_flags |= IEEE80211_F_USEPROT;
1626*32176cfdSRui Paulo 		else
1627*32176cfdSRui Paulo 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
1628*32176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap,
1629*32176cfdSRui Paulo 		    IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, wh->i_addr2,
1630*32176cfdSRui Paulo 		    "%sassoc success at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s",
1631*32176cfdSRui Paulo 		    ISREASSOC(subtype) ? "re" : "",
1632*32176cfdSRui Paulo 		    IEEE80211_NODE_AID(ni),
1633*32176cfdSRui Paulo 		    ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
1634*32176cfdSRui Paulo 		    ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
1635*32176cfdSRui Paulo 		    ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
1636*32176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
1637*32176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_HT ?
1638*32176cfdSRui Paulo 			(ni->ni_chw == 40 ? ", HT40" : ", HT20") : "",
1639*32176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
1640*32176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
1641*32176cfdSRui Paulo 			ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "",
1642*32176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "",
1643*32176cfdSRui Paulo 		    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ?
1644*32176cfdSRui Paulo 			", fast-frames" : "",
1645*32176cfdSRui Paulo 		    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ?
1646*32176cfdSRui Paulo 			", turbo" : ""
1647*32176cfdSRui Paulo 		);
1648*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_RUN, subtype);
1649*32176cfdSRui Paulo 		break;
1650*32176cfdSRui Paulo 	}
1651*32176cfdSRui Paulo 
1652*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_DEAUTH: {
1653*32176cfdSRui Paulo 		uint16_t reason;
1654*32176cfdSRui Paulo 
1655*32176cfdSRui Paulo 		if (vap->iv_state == IEEE80211_S_SCAN) {
1656*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1657*32176cfdSRui Paulo 			return;
1658*32176cfdSRui Paulo 		}
1659*32176cfdSRui Paulo 		if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
1660*32176cfdSRui Paulo 			/* NB: can happen when in promiscuous mode */
1661*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1662*32176cfdSRui Paulo 			break;
1663*32176cfdSRui Paulo 		}
1664*32176cfdSRui Paulo 
1665*32176cfdSRui Paulo 		/*
1666*32176cfdSRui Paulo 		 * deauth frame format
1667*32176cfdSRui Paulo 		 *	[2] reason
1668*32176cfdSRui Paulo 		 */
1669*32176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
1670*32176cfdSRui Paulo 		reason = le16toh(*(uint16_t *)frm);
1671*32176cfdSRui Paulo 
1672*32176cfdSRui Paulo 		vap->iv_stats.is_rx_deauth++;
1673*32176cfdSRui Paulo 		vap->iv_stats.is_rx_deauth_code = reason;
1674*32176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_deauth);
1675*32176cfdSRui Paulo 
1676*32176cfdSRui Paulo 		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
1677*32176cfdSRui Paulo 		    "recv deauthenticate (reason %d)", reason);
1678*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_AUTH,
1679*32176cfdSRui Paulo 		    (reason << 8) | IEEE80211_FC0_SUBTYPE_DEAUTH);
1680*32176cfdSRui Paulo 		break;
1681*32176cfdSRui Paulo 	}
1682*32176cfdSRui Paulo 
1683*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_DISASSOC: {
1684*32176cfdSRui Paulo 		uint16_t reason;
1685*32176cfdSRui Paulo 
1686*32176cfdSRui Paulo 		if (vap->iv_state != IEEE80211_S_RUN &&
1687*32176cfdSRui Paulo 		    vap->iv_state != IEEE80211_S_ASSOC &&
1688*32176cfdSRui Paulo 		    vap->iv_state != IEEE80211_S_AUTH) {
1689*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1690*32176cfdSRui Paulo 			return;
1691*32176cfdSRui Paulo 		}
1692*32176cfdSRui Paulo 		if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
1693*32176cfdSRui Paulo 			/* NB: can happen when in promiscuous mode */
1694*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1695*32176cfdSRui Paulo 			break;
1696*32176cfdSRui Paulo 		}
1697*32176cfdSRui Paulo 
1698*32176cfdSRui Paulo 		/*
1699*32176cfdSRui Paulo 		 * disassoc frame format
1700*32176cfdSRui Paulo 		 *	[2] reason
1701*32176cfdSRui Paulo 		 */
1702*32176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
1703*32176cfdSRui Paulo 		reason = le16toh(*(uint16_t *)frm);
1704*32176cfdSRui Paulo 
1705*32176cfdSRui Paulo 		vap->iv_stats.is_rx_disassoc++;
1706*32176cfdSRui Paulo 		vap->iv_stats.is_rx_disassoc_code = reason;
1707*32176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_disassoc);
1708*32176cfdSRui Paulo 
1709*32176cfdSRui Paulo 		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
1710*32176cfdSRui Paulo 		    "recv disassociate (reason %d)", reason);
1711*32176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
1712*32176cfdSRui Paulo 		break;
1713*32176cfdSRui Paulo 	}
1714*32176cfdSRui Paulo 
1715*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_ACTION:
1716*32176cfdSRui Paulo 		if (vap->iv_state == IEEE80211_S_RUN) {
1717*32176cfdSRui Paulo 			if (ieee80211_parse_action(ni, m0) == 0)
1718*32176cfdSRui Paulo 				ic->ic_recv_action(ni, wh, frm, efrm);
1719*32176cfdSRui Paulo 		} else
1720*32176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
1721*32176cfdSRui Paulo 		break;
1722*32176cfdSRui Paulo 
1723*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
1724*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
1725*32176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
1726*32176cfdSRui Paulo 		vap->iv_stats.is_rx_mgtdiscard++;
1727*32176cfdSRui Paulo 		return;
1728*32176cfdSRui Paulo 	default:
1729*32176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1730*32176cfdSRui Paulo 		     wh, "mgt", "subtype 0x%x not handled", subtype);
1731*32176cfdSRui Paulo 		vap->iv_stats.is_rx_badsubtype++;
1732*32176cfdSRui Paulo 		break;
1733*32176cfdSRui Paulo 	}
1734*32176cfdSRui Paulo #undef ISREASSOC
1735*32176cfdSRui Paulo #undef ISPROBE
1736*32176cfdSRui Paulo }
1737*32176cfdSRui Paulo 
1738*32176cfdSRui Paulo static void
1739*32176cfdSRui Paulo sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype)
1740*32176cfdSRui Paulo {
1741*32176cfdSRui Paulo }
1742