ieee80211_sta.c revision 193966
155714Skris/*-
255714Skris * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
355714Skris * All rights reserved.
455714Skris *
555714Skris * Redistribution and use in source and binary forms, with or without
655714Skris * modification, are permitted provided that the following conditions
755714Skris * are met:
8280304Sjkim * 1. Redistributions of source code must retain the above copyright
955714Skris *    notice, this list of conditions and the following disclaimer.
1055714Skris * 2. Redistributions in binary form must reproduce the above copyright
1155714Skris *    notice, this list of conditions and the following disclaimer in the
1255714Skris *    documentation and/or other materials provided with the distribution.
1355714Skris *
1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15280304Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1655714Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1755714Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1855714Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1955714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2055714Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2155714Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22280304Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2355714Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2455714Skris */
2555714Skris
2655714Skris#include <sys/cdefs.h>
2755714Skris#ifdef __FreeBSD__
2855714Skris__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_sta.c 193966 2009-06-11 04:43:42Z sam $");
2955714Skris#endif
3055714Skris
3155714Skris/*
3255714Skris * IEEE 802.11 Station mode support.
3355714Skris */
3455714Skris#include "opt_inet.h"
3555714Skris#include "opt_wlan.h"
3655714Skris
37280304Sjkim#include <sys/param.h>
3855714Skris#include <sys/systm.h>
3955714Skris#include <sys/mbuf.h>
40280304Sjkim#include <sys/malloc.h>
4155714Skris#include <sys/kernel.h>
4255714Skris
4355714Skris#include <sys/socket.h>
4455714Skris#include <sys/sockio.h>
4555714Skris#include <sys/endian.h>
4655714Skris#include <sys/errno.h>
4755714Skris#include <sys/proc.h>
4855714Skris#include <sys/sysctl.h>
4955714Skris
5055714Skris#include <net/if.h>
5155714Skris#include <net/if_media.h>
52280304Sjkim#include <net/if_llc.h>
5355714Skris#include <net/ethernet.h>
5455714Skris
5555714Skris#include <net/bpf.h>
5655714Skris
5755714Skris#include <net80211/ieee80211_var.h>
5855714Skris#include <net80211/ieee80211_sta.h>
5955714Skris#include <net80211/ieee80211_input.h>
60280304Sjkim#ifdef IEEE80211_SUPPORT_SUPERG
6155714Skris#include <net80211/ieee80211_superg.h>
62280304Sjkim#endif
63280304Sjkim
64280304Sjkim#define	IEEE80211_RATE2MBS(r)	(((r) & IEEE80211_RATE_VAL) / 2)
65280304Sjkim
66280304Sjkimstatic	void sta_vattach(struct ieee80211vap *);
67280304Sjkimstatic	void sta_beacon_miss(struct ieee80211vap *);
68280304Sjkimstatic	int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int);
6955714Skrisstatic	int sta_input(struct ieee80211_node *, struct mbuf *, int, int);
70280304Sjkimstatic void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *,
71110007Smarkm	    int subtype, int rssi, int nf);
72280304Sjkimstatic void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
73110007Smarkm
74280304Sjkimvoid
75280304Sjkimieee80211_sta_attach(struct ieee80211com *ic)
76280304Sjkim{
7755714Skris	ic->ic_vattach[IEEE80211_M_STA] = sta_vattach;
78280304Sjkim}
79280304Sjkim
80280304Sjkimvoid
81280304Sjkimieee80211_sta_detach(struct ieee80211com *ic)
82280304Sjkim{
83280304Sjkim}
84110007Smarkm
85280304Sjkimstatic void
86280304Sjkimsta_vdetach(struct ieee80211vap *vap)
87280304Sjkim{
88280304Sjkim}
8955714Skris
90280304Sjkimstatic void
9155714Skrissta_vattach(struct ieee80211vap *vap)
92280304Sjkim{
9355714Skris	vap->iv_newstate = sta_newstate;
94280304Sjkim	vap->iv_input = sta_input;
9555714Skris	vap->iv_recv_mgmt = sta_recv_mgmt;
96280304Sjkim	vap->iv_recv_ctl = sta_recv_ctl;
97280304Sjkim	vap->iv_opdetach = sta_vdetach;
98280304Sjkim	vap->iv_bmiss = sta_beacon_miss;
99280304Sjkim}
100280304Sjkim
101280304Sjkim/*
102280304Sjkim * Handle a beacon miss event.  The common code filters out
103280304Sjkim * spurious events that can happen when scanning and/or before
104280304Sjkim * reaching RUN state.
105280304Sjkim */
10655714Skrisstatic void
107280304Sjkimsta_beacon_miss(struct ieee80211vap *vap)
108280304Sjkim{
109280304Sjkim	struct ieee80211com *ic = vap->iv_ic;
110280304Sjkim
111280304Sjkim	KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
112280304Sjkim	KASSERT(vap->iv_state >= IEEE80211_S_RUN,
113280304Sjkim	    ("wrong state %s", ieee80211_state_name[vap->iv_state]));
114280304Sjkim
115280304Sjkim	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
116280304Sjkim	    "beacon miss, mode %s state %s\n",
117280304Sjkim	    ieee80211_opmode_name[vap->iv_opmode],
118280304Sjkim	    ieee80211_state_name[vap->iv_state]);
11955714Skris
120280304Sjkim	if (vap->iv_state == IEEE80211_S_CSA) {
12168654Skris		/*
12268654Skris		 * A Channel Switch is pending; assume we missed the
12368654Skris		 * beacon that would've completed the process and just
124280304Sjkim		 * force the switch.  If we made a mistake we'll not
125280304Sjkim		 * find the AP on the new channel and fall back to a
126280304Sjkim		 * normal scan.
127280304Sjkim		 */
128280304Sjkim		ieee80211_csa_completeswitch(ic);
129280304Sjkim		return;
130280304Sjkim	}
131280304Sjkim	if (++vap->iv_bmiss_count < vap->iv_bmiss_max) {
132280304Sjkim		/*
133280304Sjkim		 * Send a directed probe req before falling back to a
134280304Sjkim		 * scan; if we receive a response ic_bmiss_count will
135280304Sjkim		 * be reset.  Some cards mistakenly report beacon miss
136280304Sjkim		 * so this avoids the expensive scan if the ap is
137280304Sjkim		 * still there.
138280304Sjkim		 */
139280304Sjkim		ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr,
140280304Sjkim			vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid,
141280304Sjkim			vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen);
142280304Sjkim		return;
143280304Sjkim	}
144280304Sjkim	vap->iv_bmiss_count = 0;
145280304Sjkim	vap->iv_stats.is_beacon_miss++;
146280304Sjkim	if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
147280304Sjkim#ifdef IEEE80211_SUPPORT_SUPERG
148280304Sjkim		struct ieee80211com *ic = vap->iv_ic;
149280304Sjkim
150280304Sjkim		/*
151280304Sjkim		 * If we receive a beacon miss interrupt when using
15255714Skris		 * dynamic turbo, attempt to switch modes before
153280304Sjkim		 * reassociating.
154280304Sjkim		 */
155280304Sjkim		if (IEEE80211_ATH_CAP(vap, vap->iv_bss, IEEE80211_NODE_TURBOP))
156280304Sjkim			ieee80211_dturbo_switch(vap,
15755714Skris			    ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO);
158280304Sjkim#endif
159280304Sjkim		/*
160280304Sjkim		 * Try to reassociate before scanning for a new ap.
161280304Sjkim		 */
162280304Sjkim		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
163280304Sjkim	} else {
164280304Sjkim		/*
165280304Sjkim		 * Somebody else is controlling state changes (e.g.
166280304Sjkim		 * a user-mode app) don't do anything that would
167280304Sjkim		 * confuse them; just drop into scan mode so they'll
168280304Sjkim		 * notified of the state change and given control.
169280304Sjkim		 */
170280304Sjkim		ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
171280304Sjkim	}
172280304Sjkim}
173280304Sjkim
174280304Sjkim/*
175280304Sjkim * Handle deauth with reason.  We retry only for
176280304Sjkim * the cases where we might succeed.  Otherwise
177280304Sjkim * we downgrade the ap and scan.
178280304Sjkim */
179280304Sjkimstatic void
180280304Sjkimsta_authretry(struct ieee80211vap *vap, struct ieee80211_node *ni, int reason)
18155714Skris{
182280304Sjkim	switch (reason) {
183280304Sjkim	case IEEE80211_STATUS_SUCCESS:		/* NB: MLME assoc */
184280304Sjkim	case IEEE80211_STATUS_TIMEOUT:
185280304Sjkim	case IEEE80211_REASON_ASSOC_EXPIRE:
186280304Sjkim	case IEEE80211_REASON_NOT_AUTHED:
187280304Sjkim	case IEEE80211_REASON_NOT_ASSOCED:
188280304Sjkim	case IEEE80211_REASON_ASSOC_LEAVE:
18955714Skris	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
190280304Sjkim		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1);
191280304Sjkim		break;
192160817Ssimon	default:
193280304Sjkim		ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr, reason);
194280304Sjkim		if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
195280304Sjkim			ieee80211_check_scan_current(vap);
196280304Sjkim		break;
197280304Sjkim	}
198280304Sjkim}
199280304Sjkim
20055714Skris/*
201238405Sjkim * IEEE80211_M_STA vap state machine handler.
202238405Sjkim * This routine handles the main states in the 802.11 protocol.
203280304Sjkim */
204238405Sjkimstatic int
205238405Sjkimsta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
206238405Sjkim{
207280304Sjkim	struct ieee80211com *ic = vap->iv_ic;
208238405Sjkim	struct ieee80211_node *ni;
209238405Sjkim	enum ieee80211_state ostate;
210238405Sjkim
211280304Sjkim	IEEE80211_LOCK_ASSERT(ic);
212238405Sjkim
213238405Sjkim	ostate = vap->iv_state;
214238405Sjkim	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
215280304Sjkim	    __func__, ieee80211_state_name[ostate],
216238405Sjkim	    ieee80211_state_name[nstate], arg);
217238405Sjkim	vap->iv_state = nstate;			/* state transition */
218238405Sjkim	callout_stop(&vap->iv_mgtsend);		/* XXX callout_drain */
219280304Sjkim	if (ostate != IEEE80211_S_SCAN)
220238405Sjkim		ieee80211_cancel_scan(vap);	/* background scan */
221280304Sjkim	ni = vap->iv_bss;			/* NB: no reference held */
222280304Sjkim	if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
223194206Ssimon		callout_stop(&vap->iv_swbmiss);
224238405Sjkim	switch (nstate) {
225194206Ssimon	case IEEE80211_S_INIT:
226280304Sjkim		switch (ostate) {
227280304Sjkim		case IEEE80211_S_SLEEP:
228238405Sjkim			/* XXX wakeup */
229238405Sjkim		case IEEE80211_S_RUN:
230238405Sjkim			IEEE80211_SEND_MGMT(ni,
231280304Sjkim			    IEEE80211_FC0_SUBTYPE_DISASSOC,
232238405Sjkim			    IEEE80211_REASON_ASSOC_LEAVE);
233280304Sjkim			ieee80211_sta_leave(ni);
23455714Skris			break;
235280304Sjkim		case IEEE80211_S_ASSOC:
236280304Sjkim			IEEE80211_SEND_MGMT(ni,
237280304Sjkim			    IEEE80211_FC0_SUBTYPE_DEAUTH,
238280304Sjkim			    IEEE80211_REASON_AUTH_LEAVE);
239280304Sjkim			break;
240280304Sjkim		case IEEE80211_S_SCAN:
241280304Sjkim			ieee80211_cancel_scan(vap);
242280304Sjkim			break;
24355714Skris		default:
244280304Sjkim			goto invalid;
245280304Sjkim		}
246280304Sjkim		if (ostate != IEEE80211_S_INIT) {
247160817Ssimon			/* NB: optimize INIT -> INIT case */
248280304Sjkim			ieee80211_reset_bss(vap);
249280304Sjkim		}
250280304Sjkim		if (vap->iv_auth->ia_detach != NULL)
251160817Ssimon			vap->iv_auth->ia_detach(vap);
252280304Sjkim		break;
253280304Sjkim	case IEEE80211_S_SCAN:
254280304Sjkim		switch (ostate) {
255280304Sjkim		case IEEE80211_S_INIT:
256280304Sjkim			/*
257280304Sjkim			 * Initiate a scan.  We can come here as a result
258280304Sjkim			 * of an IEEE80211_IOC_SCAN_REQ too in which case
259280304Sjkim			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
260280304Sjkim			 * and the scan request parameters will be present
261280304Sjkim			 * in iv_scanreq.  Otherwise we do the default.
262280304Sjkim			 */
263280304Sjkim			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
26455714Skris				ieee80211_check_scan(vap,
265280304Sjkim				    vap->iv_scanreq_flags,
26655714Skris				    vap->iv_scanreq_duration,
267280304Sjkim				    vap->iv_scanreq_mindwell,
268280304Sjkim				    vap->iv_scanreq_maxdwell,
269280304Sjkim				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
270280304Sjkim				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
271280304Sjkim			} else
272280304Sjkim				ieee80211_check_scan_current(vap);
273280304Sjkim			break;
274280304Sjkim		case IEEE80211_S_SCAN:
275280304Sjkim		case IEEE80211_S_AUTH:
276280304Sjkim		case IEEE80211_S_ASSOC:
277280304Sjkim			/*
27855714Skris			 * These can happen either because of a timeout
279110007Smarkm			 * on an assoc/auth response or because of a
28068654Skris			 * change in state that requires a reset.  For
281280304Sjkim			 * the former we're called with a non-zero arg
282280304Sjkim			 * that is the cause for the failure; pass this
283280304Sjkim			 * to the scan code so it can update state.
284280304Sjkim			 * Otherwise trigger a new scan unless we're in
285280304Sjkim			 * manual roaming mode in which case an application
286280304Sjkim			 * must issue an explicit scan request.
287280304Sjkim			 */
288280304Sjkim			if (arg != 0)
289280304Sjkim				ieee80211_scan_assoc_fail(vap,
290238405Sjkim					vap->iv_bss->ni_macaddr, arg);
291238405Sjkim			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
292280304Sjkim				ieee80211_check_scan_current(vap);
293280304Sjkim			break;
294110007Smarkm		case IEEE80211_S_RUN:		/* beacon miss */
295280304Sjkim			/*
296280304Sjkim			 * Beacon miss.  Notify user space and if not
297238405Sjkim			 * under control of a user application (roaming
298238405Sjkim			 * manual) kick off a scan to re-connect.
299238405Sjkim			 */
300280304Sjkim			ieee80211_sta_leave(ni);
301280304Sjkim			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
302280304Sjkim				ieee80211_check_scan_current(vap);
303280304Sjkim			break;
304194206Ssimon		default:
305280304Sjkim			goto invalid;
306238405Sjkim		}
307280304Sjkim		break;
308280304Sjkim	case IEEE80211_S_AUTH:
309280304Sjkim		switch (ostate) {
310280304Sjkim		case IEEE80211_S_INIT:
311280304Sjkim		case IEEE80211_S_SCAN:
312280304Sjkim			IEEE80211_SEND_MGMT(ni,
313280304Sjkim			    IEEE80211_FC0_SUBTYPE_AUTH, 1);
314280304Sjkim			break;
315280304Sjkim		case IEEE80211_S_AUTH:
316280304Sjkim		case IEEE80211_S_ASSOC:
317280304Sjkim			switch (arg & 0xff) {
318280304Sjkim			case IEEE80211_FC0_SUBTYPE_AUTH:
319280304Sjkim				/* ??? */
320280304Sjkim				IEEE80211_SEND_MGMT(ni,
321280304Sjkim				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
322280304Sjkim				break;
323280304Sjkim			case IEEE80211_FC0_SUBTYPE_DEAUTH:
324280304Sjkim				sta_authretry(vap, ni, arg>>8);
325280304Sjkim				break;
326280304Sjkim			}
327280304Sjkim			break;
328280304Sjkim		case IEEE80211_S_RUN:
329280304Sjkim			switch (arg & 0xff) {
330280304Sjkim			case IEEE80211_FC0_SUBTYPE_AUTH:
331280304Sjkim				IEEE80211_SEND_MGMT(ni,
332280304Sjkim				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
333280304Sjkim				vap->iv_state = ostate;	/* stay RUN */
33455714Skris				break;
33568654Skris			case IEEE80211_FC0_SUBTYPE_DEAUTH:
33668654Skris				ieee80211_sta_leave(ni);
33768654Skris				if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
33868654Skris					/* try to reauth */
339280304Sjkim					IEEE80211_SEND_MGMT(ni,
340280304Sjkim					    IEEE80211_FC0_SUBTYPE_AUTH, 1);
341280304Sjkim				}
342280304Sjkim				break;
343280304Sjkim			}
344280304Sjkim			break;
345280304Sjkim		default:
346280304Sjkim			goto invalid;
347280304Sjkim		}
348280304Sjkim		break;
34968654Skris	case IEEE80211_S_ASSOC:
350280304Sjkim		switch (ostate) {
35168654Skris		case IEEE80211_S_AUTH:
352280304Sjkim		case IEEE80211_S_ASSOC:
35368654Skris			IEEE80211_SEND_MGMT(ni,
354280304Sjkim			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
35568654Skris			break;
356280304Sjkim		case IEEE80211_S_SLEEP:		/* cannot happen */
35768654Skris		case IEEE80211_S_RUN:
358280304Sjkim			ieee80211_sta_leave(ni);
359110007Smarkm			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
360280304Sjkim				IEEE80211_SEND_MGMT(ni, arg ?
361160817Ssimon				    IEEE80211_FC0_SUBTYPE_REASSOC_REQ :
362280304Sjkim				    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
363238405Sjkim			}
364280304Sjkim			break;
365194206Ssimon		default:
366280304Sjkim			goto invalid;
367194206Ssimon		}
368280304Sjkim		break;
369238405Sjkim	case IEEE80211_S_RUN:
370280304Sjkim		if (vap->iv_flags & IEEE80211_F_WPA) {
371238405Sjkim			/* XXX validate prerequisites */
372280304Sjkim		}
373280304Sjkim		switch (ostate) {
374280304Sjkim		case IEEE80211_S_RUN:
375238405Sjkim		case IEEE80211_S_CSA:
376280304Sjkim			break;
377280304Sjkim		case IEEE80211_S_AUTH:		/* when join is done in fw */
37868654Skris		case IEEE80211_S_ASSOC:
37968654Skris#ifdef IEEE80211_DEBUG
38068654Skris			if (ieee80211_msg_debug(vap)) {
381280304Sjkim				ieee80211_note(vap, "%s with %s ssid ",
382280304Sjkim				    (vap->iv_opmode == IEEE80211_M_STA ?
383280304Sjkim				    "associated" : "synchronized"),
384280304Sjkim				    ether_sprintf(ni->ni_bssid));
385280304Sjkim				ieee80211_print_essid(vap->iv_bss->ni_essid,
386280304Sjkim				    ni->ni_esslen);
387280304Sjkim				/* XXX MCS/HT */
388280304Sjkim				printf(" channel %d start %uMb\n",
389280304Sjkim				    ieee80211_chan2ieee(ic, ic->ic_curchan),
390280304Sjkim				    IEEE80211_RATE2MBS(ni->ni_txrate));
391280304Sjkim			}
392280304Sjkim#endif
393280304Sjkim			ieee80211_scan_assoc_success(vap, ni->ni_macaddr);
394280304Sjkim			ieee80211_notify_node_join(ni,
395280304Sjkim			    arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
396280304Sjkim			break;
397280304Sjkim		case IEEE80211_S_SLEEP:
398280304Sjkim			ieee80211_sta_pwrsave(vap, 0);
399280304Sjkim			break;
400280304Sjkim		default:
401280304Sjkim			goto invalid;
402280304Sjkim		}
403280304Sjkim		ieee80211_sync_curchan(ic);
404238405Sjkim		if (ostate != IEEE80211_S_RUN &&
405280304Sjkim		    (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
406238405Sjkim			/*
407280304Sjkim			 * Start s/w beacon miss timer for devices w/o
408238405Sjkim			 * hardware support.  We fudge a bit here since
409280304Sjkim			 * we're doing this in software.
41068654Skris			 */
411284285Sjkim			vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
412284285Sjkim				2 * vap->iv_bmissthreshold * ni->ni_intval);
413284285Sjkim			vap->iv_swbmiss_count = 0;
414238405Sjkim			callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
415238405Sjkim				ieee80211_swbmiss, vap);
416280304Sjkim		}
417238405Sjkim		/*
418280304Sjkim		 * When 802.1x is not in use mark the port authorized
419238405Sjkim		 * at this point so traffic can flow.
420280304Sjkim		 */
421238405Sjkim		if (ni->ni_authmode != IEEE80211_AUTH_8021X)
422280304Sjkim			ieee80211_node_authorize(ni);
423280304Sjkim		/*
424280304Sjkim		 * Fake association when joining an existing bss.
425280304Sjkim		 */
42655714Skris		if (ic->ic_newassoc != NULL)
427280304Sjkim			ic->ic_newassoc(vap->iv_bss, ostate != IEEE80211_S_RUN);
428280304Sjkim		break;
429280304Sjkim	case IEEE80211_S_CSA:
430280304Sjkim		if (ostate != IEEE80211_S_RUN)
431280304Sjkim			goto invalid;
432280304Sjkim		break;
433280304Sjkim	case IEEE80211_S_SLEEP:
434280304Sjkim		ieee80211_sta_pwrsave(vap, 0);
435280304Sjkim		break;
436280304Sjkim	default:
437280304Sjkim	invalid:
438280304Sjkim		IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
439280304Sjkim		    "%s: unexpected state transition %s -> %s\n", __func__,
440280304Sjkim		    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
441280304Sjkim		break;
442280304Sjkim	}
443280304Sjkim	return 0;
444280304Sjkim}
44555714Skris
446280304Sjkim/*
447280304Sjkim * Return non-zero if the frame is an echo of a multicast
448280304Sjkim * frame sent by ourself.  The dir is known to be DSTODS.
449280304Sjkim */
450280304Sjkimstatic __inline int
451280304Sjkimisdstods_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
452280304Sjkim{
453280304Sjkim#define	QWH4(wh)	((const struct ieee80211_qosframe_addr4 *)wh)
454280304Sjkim#define	WH4(wh)		((const struct ieee80211_frame_addr4 *)wh)
455280304Sjkim	const uint8_t *sa;
456280304Sjkim
457280304Sjkim	KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode"));
458280304Sjkim
459280304Sjkim	if (!IEEE80211_IS_MULTICAST(wh->i_addr3))
460280304Sjkim		return 0;
46155714Skris	sa = IEEE80211_QOS_HAS_SEQ(wh) ? QWH4(wh)->i_addr4 : WH4(wh)->i_addr4;
46255714Skris	return IEEE80211_ADDR_EQ(sa, vap->iv_myaddr);
463280304Sjkim#undef WH4
464280304Sjkim#undef QWH4
465280304Sjkim}
466280304Sjkim
46755714Skris/*
468280304Sjkim * Return non-zero if the frame is an echo of a multicast
469280304Sjkim * frame sent by ourself.  The dir is known to be FROMDS.
470280304Sjkim */
471280304Sjkimstatic __inline int
47272616Skrisisfromds_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
473280304Sjkim{
474280304Sjkim	KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode"));
475280304Sjkim
476280304Sjkim	if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
47772616Skris		return 0;
478280304Sjkim	return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
479280304Sjkim}
480280304Sjkim
481280304Sjkim/*
48255714Skris * Decide if a received management frame should be
483280304Sjkim * printed when debugging is enabled.  This filters some
484280304Sjkim * of the less interesting frames that come frequently
485160817Ssimon * (e.g. beacons).
486280304Sjkim */
487160817Ssimonstatic __inline int
48855714Skrisdoprint(struct ieee80211vap *vap, int subtype)
489280304Sjkim{
490280304Sjkim	switch (subtype) {
491280304Sjkim	case IEEE80211_FC0_SUBTYPE_BEACON:
492280304Sjkim		return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN);
49355714Skris	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
494167615Ssimon		return 0;
495280304Sjkim	}
496280304Sjkim	return 1;
497280304Sjkim}
498167615Ssimon
499167615Ssimon/*
500238405Sjkim * Process a received frame.  The node associated with the sender
50155714Skris * should be supplied.  If nothing was found in the node table then
502238405Sjkim * the caller is assumed to supply a reference to iv_bss instead.
503280304Sjkim * The RSSI and a timestamp are also supplied.  The RSSI data is used
504280304Sjkim * during AP scanning to select a AP to associate with; it can have
505280304Sjkim * any units so long as values have consistent units and higher values
50655714Skris * mean ``better signal''.  The receive timestamp is currently not used
507167615Ssimon * by the 802.11 layer.
508280304Sjkim */
509167615Ssimonstatic int
510167615Ssimonsta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
511167615Ssimon{
512167615Ssimon#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
513280304Sjkim#define	HAS_SEQ(type)	((type & 0x4) == 0)
51455714Skris	struct ieee80211vap *vap = ni->ni_vap;
515280304Sjkim	struct ieee80211com *ic = ni->ni_ic;
516167615Ssimon	struct ifnet *ifp = vap->iv_ifp;
517167615Ssimon	struct ieee80211_frame *wh;
518167615Ssimon	struct ieee80211_key *key;
519167615Ssimon	struct ether_header *eh;
520238405Sjkim	int hdrspace, need_tap;
521280304Sjkim	uint8_t dir, type, subtype, qos;
522167615Ssimon	uint8_t *bssid;
523280304Sjkim	uint16_t rxseq;
524167615Ssimon
525280304Sjkim	if (m->m_flags & M_AMPDU_MPDU) {
52655714Skris		/*
527280304Sjkim		 * Fastpath for A-MPDU reorder q resubmission.  Frames
528280304Sjkim		 * w/ M_AMPDU_MPDU marked have already passed through
52955714Skris		 * here but were received out of order and been held on
530280304Sjkim		 * the reorder queue.  When resubmitted they are marked
531280304Sjkim		 * with the M_AMPDU_MPDU flag and we can bypass most of
532280304Sjkim		 * the normal processing.
533280304Sjkim		 */
534280304Sjkim		wh = mtod(m, struct ieee80211_frame *);
535280304Sjkim		type = IEEE80211_FC0_TYPE_DATA;
536280304Sjkim		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
537280304Sjkim		subtype = IEEE80211_FC0_SUBTYPE_QOS;
538280304Sjkim		hdrspace = ieee80211_hdrspace(ic, wh);	/* XXX optimize? */
539280304Sjkim		goto resubmit_ampdu;
54055714Skris	}
541280304Sjkim
542280304Sjkim	KASSERT(ni != NULL, ("null node"));
543280304Sjkim	ni->ni_inact = ni->ni_inact_reload;
544280304Sjkim
545280304Sjkim	need_tap = 1;			/* mbuf need to be tapped. */
546280304Sjkim	type = -1;			/* undefined */
547280304Sjkim
548280304Sjkim	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
549280304Sjkim		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
550280304Sjkim		    ni->ni_macaddr, NULL,
55155714Skris		    "too short (1): len %u", m->m_pkthdr.len);
552167615Ssimon		vap->iv_stats.is_rx_tooshort++;
553280304Sjkim		goto out;
55455714Skris	}
555280304Sjkim	/*
556280304Sjkim	 * Bit of a cheat here, we use a pointer for a 3-address
557280304Sjkim	 * frame format but don't reference fields past outside
558280304Sjkim	 * ieee80211_frame_min w/o first validating the data is
559280304Sjkim	 * present.
560280304Sjkim	 */
561280304Sjkim	wh = mtod(m, struct ieee80211_frame *);
562280304Sjkim
56355714Skris	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
564280304Sjkim	    IEEE80211_FC0_VERSION_0) {
565280304Sjkim		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
566110007Smarkm		    ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x",
567280304Sjkim		    wh->i_fc[0], wh->i_fc[1]);
568280304Sjkim		vap->iv_stats.is_rx_badversion++;
569280304Sjkim		goto err;
570280304Sjkim	}
571280304Sjkim
572280304Sjkim	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
573280304Sjkim	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
574280304Sjkim	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
575280304Sjkim	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
576280304Sjkim		bssid = wh->i_addr2;
577280304Sjkim		if (!IEEE80211_ADDR_EQ(bssid, ni->ni_bssid)) {
57855714Skris			/* not interested in */
579280304Sjkim			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
580280304Sjkim			    bssid, NULL, "%s", "not to bss");
581280304Sjkim			vap->iv_stats.is_rx_wrongbss++;
582110007Smarkm			goto out;
583280304Sjkim		}
584280304Sjkim		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
585280304Sjkim		ni->ni_noise = nf;
586280304Sjkim		if (HAS_SEQ(type)) {
587280304Sjkim			uint8_t tid = ieee80211_gettid(wh);
58855714Skris			if (IEEE80211_QOS_HAS_SEQ(wh) &&
589280304Sjkim			    TID_TO_WME_AC(tid) >= WME_AC_VI)
590280304Sjkim				ic->ic_wme.wme_hipri_traffic++;
591280304Sjkim			rxseq = le16toh(*(uint16_t *)wh->i_seq);
592280304Sjkim			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
59355714Skris			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
594280304Sjkim			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
595280304Sjkim				/* duplicate, discard */
596280304Sjkim				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
597194206Ssimon				    bssid, "duplicate",
598280304Sjkim				    "seqno <%u,%u> fragno <%u,%u> tid %u",
599280304Sjkim				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
600280304Sjkim				    ni->ni_rxseqs[tid] >>
601280304Sjkim					IEEE80211_SEQ_SEQ_SHIFT,
602280304Sjkim				    rxseq & IEEE80211_SEQ_FRAG_MASK,
603280304Sjkim				    ni->ni_rxseqs[tid] &
604280304Sjkim					IEEE80211_SEQ_FRAG_MASK,
605280304Sjkim				    tid);
606280304Sjkim				vap->iv_stats.is_rx_dup++;
60755714Skris				IEEE80211_NODE_STAT(ni, rx_dup);
608280304Sjkim				goto out;
609280304Sjkim			}
610280304Sjkim			ni->ni_rxseqs[tid] = rxseq;
611280304Sjkim		}
612280304Sjkim	}
613280304Sjkim
614280304Sjkim	switch (type) {
615280304Sjkim	case IEEE80211_FC0_TYPE_DATA:
616280304Sjkim		hdrspace = ieee80211_hdrspace(ic, wh);
61755714Skris		if (m->m_len < hdrspace &&
618280304Sjkim		    (m = m_pullup(m, hdrspace)) == NULL) {
619280304Sjkim			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
620280304Sjkim			    ni->ni_macaddr, NULL,
621280304Sjkim			    "data too short: expecting %u", hdrspace);
622280304Sjkim			vap->iv_stats.is_rx_tooshort++;
623280304Sjkim			goto out;		/* XXX */
624280304Sjkim		}
625280304Sjkim		/*
626280304Sjkim		 * Handle A-MPDU re-ordering.  If the frame is to be
627280304Sjkim		 * processed directly then ieee80211_ampdu_reorder
62855714Skris		 * will return 0; otherwise it has consumed the mbuf
629280304Sjkim		 * and we should do nothing more with it.
630280304Sjkim		 */
63155714Skris		if ((m->m_flags & M_AMPDU) &&
632280304Sjkim		    (dir == IEEE80211_FC1_DIR_FROMDS ||
633280304Sjkim		     dir == IEEE80211_FC1_DIR_DSTODS) &&
63455714Skris		    ieee80211_ampdu_reorder(ni, m) != 0) {
635280304Sjkim			m = NULL;
636280304Sjkim			goto out;
637280304Sjkim		}
638280304Sjkim	resubmit_ampdu:
639238405Sjkim		if (dir == IEEE80211_FC1_DIR_FROMDS) {
640280304Sjkim			if ((ifp->if_flags & IFF_SIMPLEX) &&
641280304Sjkim			    isfromds_mcastecho(vap, wh)) {
642280304Sjkim				/*
643238405Sjkim				 * In IEEE802.11 network, multicast
644280304Sjkim				 * packets sent from "me" are broadcast
645280304Sjkim				 * from the AP; silently discard for
646280304Sjkim				 * SIMPLEX interface.
647280304Sjkim				 */
64855714Skris				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
649280304Sjkim				    wh, "data", "%s", "multicast echo");
650280304Sjkim				vap->iv_stats.is_rx_mcastecho++;
651280304Sjkim				goto out;
652280304Sjkim			}
65355714Skris			if ((vap->iv_flags & IEEE80211_F_DWDS) &&
654280304Sjkim			    IEEE80211_IS_MULTICAST(wh->i_addr1)) {
655280304Sjkim				/*
656280304Sjkim				 * DWDS sta's must drop 3-address mcast frames
657280304Sjkim				 * as they will be sent separately as a 4-addr
658280304Sjkim				 * frame.  Accepting the 3-addr frame will
65955714Skris				 * confuse the bridge into thinking the sending
660280304Sjkim				 * sta is located at the end of WDS link.
661280304Sjkim				 */
662280304Sjkim				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
663280304Sjkim				    "3-address data", "%s", "DWDS enabled");
664280304Sjkim				vap->iv_stats.is_rx_mcastecho++;
665280304Sjkim				goto out;
66655714Skris			}
66755714Skris		} else if (dir == IEEE80211_FC1_DIR_DSTODS) {
66868654Skris			if ((vap->iv_flags & IEEE80211_F_DWDS) == 0) {
669160817Ssimon				IEEE80211_DISCARD(vap,
670160817Ssimon				    IEEE80211_MSG_INPUT, wh, "4-address data",
67168654Skris				    "%s", "DWDS not enabled");
672110007Smarkm				vap->iv_stats.is_rx_wrongdir++;
67368654Skris				goto out;
674160817Ssimon			}
67555714Skris			if ((ifp->if_flags & IFF_SIMPLEX) &&
676280304Sjkim			    isdstods_mcastecho(vap, wh)) {
67755714Skris				/*
67855714Skris				 * In IEEE802.11 network, multicast
67955714Skris				 * packets sent from "me" are broadcast
68055714Skris				 * from the AP; silently discard for
681280304Sjkim				 * SIMPLEX interface.
682280304Sjkim				 */
683280304Sjkim				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
68455714Skris				    "4-address data", "%s", "multicast echo");
685110007Smarkm				vap->iv_stats.is_rx_mcastecho++;
686280304Sjkim				goto out;
687110007Smarkm			}
688280304Sjkim		} else {
689280304Sjkim			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
690110007Smarkm			    "data", "incorrect dir 0x%x", dir);
691280304Sjkim			vap->iv_stats.is_rx_wrongdir++;
692280304Sjkim			goto out;
693110007Smarkm		}
694280304Sjkim
695280304Sjkim		/*
696110007Smarkm		 * Handle privacy requirements.  Note that we
697110007Smarkm		 * must not be preempted from here until after
698110007Smarkm		 * we (potentially) call ieee80211_crypto_demic;
699110007Smarkm		 * otherwise we may violate assumptions in the
700160817Ssimon		 * crypto cipher modules used to do delayed update
701280304Sjkim		 * of replay sequence numbers.
702280304Sjkim		 */
703160817Ssimon		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
704160817Ssimon			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
705280304Sjkim				/*
706280304Sjkim				 * Discard encrypted frames when privacy is off.
707160817Ssimon				 */
708160817Ssimon				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
709280304Sjkim				    wh, "WEP", "%s", "PRIVACY off");
710280304Sjkim				vap->iv_stats.is_rx_noprivacy++;
711110007Smarkm				IEEE80211_NODE_STAT(ni, rx_noprivacy);
712280304Sjkim				goto out;
713280304Sjkim			}
714110007Smarkm			key = ieee80211_crypto_decap(ni, m, hdrspace);
715280304Sjkim			if (key == NULL) {
716280304Sjkim				/* NB: stats+msgs handled in crypto_decap */
717238405Sjkim				IEEE80211_NODE_STAT(ni, rx_wepfail);
718280304Sjkim				goto out;
719280304Sjkim			}
720280304Sjkim			wh = mtod(m, struct ieee80211_frame *);
721110007Smarkm			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
722110007Smarkm		} else {
723110007Smarkm			/* XXX M_WEP and IEEE80211_F_PRIVACY */
724110007Smarkm			key = NULL;
725110007Smarkm		}
726142428Snectar
727280304Sjkim		/*
728142428Snectar		 * Save QoS bits for use below--before we strip the header.
729142428Snectar		 */
730142428Snectar		if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
731280304Sjkim			qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
732280304Sjkim			    ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
733142428Snectar			    ((struct ieee80211_qosframe *)wh)->i_qos[0];
734142428Snectar		} else
735280304Sjkim			qos = 0;
736142428Snectar
737280304Sjkim		/*
738142428Snectar		 * Next up, any fragmentation.
739142428Snectar		 */
740110007Smarkm		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
741110007Smarkm			m = ieee80211_defrag(ni, m, hdrspace);
742110007Smarkm			if (m == NULL) {
743110007Smarkm				/* Fragment dropped or frame not complete yet */
744110007Smarkm				goto out;
745110007Smarkm			}
746110007Smarkm		}
747280304Sjkim		wh = NULL;		/* no longer valid, catch any uses */
748280304Sjkim
749280304Sjkim		/*
750280304Sjkim		 * Next strip any MSDU crypto bits.
751280304Sjkim		 */
752280304Sjkim		if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) {
753280304Sjkim			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
754110007Smarkm			    ni->ni_macaddr, "data", "%s", "demic error");
755110007Smarkm			vap->iv_stats.is_rx_demicfail++;
756110007Smarkm			IEEE80211_NODE_STAT(ni, rx_demicfail);
757280304Sjkim			goto out;
758280304Sjkim		}
759110007Smarkm
760280304Sjkim		/* copy to listener after decrypt */
761110007Smarkm		if (ieee80211_radiotap_active_vap(vap))
762110007Smarkm			ieee80211_radiotap_tx(vap, m);
763280304Sjkim		need_tap = 0;
764238405Sjkim
765280304Sjkim		/*
766280304Sjkim		 * Finally, strip the 802.11 header.
767280304Sjkim		 */
768110007Smarkm		m = ieee80211_decap(vap, m, hdrspace);
769142428Snectar		if (m == NULL) {
770280304Sjkim			/* XXX mask bit to check for both */
771110007Smarkm			/* don't count Null data frames as errors */
772110007Smarkm			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA ||
773280304Sjkim			    subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)
774280304Sjkim				goto out;
775110007Smarkm			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
776110007Smarkm			    ni->ni_macaddr, "data", "%s", "decap error");
777110007Smarkm			vap->iv_stats.is_rx_decap++;
778110007Smarkm			IEEE80211_NODE_STAT(ni, rx_decap);
779142428Snectar			goto err;
780280304Sjkim		}
781110007Smarkm		eh = mtod(m, struct ether_header *);
782280304Sjkim		if (!ieee80211_node_is_authorized(ni)) {
783280304Sjkim			/*
784110007Smarkm			 * Deny any non-PAE frames received prior to
785110007Smarkm			 * authorization.  For open/shared-key
786142428Snectar			 * authentication the port is mark authorized
787280304Sjkim			 * after authentication completes.  For 802.1x
788110007Smarkm			 * the port is not marked authorized by the
789280304Sjkim			 * authenticator until the handshake has completed.
790280304Sjkim			 */
791110007Smarkm			if (eh->ether_type != htons(ETHERTYPE_PAE)) {
792110007Smarkm				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
793142428Snectar				    eh->ether_shost, "data",
794280304Sjkim				    "unauthorized port: ether type 0x%x len %u",
795110007Smarkm				    eh->ether_type, m->m_pkthdr.len);
796280304Sjkim				vap->iv_stats.is_rx_unauth++;
797280304Sjkim				IEEE80211_NODE_STAT(ni, rx_unauth);
798110007Smarkm				goto err;
799110007Smarkm			}
800142428Snectar		} else {
801280304Sjkim			/*
802110007Smarkm			 * When denying unencrypted frames, discard
803280304Sjkim			 * any non-PAE frames received without encryption.
804280304Sjkim			 */
805110007Smarkm			if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
806110007Smarkm			    (key == NULL && (m->m_flags & M_WEP) == 0) &&
807142428Snectar			    eh->ether_type != htons(ETHERTYPE_PAE)) {
808142428Snectar				/*
809142428Snectar				 * Drop unencrypted frames.
810280304Sjkim				 */
811110007Smarkm				vap->iv_stats.is_rx_unencrypted++;
812110007Smarkm				IEEE80211_NODE_STAT(ni, rx_unencrypted);
813246772Sjkim				goto out;
814238405Sjkim			}
815238405Sjkim		}
816110007Smarkm		/* XXX require HT? */
817110007Smarkm		if (qos & IEEE80211_QOS_AMSDU) {
818142428Snectar			m = ieee80211_decap_amsdu(ni, m);
819142428Snectar			if (m == NULL)
820142428Snectar				return IEEE80211_FC0_TYPE_DATA;
821280304Sjkim		} else {
822110007Smarkm#ifdef IEEE80211_SUPPORT_SUPERG
823110007Smarkm			m = ieee80211_decap_fastframe(vap, ni, m);
824246772Sjkim			if (m == NULL)
825238405Sjkim				return IEEE80211_FC0_TYPE_DATA;
826110007Smarkm#endif
827110007Smarkm		}
828142428Snectar		ieee80211_deliver_data(vap, ni, m);
829142428Snectar		return IEEE80211_FC0_TYPE_DATA;
830142428Snectar
831280304Sjkim	case IEEE80211_FC0_TYPE_MGT:
832110007Smarkm		vap->iv_stats.is_rx_mgmt++;
833110007Smarkm		IEEE80211_NODE_STAT(ni, rx_mgmt);
834246772Sjkim		if (dir != IEEE80211_FC1_DIR_NODS) {
835238405Sjkim			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
836238405Sjkim			    wh, "data", "incorrect dir 0x%x", dir);
837280304Sjkim			vap->iv_stats.is_rx_wrongdir++;
838238405Sjkim			goto err;
839238405Sjkim		}
840280304Sjkim		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
841280304Sjkim			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
842280304Sjkim			    ni->ni_macaddr, "mgt", "too short: len %u",
843162914Ssimon			    m->m_pkthdr.len);
844162914Ssimon			vap->iv_stats.is_rx_tooshort++;
845162914Ssimon			goto out;
846162914Ssimon		}
847162914Ssimon#ifdef IEEE80211_DEBUG
848280304Sjkim		if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) ||
849162914Ssimon		    ieee80211_msg_dumppkts(vap)) {
850162914Ssimon			if_printf(ifp, "received %s from %s rssi %d\n",
851162914Ssimon			    ieee80211_mgt_subtype_name[subtype >>
852162914Ssimon				IEEE80211_FC0_SUBTYPE_SHIFT],
853162914Ssimon			    ether_sprintf(wh->i_addr2), rssi);
854162914Ssimon		}
855280304Sjkim#endif
856162914Ssimon		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
857162914Ssimon			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
858162914Ssimon				/*
859162914Ssimon				 * Only shared key auth frames with a challenge
860162914Ssimon				 * should be encrypted, discard all others.
861162914Ssimon				 */
862280304Sjkim				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
863162914Ssimon				    wh, ieee80211_mgt_subtype_name[subtype >>
864280304Sjkim					IEEE80211_FC0_SUBTYPE_SHIFT],
865110007Smarkm				    "%s", "WEP set but not permitted");
866280304Sjkim				vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
867194206Ssimon				goto out;
868194206Ssimon			}
869194206Ssimon			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
870280304Sjkim				/*
871194206Ssimon				 * Discard encrypted frames when privacy is off.
872280304Sjkim				 */
873194206Ssimon				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
874110007Smarkm				    wh, "mgt", "%s", "WEP set but PRIVACY off");
875110007Smarkm				vap->iv_stats.is_rx_noprivacy++;
876110007Smarkm				goto out;
877280304Sjkim			}
878280304Sjkim			hdrspace = ieee80211_hdrspace(ic, wh);
879280304Sjkim			key = ieee80211_crypto_decap(ni, m, hdrspace);
880280304Sjkim			if (key == NULL) {
881280304Sjkim				/* NB: stats+msgs handled in crypto_decap */
882280304Sjkim				goto out;
883280304Sjkim			}
884110007Smarkm			wh = mtod(m, struct ieee80211_frame *);
88559194Skris			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
88659194Skris		}
887280304Sjkim		vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
888280304Sjkim		goto out;
889280304Sjkim
89055714Skris	case IEEE80211_FC0_TYPE_CTL:
891110007Smarkm		vap->iv_stats.is_rx_ctl++;
892110007Smarkm		IEEE80211_NODE_STAT(ni, rx_ctrl);
89355714Skris		vap->iv_recv_ctl(ni, m, subtype);
89455714Skris		goto out;
89555714Skris
89655714Skris	default:
89755714Skris		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
898280304Sjkim		    wh, NULL, "bad frame type 0x%x", type);
899280304Sjkim		/* should not come here */
900280304Sjkim		break;
901280304Sjkim	}
902280304Sjkimerr:
903280304Sjkim	ifp->if_ierrors++;
904238405Sjkimout:
905280304Sjkim	if (m != NULL) {
906280304Sjkim		if (need_tap && ieee80211_radiotap_active_vap(vap))
907280304Sjkim			ieee80211_radiotap_rx(vap, m);
908280304Sjkim		m_freem(m);
909280304Sjkim	}
910280304Sjkim	return type;
911238405Sjkim#undef SEQ_LEQ
912280304Sjkim}
913280304Sjkim
914280304Sjkimstatic void
915280304Sjkimsta_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
916280304Sjkim    int rssi, int nf, uint16_t seq, uint16_t status)
917280304Sjkim{
918280304Sjkim	struct ieee80211vap *vap = ni->ni_vap;
919280304Sjkim
920280304Sjkim	if (ni->ni_authmode == IEEE80211_AUTH_SHARED) {
921280304Sjkim		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
922280304Sjkim		    ni->ni_macaddr, "open auth",
923280304Sjkim		    "bad sta auth mode %u", ni->ni_authmode);
924280304Sjkim		vap->iv_stats.is_rx_bad_auth++;	/* XXX */
925280304Sjkim		return;
926280304Sjkim	}
927110007Smarkm	if (vap->iv_state != IEEE80211_S_AUTH ||
928280304Sjkim	    seq != IEEE80211_AUTH_OPEN_RESPONSE) {
929110007Smarkm		vap->iv_stats.is_rx_bad_auth++;
930280304Sjkim		return;
931110007Smarkm	}
932280304Sjkim	if (status != 0) {
933280304Sjkim		IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
934110007Smarkm		    ni, "open auth failed (reason %d)", status);
935280304Sjkim		vap->iv_stats.is_rx_auth_fail++;
936110007Smarkm		vap->iv_stats.is_rx_authfail_code = status;
937280304Sjkim		ieee80211_new_state(vap, IEEE80211_S_SCAN,
938280304Sjkim		    IEEE80211_SCAN_FAIL_STATUS);
939110007Smarkm	} else
940280304Sjkim		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
941110007Smarkm}
942280304Sjkim
943280304Sjkimstatic void
944160817Ssimonsta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
945280304Sjkim    uint8_t *frm, uint8_t *efrm, int rssi, int nf,
946160817Ssimon    uint16_t seq, uint16_t status)
947280304Sjkim{
948110007Smarkm	struct ieee80211vap *vap = ni->ni_vap;
949280304Sjkim	uint8_t *challenge;
950280304Sjkim	int estatus;
951160817Ssimon
952280304Sjkim	/*
953280304Sjkim	 * NB: this can happen as we allow pre-shared key
954280304Sjkim	 * authentication to be enabled w/o wep being turned
95555714Skris	 * on so that configuration of these can be done
956280304Sjkim	 * in any order.  It may be better to enforce the
957280304Sjkim	 * ordering in which case this check would just be
958280304Sjkim	 * for sanity/consistency.
959280304Sjkim	 */
960280304Sjkim	if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
96155714Skris		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
962160817Ssimon		    ni->ni_macaddr, "shared key auth",
963160817Ssimon		    "%s", " PRIVACY is disabled");
964280304Sjkim		estatus = IEEE80211_STATUS_ALG;
965160817Ssimon		goto bad;
96655714Skris	}
967160817Ssimon	/*
968160817Ssimon	 * Pre-shared key authentication is evil; accept
969238405Sjkim	 * it only if explicitly configured (it is supported
970280304Sjkim	 * mainly for compatibility with clients like OS X).
971238405Sjkim	 */
972280304Sjkim	if (ni->ni_authmode != IEEE80211_AUTH_AUTO &&
973238405Sjkim	    ni->ni_authmode != IEEE80211_AUTH_SHARED) {
974280304Sjkim		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
975238405Sjkim		    ni->ni_macaddr, "shared key auth",
976238405Sjkim		    "bad sta auth mode %u", ni->ni_authmode);
977238405Sjkim		vap->iv_stats.is_rx_bad_auth++;	/* XXX maybe a unique error? */
97855714Skris		estatus = IEEE80211_STATUS_ALG;
97955714Skris		goto bad;
98055714Skris	}
98155714Skris
98255714Skris	challenge = NULL;
98355714Skris	if (frm + 1 < efrm) {
98455714Skris		if ((frm[1] + 2) > (efrm - frm)) {
985280304Sjkim			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
986280304Sjkim			    ni->ni_macaddr, "shared key auth",
98755714Skris			    "ie %d/%d too long",
98855714Skris			    frm[0], (frm[1] + 2) - (efrm - frm));
98955714Skris			vap->iv_stats.is_rx_bad_auth++;
990280304Sjkim			estatus = IEEE80211_STATUS_CHALLENGE;
991280304Sjkim			goto bad;
99255714Skris		}
993280304Sjkim		if (*frm == IEEE80211_ELEMID_CHALLENGE)
994280304Sjkim			challenge = frm;
995238405Sjkim		frm += frm[1] + 2;
996280304Sjkim	}
997280304Sjkim	switch (seq) {
99855714Skris	case IEEE80211_AUTH_SHARED_CHALLENGE:
999280304Sjkim	case IEEE80211_AUTH_SHARED_RESPONSE:
1000280304Sjkim		if (challenge == NULL) {
100155714Skris			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
100255714Skris			    ni->ni_macaddr, "shared key auth",
100355714Skris			    "%s", "no challenge");
1004280304Sjkim			vap->iv_stats.is_rx_bad_auth++;
1005280304Sjkim			estatus = IEEE80211_STATUS_CHALLENGE;
1006238405Sjkim			goto bad;
1007238405Sjkim		}
1008238405Sjkim		if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
1009238405Sjkim			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
1010280304Sjkim			    ni->ni_macaddr, "shared key auth",
1011238405Sjkim			    "bad challenge len %d", challenge[1]);
1012280304Sjkim			vap->iv_stats.is_rx_bad_auth++;
1013238405Sjkim			estatus = IEEE80211_STATUS_CHALLENGE;
1014280304Sjkim			goto bad;
1015280304Sjkim		}
1016110007Smarkm	default:
1017280304Sjkim		break;
1018280304Sjkim	}
1019280304Sjkim	if (vap->iv_state != IEEE80211_S_AUTH)
102055714Skris		return;
102155714Skris	switch (seq) {
1022280304Sjkim	case IEEE80211_AUTH_SHARED_PASS:
1023280304Sjkim		if (ni->ni_challenge != NULL) {
1024280304Sjkim			free(ni->ni_challenge, M_80211_NODE);
1025194206Ssimon			ni->ni_challenge = NULL;
1026280304Sjkim		}
1027280304Sjkim		if (status != 0) {
1028280304Sjkim			IEEE80211_NOTE_FRAME(vap,
1029280304Sjkim			    IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, wh,
1030280304Sjkim			    "shared key auth failed (reason %d)", status);
1031194206Ssimon			vap->iv_stats.is_rx_auth_fail++;
1032238405Sjkim			vap->iv_stats.is_rx_authfail_code = status;
1033238405Sjkim			return;
1034238405Sjkim		}
1035238405Sjkim		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
1036280304Sjkim		break;
1037238405Sjkim	case IEEE80211_AUTH_SHARED_CHALLENGE:
1038238405Sjkim		if (!ieee80211_alloc_challenge(ni))
1039280304Sjkim			return;
1040280304Sjkim		/* XXX could optimize by passing recvd challenge */
1041280304Sjkim		memcpy(ni->ni_challenge, &challenge[2], challenge[1]);
1042280304Sjkim		IEEE80211_SEND_MGMT(ni,
1043238405Sjkim			IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
1044280304Sjkim		break;
1045280304Sjkim	default:
1046280304Sjkim		IEEE80211_DISCARD(vap, IEEE80211_MSG_AUTH,
1047280304Sjkim		    wh, "shared key auth", "bad seq %d", seq);
1048280304Sjkim		vap->iv_stats.is_rx_bad_auth++;
1049280304Sjkim		return;
1050238405Sjkim	}
1051238405Sjkim	return;
1052280304Sjkimbad:
1053280304Sjkim	/*
1054280304Sjkim	 * Kick the state machine.  This short-circuits
1055280304Sjkim	 * using the mgt frame timeout to trigger the
1056280304Sjkim	 * state transition.
1057280304Sjkim	 */
1058280304Sjkim	if (vap->iv_state == IEEE80211_S_AUTH)
1059280304Sjkim		ieee80211_new_state(vap, IEEE80211_S_SCAN,
1060280304Sjkim		    IEEE80211_SCAN_FAIL_STATUS);
1061280304Sjkim}
1062280304Sjkim
1063238405Sjkimstatic int
1064280304Sjkimieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
1065280304Sjkim	const struct ieee80211_frame *wh)
1066280304Sjkim{
1067280304Sjkim#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
1068280304Sjkim	struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme;
1069280304Sjkim	u_int len = frm[1], qosinfo;
1070280304Sjkim	int i;
1071280304Sjkim
1072280304Sjkim	if (len < sizeof(struct ieee80211_wme_param)-2) {
1073238405Sjkim		IEEE80211_DISCARD_IE(vap,
1074280304Sjkim		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
1075280304Sjkim		    wh, "WME", "too short, len %u", len);
1076280304Sjkim		return -1;
1077280304Sjkim	}
1078280304Sjkim	qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)];
1079280304Sjkim	qosinfo &= WME_QOSINFO_COUNT;
1080280304Sjkim	/* XXX do proper check for wraparound */
1081280304Sjkim	if (qosinfo == wme->wme_wmeChanParams.cap_info)
1082280304Sjkim		return 0;
1083280304Sjkim	frm += __offsetof(struct ieee80211_wme_param, params_acParams);
1084280304Sjkim	for (i = 0; i < WME_NUM_AC; i++) {
1085280304Sjkim		struct wmeParams *wmep =
1086280304Sjkim			&wme->wme_wmeChanParams.cap_wmeParams[i];
1087280304Sjkim		/* NB: ACI not used */
1088238405Sjkim		wmep->wmep_acm = MS(frm[0], WME_PARAM_ACM);
1089238405Sjkim		wmep->wmep_aifsn = MS(frm[0], WME_PARAM_AIFSN);
1090280304Sjkim		wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN);
1091238405Sjkim		wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX);
1092280304Sjkim		wmep->wmep_txopLimit = LE_READ_2(frm+2);
1093280304Sjkim		frm += 4;
1094238405Sjkim	}
1095280304Sjkim	wme->wme_wmeChanParams.cap_info = qosinfo;
1096280304Sjkim	return 1;
1097280304Sjkim#undef MS
1098280304Sjkim}
1099280304Sjkim
1100280304Sjkim/*
1101280304Sjkim * Process 11h Channel Switch Announcement (CSA) ie.  If this
1102280304Sjkim * is the first CSA then initiate the switch.  Otherwise we
1103280304Sjkim * track state and trigger completion and/or cancel of the switch.
1104280304Sjkim * XXX should be public for IBSS use
1105280304Sjkim */
1106238405Sjkimstatic void
1107280304Sjkimieee80211_parse_csaparams(struct ieee80211vap *vap, uint8_t *frm,
1108280304Sjkim	const struct ieee80211_frame *wh)
1109280304Sjkim{
1110238405Sjkim	struct ieee80211com *ic = vap->iv_ic;
1111280304Sjkim	const struct ieee80211_csa_ie *csa =
1112280304Sjkim	    (const struct ieee80211_csa_ie *) frm;
1113238405Sjkim
1114280304Sjkim	KASSERT(vap->iv_state >= IEEE80211_S_RUN,
1115280304Sjkim	    ("state %s", ieee80211_state_name[vap->iv_state]));
1116238405Sjkim
1117280304Sjkim	if (csa->csa_mode > 1) {
1118280304Sjkim		IEEE80211_DISCARD_IE(vap,
1119238405Sjkim		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
1120280304Sjkim		    wh, "CSA", "invalid mode %u", csa->csa_mode);
1121280304Sjkim		return;
1122280304Sjkim	}
1123238405Sjkim	IEEE80211_LOCK(ic);
1124280304Sjkim	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
1125280304Sjkim		/*
1126238405Sjkim		 * Convert the channel number to a channel reference.  We
1127280304Sjkim		 * try first to preserve turbo attribute of the current
1128280304Sjkim		 * channel then fallback.  Note this will not work if the
1129238405Sjkim		 * CSA specifies a channel that requires a band switch (e.g.
1130280304Sjkim		 * 11a => 11g).  This is intentional as 11h is defined only
1131238405Sjkim		 * for 5GHz/11a and because the switch does not involve a
1132280304Sjkim		 * reassociation, protocol state (capabilities, negotated
1133238405Sjkim		 * rates, etc) may/will be wrong.
1134280304Sjkim		 */
1135238405Sjkim		struct ieee80211_channel *c =
1136238405Sjkim		    ieee80211_find_channel_byieee(ic, csa->csa_newchan,
1137280304Sjkim			(ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALLTURBO));
1138238405Sjkim		if (c == NULL) {
1139280304Sjkim			c = ieee80211_find_channel_byieee(ic,
1140280304Sjkim			    csa->csa_newchan,
1141280304Sjkim			    (ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALL));
1142238405Sjkim			if (c == NULL) {
1143280304Sjkim				IEEE80211_DISCARD_IE(vap,
1144238405Sjkim				    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
1145280304Sjkim				    wh, "CSA", "invalid channel %u",
1146238405Sjkim				    csa->csa_newchan);
1147280304Sjkim				goto done;
1148280304Sjkim			}
1149280304Sjkim		}
1150238405Sjkim#if IEEE80211_CSA_COUNT_MIN > 0
1151280304Sjkim		if (csa->csa_count < IEEE80211_CSA_COUNT_MIN) {
1152238405Sjkim			/*
1153238405Sjkim			 * Require at least IEEE80211_CSA_COUNT_MIN count to
1154280304Sjkim			 * reduce the risk of being redirected by a fabricated
1155238405Sjkim			 * CSA.  If a valid CSA is dropped we'll still get a
1156280304Sjkim			 * beacon miss when the AP leaves the channel so we'll
1157238405Sjkim			 * eventually follow to the new channel.
1158238405Sjkim			 *
1159238405Sjkim			 * NOTE: this violates the 11h spec that states that
1160238405Sjkim			 * count may be any value and if 0 then a switch
1161238405Sjkim			 * should happen asap.
1162238405Sjkim			 */
1163238405Sjkim			IEEE80211_DISCARD_IE(vap,
1164238405Sjkim			    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
1165238405Sjkim			    wh, "CSA", "count %u too small, must be >= %u",
1166238405Sjkim			    csa->csa_count, IEEE80211_CSA_COUNT_MIN);
1167280304Sjkim			goto done;
1168238405Sjkim		}
1169280304Sjkim#endif
1170238405Sjkim		ieee80211_csa_startswitch(ic, c, csa->csa_mode, csa->csa_count);
1171238405Sjkim	} else {
1172238405Sjkim		/*
1173238405Sjkim		 * Validate this ie against the initial CSA.  We require
1174238405Sjkim		 * mode and channel not change and the count must be
1175280304Sjkim		 * monotonically decreasing.  This may be pointless and
1176238405Sjkim		 * canceling the switch as a result may be too paranoid but
1177238405Sjkim		 * in the worst case if we drop out of CSA because of this
1178238405Sjkim		 * and the AP does move then we'll just end up taking a
1179238405Sjkim		 * beacon miss and scan to find the AP.
1180238405Sjkim		 *
1181238405Sjkim		 * XXX may want <= on count as we also process ProbeResp
1182238405Sjkim		 * frames and those may come in w/ the same count as the
1183238405Sjkim		 * previous beacon; but doing so leaves us open to a stuck
1184238405Sjkim		 * count until we add a dead-man timer
1185238405Sjkim		 */
1186238405Sjkim		if (!(csa->csa_count < ic->ic_csa_count &&
1187238405Sjkim		      csa->csa_mode == ic->ic_csa_mode &&
1188280304Sjkim		      csa->csa_newchan == ieee80211_chan2ieee(ic, ic->ic_csa_newchan))) {
1189280304Sjkim			IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_DOTH, wh,
1190238405Sjkim			    "CSA ie mismatch, initial ie <%d,%d,%d>, "
1191238405Sjkim			    "this ie <%d,%d,%d>", ic->ic_csa_mode,
1192280304Sjkim			    ic->ic_csa_newchan, ic->ic_csa_count,
1193280304Sjkim			    csa->csa_mode, csa->csa_newchan, csa->csa_count);
1194238405Sjkim			ieee80211_csa_cancelswitch(ic);
1195238405Sjkim		} else {
1196280304Sjkim			if (csa->csa_count <= 1)
1197280304Sjkim				ieee80211_csa_completeswitch(ic);
1198238405Sjkim			else
1199238405Sjkim				ic->ic_csa_count = csa->csa_count;
1200280304Sjkim		}
1201280304Sjkim	}
1202238405Sjkimdone:
1203238405Sjkim	IEEE80211_UNLOCK(ic);
1204280304Sjkim}
1205280304Sjkim
1206238405Sjkim/*
1207238405Sjkim * Return non-zero if a background scan may be continued:
1208238405Sjkim * o bg scan is active
1209238405Sjkim * o no channel switch is pending
1210238405Sjkim * o there has not been any traffic recently
1211280304Sjkim *
1212238405Sjkim * Note we do not check if there is an administrative enable;
1213238405Sjkim * this is only done to start the scan.  We assume that any
1214238405Sjkim * change in state will be accompanied by a request to cancel
1215238405Sjkim * active scans which will otherwise cause this test to fail.
1216238405Sjkim */
1217238405Sjkimstatic __inline int
1218238405Sjkimcontbgscan(struct ieee80211vap *vap)
1219238405Sjkim{
1220238405Sjkim	struct ieee80211com *ic = vap->iv_ic;
1221238405Sjkim
1222238405Sjkim	return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
1223238405Sjkim	    (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
1224280304Sjkim	    vap->iv_state == IEEE80211_S_RUN &&		/* XXX? */
1225238405Sjkim	    time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
1226238405Sjkim}
1227280304Sjkim
1228280304Sjkim/*
1229238405Sjkim * Return non-zero if a backgrond scan may be started:
1230238405Sjkim * o bg scanning is administratively enabled
1231280304Sjkim * o no channel switch is pending
1232238405Sjkim * o we are not boosted on a dynamic turbo channel
1233238405Sjkim * o there has not been a scan recently
1234280304Sjkim * o there has not been any traffic recently
1235280304Sjkim */
1236280304Sjkimstatic __inline int
1237238405Sjkimstartbgscan(struct ieee80211vap *vap)
1238238405Sjkim{
1239280304Sjkim	struct ieee80211com *ic = vap->iv_ic;
1240280304Sjkim
1241280304Sjkim	return ((vap->iv_flags & IEEE80211_F_BGSCAN) &&
1242238405Sjkim	    (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
1243238405Sjkim#ifdef IEEE80211_SUPPORT_SUPERG
1244280304Sjkim	    !IEEE80211_IS_CHAN_DTURBO(ic->ic_curchan) &&
1245280304Sjkim#endif
1246280304Sjkim	    time_after(ticks, ic->ic_lastscan + vap->iv_bgscanintvl) &&
1247280304Sjkim	    time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
1248280304Sjkim}
1249238405Sjkim
1250238405Sjkimstatic void
1251280304Sjkimsta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
1252280304Sjkim	int subtype, int rssi, int nf)
1253280304Sjkim{
1254280304Sjkim#define	ISPROBE(_st)	((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
1255280304Sjkim#define	ISREASSOC(_st)	((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
1256280304Sjkim	struct ieee80211vap *vap = ni->ni_vap;
1257238405Sjkim	struct ieee80211com *ic = ni->ni_ic;
1258238405Sjkim	struct ieee80211_frame *wh;
1259280304Sjkim	uint8_t *frm, *efrm;
1260280304Sjkim	uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
1261280304Sjkim	uint8_t rate;
1262280304Sjkim
1263280304Sjkim	wh = mtod(m0, struct ieee80211_frame *);
1264280304Sjkim	frm = (uint8_t *)&wh[1];
1265280304Sjkim	efrm = mtod(m0, uint8_t *) + m0->m_len;
1266280304Sjkim	switch (subtype) {
1267280304Sjkim	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
1268280304Sjkim	case IEEE80211_FC0_SUBTYPE_BEACON: {
1269238405Sjkim		struct ieee80211_scanparams scan;
1270238405Sjkim		/*
1271280304Sjkim		 * We process beacon/probe response frames:
1272280304Sjkim		 *    o when scanning, or
1273280304Sjkim		 *    o station mode when associated (to collect state
1274280304Sjkim		 *      updates such as 802.11g slot time)
1275280304Sjkim		 * Frames otherwise received are discarded.
1276280304Sjkim		 */
1277238405Sjkim		if (!((ic->ic_flags & IEEE80211_F_SCAN) || ni->ni_associd)) {
1278238405Sjkim			vap->iv_stats.is_rx_mgtdiscard++;
1279280304Sjkim			return;
1280280304Sjkim		}
1281280304Sjkim		/* XXX probe response in sta mode when !scanning? */
1282280304Sjkim		if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
1283280304Sjkim			return;
1284280304Sjkim		/*
1285238405Sjkim		 * Count frame now that we know it's to be processed.
1286238405Sjkim		 */
1287280304Sjkim		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
1288280304Sjkim			vap->iv_stats.is_rx_beacon++;		/* XXX remove */
1289280304Sjkim			IEEE80211_NODE_STAT(ni, rx_beacons);
1290280304Sjkim		} else
1291280304Sjkim			IEEE80211_NODE_STAT(ni, rx_proberesp);
1292280304Sjkim		/*
1293238405Sjkim		 * When operating in station mode, check for state updates.
1294238405Sjkim		 * Be careful to ignore beacons received while doing a
1295280304Sjkim		 * background scan.  We consider only 11g/WMM stuff right now.
1296280304Sjkim		 */
1297280304Sjkim		if (ni->ni_associd != 0 &&
1298280304Sjkim		    ((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
1299280304Sjkim		     IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) {
1300280304Sjkim			/* record tsf of last beacon */
1301238405Sjkim			memcpy(ni->ni_tstamp.data, scan.tstamp,
1302238405Sjkim				sizeof(ni->ni_tstamp));
1303280304Sjkim			/* count beacon frame for s/w bmiss handling */
1304280304Sjkim			vap->iv_swbmiss_count++;
1305280304Sjkim			vap->iv_bmiss_count = 0;
1306280304Sjkim			if (ni->ni_erp != scan.erp) {
1307238405Sjkim				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1308238405Sjkim				    wh->i_addr2,
1309280304Sjkim				    "erp change: was 0x%x, now 0x%x",
1310280304Sjkim				    ni->ni_erp, scan.erp);
1311280304Sjkim				if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
1312280304Sjkim				    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
1313280304Sjkim					ic->ic_flags |= IEEE80211_F_USEPROT;
1314238405Sjkim				else
1315246772Sjkim					ic->ic_flags &= ~IEEE80211_F_USEPROT;
1316246772Sjkim				ni->ni_erp = scan.erp;
131755714Skris				/* XXX statistic */
1318280304Sjkim				/* XXX driver notification */
1319280304Sjkim			}
132055714Skris			if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
132155714Skris				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
132289840Skris				    wh->i_addr2,
132355714Skris				    "capabilities change: was 0x%x, now 0x%x",
132455714Skris				    ni->ni_capinfo, scan.capinfo);
132555714Skris				/*
132655714Skris				 * NB: we assume short preamble doesn't
1327280304Sjkim				 *     change dynamically
1328280304Sjkim				 */
1329280304Sjkim				ieee80211_set_shortslottime(ic,
1330280304Sjkim					IEEE80211_IS_CHAN_A(ic->ic_bsschan) ||
1331280304Sjkim					(scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
1332280304Sjkim				ni->ni_capinfo = (ni->ni_capinfo &~ IEEE80211_CAPINFO_SHORT_SLOTTIME)
1333280304Sjkim					       | (scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME);
1334280304Sjkim				/* XXX statistic */
1335280304Sjkim			}
1336280304Sjkim			if (scan.wme != NULL &&
1337280304Sjkim			    (ni->ni_flags & IEEE80211_NODE_QOS) &&
1338280304Sjkim			    ieee80211_parse_wmeparams(vap, scan.wme, wh) > 0)
1339280304Sjkim				ieee80211_wme_updateparams(vap);
1340280304Sjkim#ifdef IEEE80211_SUPPORT_SUPERG
1341280304Sjkim			if (scan.ath != NULL)
1342280304Sjkim				ieee80211_parse_athparams(ni, scan.ath, wh);
1343280304Sjkim#endif
1344280304Sjkim			if (scan.htcap != NULL && scan.htinfo != NULL &&
1345280304Sjkim			    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1346280304Sjkim				ieee80211_ht_updateparams(ni,
1347280304Sjkim				    scan.htcap, scan.htinfo);
1348280304Sjkim				/* XXX state changes? */
1349280304Sjkim			}
1350280304Sjkim			if (scan.tim != NULL) {
1351280304Sjkim				struct ieee80211_tim_ie *tim =
1352280304Sjkim				    (struct ieee80211_tim_ie *) scan.tim;
1353280304Sjkim#if 0
1354280304Sjkim				int aid = IEEE80211_AID(ni->ni_associd);
1355280304Sjkim				int ix = aid / NBBY;
1356280304Sjkim				int min = tim->tim_bitctl &~ 1;
1357280304Sjkim				int max = tim->tim_len + min - 4;
1358280304Sjkim				if ((tim->tim_bitctl&1) ||
1359280304Sjkim				    (min <= ix && ix <= max &&
1360280304Sjkim				     isset(tim->tim_bitmap - min, aid))) {
1361280304Sjkim					/*
1362280304Sjkim					 * XXX Do not let bg scan kick off
1363280304Sjkim					 * we are expecting data.
1364280304Sjkim					 */
1365280304Sjkim					ic->ic_lastdata = ticks;
1366280304Sjkim					ieee80211_sta_pwrsave(vap, 0);
1367280304Sjkim				}
1368280304Sjkim#endif
1369280304Sjkim				ni->ni_dtim_count = tim->tim_count;
1370280304Sjkim				ni->ni_dtim_period = tim->tim_period;
1371280304Sjkim			}
1372280304Sjkim			if (scan.csa != NULL &&
1373280304Sjkim			    (vap->iv_flags & IEEE80211_F_DOTH))
1374280304Sjkim				ieee80211_parse_csaparams(vap, scan.csa, wh);
1375280304Sjkim			else if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
1376280304Sjkim				/*
1377280304Sjkim				 * No CSA ie or 11h disabled, but a channel
1378280304Sjkim				 * switch is pending; drop out so we aren't
1379280304Sjkim				 * stuck in CSA state.  If the AP really is
1380280304Sjkim				 * moving we'll get a beacon miss and scan.
1381280304Sjkim				 */
1382280304Sjkim				IEEE80211_LOCK(ic);
1383280304Sjkim				ieee80211_csa_cancelswitch(ic);
1384280304Sjkim				IEEE80211_UNLOCK(ic);
1385280304Sjkim			}
1386280304Sjkim			/*
1387280304Sjkim			 * If scanning, pass the info to the scan module.
1388280304Sjkim			 * Otherwise, check if it's the right time to do
1389280304Sjkim			 * a background scan.  Background scanning must
1390280304Sjkim			 * be enabled and we must not be operating in the
1391280304Sjkim			 * turbo phase of dynamic turbo mode.  Then,
1392280304Sjkim			 * it's been a while since the last background
1393280304Sjkim			 * scan and if no data frames have come through
1394280304Sjkim			 * recently, kick off a scan.  Note that this
1395280304Sjkim			 * is the mechanism by which a background scan
1396280304Sjkim			 * is started _and_ continued each time we
1397280304Sjkim			 * return on-channel to receive a beacon from
1398280304Sjkim			 * our ap.
1399280304Sjkim			 */
1400280304Sjkim			if (ic->ic_flags & IEEE80211_F_SCAN) {
1401280304Sjkim				ieee80211_add_scan(vap, &scan, wh,
1402280304Sjkim					subtype, rssi, nf);
1403280304Sjkim			} else if (contbgscan(vap)) {
140455714Skris				ieee80211_bg_scan(vap, 0);
140555714Skris			} else if (startbgscan(vap)) {
1406280304Sjkim				vap->iv_stats.is_scan_bg++;
1407280304Sjkim#if 0
1408280304Sjkim				/* wakeup if we are sleeing */
1409280304Sjkim				ieee80211_set_pwrsave(vap, 0);
1410280304Sjkim#endif
1411280304Sjkim				ieee80211_bg_scan(vap, 0);
1412280304Sjkim			}
1413280304Sjkim			return;
1414280304Sjkim		}
1415280304Sjkim		/*
1416280304Sjkim		 * If scanning, just pass information to the scan module.
1417280304Sjkim		 */
1418280304Sjkim		if (ic->ic_flags & IEEE80211_F_SCAN) {
1419280304Sjkim			if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
1420280304Sjkim				/*
1421280304Sjkim				 * Actively scanning a channel marked passive;
1422280304Sjkim				 * send a probe request now that we know there
1423280304Sjkim				 * is 802.11 traffic present.
1424280304Sjkim				 *
1425280304Sjkim				 * XXX check if the beacon we recv'd gives
1426280304Sjkim				 * us what we need and suppress the probe req
1427280304Sjkim				 */
1428280304Sjkim				ieee80211_probe_curchan(vap, 1);
1429280304Sjkim				ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
1430280304Sjkim			}
1431280304Sjkim			ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
1432280304Sjkim			return;
1433280304Sjkim		}
1434280304Sjkim		break;
1435280304Sjkim	}
1436280304Sjkim
1437280304Sjkim	case IEEE80211_FC0_SUBTYPE_AUTH: {
1438280304Sjkim		uint16_t algo, seq, status;
1439280304Sjkim		/*
1440280304Sjkim		 * auth frame format
1441280304Sjkim		 *	[2] algorithm
1442280304Sjkim		 *	[2] sequence
1443280304Sjkim		 *	[2] status
1444280304Sjkim		 *	[tlv*] challenge
1445280304Sjkim		 */
1446280304Sjkim		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
1447280304Sjkim		algo   = le16toh(*(uint16_t *)frm);
1448280304Sjkim		seq    = le16toh(*(uint16_t *)(frm + 2));
1449280304Sjkim		status = le16toh(*(uint16_t *)(frm + 4));
1450280304Sjkim		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2,
1451280304Sjkim		    "recv auth frame with algorithm %d seq %d", algo, seq);
1452280304Sjkim
1453280304Sjkim		if (vap->iv_flags & IEEE80211_F_COUNTERM) {
1454280304Sjkim			IEEE80211_DISCARD(vap,
1455280304Sjkim			    IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
1456280304Sjkim			    wh, "auth", "%s", "TKIP countermeasures enabled");
1457280304Sjkim			vap->iv_stats.is_rx_auth_countermeasures++;
1458280304Sjkim			if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
1459280304Sjkim				ieee80211_send_error(ni, wh->i_addr2,
1460280304Sjkim					IEEE80211_FC0_SUBTYPE_AUTH,
1461280304Sjkim					IEEE80211_REASON_MIC_FAILURE);
1462280304Sjkim			}
1463280304Sjkim			return;
1464280304Sjkim		}
1465280304Sjkim		if (algo == IEEE80211_AUTH_ALG_SHARED)
1466280304Sjkim			sta_auth_shared(ni, wh, frm + 6, efrm, rssi, nf,
1467280304Sjkim			    seq, status);
1468280304Sjkim		else if (algo == IEEE80211_AUTH_ALG_OPEN)
1469280304Sjkim			sta_auth_open(ni, wh, rssi, nf, seq, status);
1470280304Sjkim		else {
1471280304Sjkim			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1472280304Sjkim			    wh, "auth", "unsupported alg %d", algo);
1473280304Sjkim			vap->iv_stats.is_rx_auth_unsupported++;
1474280304Sjkim			return;
1475280304Sjkim		}
147655714Skris		break;
147755714Skris	}
147855714Skris
147955714Skris	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
148055714Skris	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: {
1481		uint16_t capinfo, associd;
1482		uint16_t status;
1483
1484		if (vap->iv_state != IEEE80211_S_ASSOC) {
1485			vap->iv_stats.is_rx_mgtdiscard++;
1486			return;
1487		}
1488
1489		/*
1490		 * asresp frame format
1491		 *	[2] capability information
1492		 *	[2] status
1493		 *	[2] association ID
1494		 *	[tlv] supported rates
1495		 *	[tlv] extended supported rates
1496		 *	[tlv] WME
1497		 *	[tlv] HT capabilities
1498		 *	[tlv] HT info
1499		 */
1500		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
1501		ni = vap->iv_bss;
1502		capinfo = le16toh(*(uint16_t *)frm);
1503		frm += 2;
1504		status = le16toh(*(uint16_t *)frm);
1505		frm += 2;
1506		if (status != 0) {
1507			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1508			    wh->i_addr2, "%sassoc failed (reason %d)",
1509			    ISREASSOC(subtype) ?  "re" : "", status);
1510			vap->iv_stats.is_rx_auth_fail++;	/* XXX */
1511			return;
1512		}
1513		associd = le16toh(*(uint16_t *)frm);
1514		frm += 2;
1515
1516		rates = xrates = wme = htcap = htinfo = NULL;
1517		while (efrm - frm > 1) {
1518			IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
1519			switch (*frm) {
1520			case IEEE80211_ELEMID_RATES:
1521				rates = frm;
1522				break;
1523			case IEEE80211_ELEMID_XRATES:
1524				xrates = frm;
1525				break;
1526			case IEEE80211_ELEMID_HTCAP:
1527				htcap = frm;
1528				break;
1529			case IEEE80211_ELEMID_HTINFO:
1530				htinfo = frm;
1531				break;
1532			case IEEE80211_ELEMID_VENDOR:
1533				if (iswmeoui(frm))
1534					wme = frm;
1535				else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) {
1536					/*
1537					 * Accept pre-draft HT ie's if the
1538					 * standard ones have not been seen.
1539					 */
1540					if (ishtcapoui(frm)) {
1541						if (htcap == NULL)
1542							htcap = frm;
1543					} else if (ishtinfooui(frm)) {
1544						if (htinfo == NULL)
1545							htcap = frm;
1546					}
1547				}
1548				/* XXX Atheros OUI support */
1549				break;
1550			}
1551			frm += frm[1] + 2;
1552		}
1553
1554		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return);
1555		if (xrates != NULL)
1556			IEEE80211_VERIFY_ELEMENT(xrates,
1557				IEEE80211_RATE_MAXSIZE - rates[1], return);
1558		rate = ieee80211_setup_rates(ni, rates, xrates,
1559				IEEE80211_F_JOIN |
1560				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1561				IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1562		if (rate & IEEE80211_RATE_BASIC) {
1563			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
1564			    wh->i_addr2,
1565			    "%sassoc failed (rate set mismatch)",
1566			    ISREASSOC(subtype) ?  "re" : "");
1567			vap->iv_stats.is_rx_assoc_norate++;
1568			ieee80211_new_state(vap, IEEE80211_S_SCAN,
1569			    IEEE80211_SCAN_FAIL_STATUS);
1570			return;
1571		}
1572
1573		ni->ni_capinfo = capinfo;
1574		ni->ni_associd = associd;
1575		if (ni->ni_jointime == 0)
1576			ni->ni_jointime = time_uptime;
1577		if (wme != NULL &&
1578		    ieee80211_parse_wmeparams(vap, wme, wh) >= 0) {
1579			ni->ni_flags |= IEEE80211_NODE_QOS;
1580			ieee80211_wme_updateparams(vap);
1581		} else
1582			ni->ni_flags &= ~IEEE80211_NODE_QOS;
1583		/*
1584		 * Setup HT state according to the negotiation.
1585		 *
1586		 * NB: shouldn't need to check if HT use is enabled but some
1587		 *     ap's send back HT ie's even when we don't indicate we
1588		 *     are HT capable in our AssocReq.
1589		 */
1590		if (htcap != NULL && htinfo != NULL &&
1591		    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1592			ieee80211_ht_node_init(ni);
1593			ieee80211_ht_updateparams(ni, htcap, htinfo);
1594			ieee80211_setup_htrates(ni, htcap,
1595			     IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
1596			ieee80211_setup_basic_htrates(ni, htinfo);
1597			ieee80211_node_setuptxparms(ni);
1598		} else {
1599#ifdef IEEE80211_SUPPORT_SUPERG
1600			if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_ATH))
1601				ieee80211_ff_node_init(ni);
1602#endif
1603		}
1604		/*
1605		 * Configure state now that we are associated.
1606		 *
1607		 * XXX may need different/additional driver callbacks?
1608		 */
1609		if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
1610		    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
1611			ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
1612			ic->ic_flags &= ~IEEE80211_F_USEBARKER;
1613		} else {
1614			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
1615			ic->ic_flags |= IEEE80211_F_USEBARKER;
1616		}
1617		ieee80211_set_shortslottime(ic,
1618			IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
1619			(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
1620		/*
1621		 * Honor ERP protection.
1622		 *
1623		 * NB: ni_erp should zero for non-11g operation.
1624		 */
1625		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
1626		    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
1627			ic->ic_flags |= IEEE80211_F_USEPROT;
1628		else
1629			ic->ic_flags &= ~IEEE80211_F_USEPROT;
1630		IEEE80211_NOTE_MAC(vap,
1631		    IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, wh->i_addr2,
1632		    "%sassoc success at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s",
1633		    ISREASSOC(subtype) ? "re" : "",
1634		    IEEE80211_NODE_AID(ni),
1635		    ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
1636		    ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
1637		    ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
1638		    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
1639		    ni->ni_flags & IEEE80211_NODE_HT ?
1640			(ni->ni_chw == 40 ? ", HT40" : ", HT20") : "",
1641		    ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
1642		    ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
1643			ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "",
1644		    ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "",
1645		    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ?
1646			", fast-frames" : "",
1647		    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ?
1648			", turbo" : ""
1649		);
1650		ieee80211_new_state(vap, IEEE80211_S_RUN, subtype);
1651		break;
1652	}
1653
1654	case IEEE80211_FC0_SUBTYPE_DEAUTH: {
1655		uint16_t reason;
1656
1657		if (vap->iv_state == IEEE80211_S_SCAN) {
1658			vap->iv_stats.is_rx_mgtdiscard++;
1659			return;
1660		}
1661		if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
1662			/* NB: can happen when in promiscuous mode */
1663			vap->iv_stats.is_rx_mgtdiscard++;
1664			break;
1665		}
1666
1667		/*
1668		 * deauth frame format
1669		 *	[2] reason
1670		 */
1671		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
1672		reason = le16toh(*(uint16_t *)frm);
1673
1674		vap->iv_stats.is_rx_deauth++;
1675		vap->iv_stats.is_rx_deauth_code = reason;
1676		IEEE80211_NODE_STAT(ni, rx_deauth);
1677
1678		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
1679		    "recv deauthenticate (reason %d)", reason);
1680		ieee80211_new_state(vap, IEEE80211_S_AUTH,
1681		    (reason << 8) | IEEE80211_FC0_SUBTYPE_DEAUTH);
1682		break;
1683	}
1684
1685	case IEEE80211_FC0_SUBTYPE_DISASSOC: {
1686		uint16_t reason;
1687
1688		if (vap->iv_state != IEEE80211_S_RUN &&
1689		    vap->iv_state != IEEE80211_S_ASSOC &&
1690		    vap->iv_state != IEEE80211_S_AUTH) {
1691			vap->iv_stats.is_rx_mgtdiscard++;
1692			return;
1693		}
1694		if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
1695			/* NB: can happen when in promiscuous mode */
1696			vap->iv_stats.is_rx_mgtdiscard++;
1697			break;
1698		}
1699
1700		/*
1701		 * disassoc frame format
1702		 *	[2] reason
1703		 */
1704		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
1705		reason = le16toh(*(uint16_t *)frm);
1706
1707		vap->iv_stats.is_rx_disassoc++;
1708		vap->iv_stats.is_rx_disassoc_code = reason;
1709		IEEE80211_NODE_STAT(ni, rx_disassoc);
1710
1711		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
1712		    "recv disassociate (reason %d)", reason);
1713		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
1714		break;
1715	}
1716
1717	case IEEE80211_FC0_SUBTYPE_ACTION:
1718		if (vap->iv_state == IEEE80211_S_RUN) {
1719			if (ieee80211_parse_action(ni, m0) == 0)
1720				ic->ic_recv_action(ni, frm, efrm);
1721		} else
1722			vap->iv_stats.is_rx_mgtdiscard++;
1723		break;
1724
1725	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
1726	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
1727	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
1728		vap->iv_stats.is_rx_mgtdiscard++;
1729		return;
1730	default:
1731		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1732		     wh, "mgt", "subtype 0x%x not handled", subtype);
1733		vap->iv_stats.is_rx_badsubtype++;
1734		break;
1735	}
1736#undef ISREASSOC
1737#undef ISPROBE
1738}
1739
1740static void
1741sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype)
1742{
1743}
1744