xref: /dflybsd-src/sys/netproto/802_11/wlan/ieee80211_sta.c (revision 6168f72eea01eb115cae2aabc2b56f97a8b5760d)
132176cfdSRui Paulo /*-
232176cfdSRui Paulo  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
332176cfdSRui Paulo  * All rights reserved.
432176cfdSRui Paulo  *
532176cfdSRui Paulo  * Redistribution and use in source and binary forms, with or without
632176cfdSRui Paulo  * modification, are permitted provided that the following conditions
732176cfdSRui Paulo  * are met:
832176cfdSRui Paulo  * 1. Redistributions of source code must retain the above copyright
932176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer.
1032176cfdSRui Paulo  * 2. Redistributions in binary form must reproduce the above copyright
1132176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer in the
1232176cfdSRui Paulo  *    documentation and/or other materials provided with the distribution.
1332176cfdSRui Paulo  *
1432176cfdSRui Paulo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1532176cfdSRui Paulo  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1632176cfdSRui Paulo  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1732176cfdSRui Paulo  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1832176cfdSRui Paulo  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1932176cfdSRui Paulo  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2032176cfdSRui Paulo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2132176cfdSRui Paulo  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2232176cfdSRui Paulo  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2332176cfdSRui Paulo  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2432176cfdSRui Paulo  *
2532176cfdSRui Paulo  * $FreeBSD: head/sys/net80211/ieee80211_sta.c 203422 2010-02-03 10:07:43Z rpaulo $
2632176cfdSRui Paulo  * $DragonFly$
2732176cfdSRui Paulo  */
2832176cfdSRui Paulo 
2932176cfdSRui Paulo /*
3032176cfdSRui Paulo  * IEEE 802.11 Station mode support.
3132176cfdSRui Paulo  */
3232176cfdSRui Paulo #include "opt_inet.h"
3332176cfdSRui Paulo #include "opt_wlan.h"
3432176cfdSRui Paulo 
3532176cfdSRui Paulo #include <sys/param.h>
3632176cfdSRui Paulo #include <sys/systm.h>
3732176cfdSRui Paulo #include <sys/mbuf.h>
3832176cfdSRui Paulo #include <sys/malloc.h>
3932176cfdSRui Paulo #include <sys/kernel.h>
4032176cfdSRui Paulo 
4132176cfdSRui Paulo #include <sys/socket.h>
4232176cfdSRui Paulo #include <sys/sockio.h>
4332176cfdSRui Paulo #include <sys/endian.h>
4432176cfdSRui Paulo #include <sys/errno.h>
4532176cfdSRui Paulo #include <sys/proc.h>
4632176cfdSRui Paulo #include <sys/sysctl.h>
4732176cfdSRui Paulo 
4832176cfdSRui Paulo #include <net/if.h>
4932176cfdSRui Paulo #include <net/if_media.h>
5032176cfdSRui Paulo #include <net/if_llc.h>
5132176cfdSRui Paulo #include <net/ethernet.h>
5232176cfdSRui Paulo #include <net/route.h>
5332176cfdSRui Paulo 
5432176cfdSRui Paulo #include <net/bpf.h>
5532176cfdSRui Paulo 
5632176cfdSRui Paulo #include <netproto/802_11/ieee80211_var.h>
5732176cfdSRui Paulo #include <netproto/802_11/ieee80211_sta.h>
5832176cfdSRui Paulo #include <netproto/802_11/ieee80211_input.h>
5932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
6032176cfdSRui Paulo #include <netproto/802_11/ieee80211_superg.h>
6132176cfdSRui Paulo #endif
6232176cfdSRui Paulo 
6332176cfdSRui Paulo #define	IEEE80211_RATE2MBS(r)	(((r) & IEEE80211_RATE_VAL) / 2)
6432176cfdSRui Paulo 
6532176cfdSRui Paulo static	void sta_vattach(struct ieee80211vap *);
6632176cfdSRui Paulo static	void sta_beacon_miss(struct ieee80211vap *);
6732176cfdSRui Paulo static	int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int);
6832176cfdSRui Paulo static	int sta_input(struct ieee80211_node *, struct mbuf *, int, int);
6932176cfdSRui Paulo static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *,
7032176cfdSRui Paulo 	    int subtype, int rssi, int nf);
7132176cfdSRui Paulo static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
7232176cfdSRui Paulo 
7332176cfdSRui Paulo void
7432176cfdSRui Paulo ieee80211_sta_attach(struct ieee80211com *ic)
7532176cfdSRui Paulo {
7632176cfdSRui Paulo 	ic->ic_vattach[IEEE80211_M_STA] = sta_vattach;
7732176cfdSRui Paulo }
7832176cfdSRui Paulo 
7932176cfdSRui Paulo void
8032176cfdSRui Paulo ieee80211_sta_detach(struct ieee80211com *ic)
8132176cfdSRui Paulo {
8232176cfdSRui Paulo }
8332176cfdSRui Paulo 
8432176cfdSRui Paulo static void
8532176cfdSRui Paulo sta_vdetach(struct ieee80211vap *vap)
8632176cfdSRui Paulo {
8732176cfdSRui Paulo }
8832176cfdSRui Paulo 
8932176cfdSRui Paulo static void
9032176cfdSRui Paulo sta_vattach(struct ieee80211vap *vap)
9132176cfdSRui Paulo {
9232176cfdSRui Paulo 	vap->iv_newstate = sta_newstate;
9332176cfdSRui Paulo 	vap->iv_input = sta_input;
9432176cfdSRui Paulo 	vap->iv_recv_mgmt = sta_recv_mgmt;
9532176cfdSRui Paulo 	vap->iv_recv_ctl = sta_recv_ctl;
9632176cfdSRui Paulo 	vap->iv_opdetach = sta_vdetach;
9732176cfdSRui Paulo 	vap->iv_bmiss = sta_beacon_miss;
9832176cfdSRui Paulo }
9932176cfdSRui Paulo 
10032176cfdSRui Paulo /*
10132176cfdSRui Paulo  * Handle a beacon miss event.  The common code filters out
10232176cfdSRui Paulo  * spurious events that can happen when scanning and/or before
10332176cfdSRui Paulo  * reaching RUN state.
10432176cfdSRui Paulo  */
10532176cfdSRui Paulo static void
10632176cfdSRui Paulo sta_beacon_miss(struct ieee80211vap *vap)
10732176cfdSRui Paulo {
10832176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
10932176cfdSRui Paulo 
11032176cfdSRui Paulo 	KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
11132176cfdSRui Paulo 	KASSERT(vap->iv_state >= IEEE80211_S_RUN,
11232176cfdSRui Paulo 	    ("wrong state %s", ieee80211_state_name[vap->iv_state]));
11332176cfdSRui Paulo 
11432176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
11532176cfdSRui Paulo 	    "beacon miss, mode %s state %s\n",
11632176cfdSRui Paulo 	    ieee80211_opmode_name[vap->iv_opmode],
11732176cfdSRui Paulo 	    ieee80211_state_name[vap->iv_state]);
11832176cfdSRui Paulo 
11932176cfdSRui Paulo 	if (vap->iv_state == IEEE80211_S_CSA) {
12032176cfdSRui Paulo 		/*
12132176cfdSRui Paulo 		 * A Channel Switch is pending; assume we missed the
12232176cfdSRui Paulo 		 * beacon that would've completed the process and just
12332176cfdSRui Paulo 		 * force the switch.  If we made a mistake we'll not
12432176cfdSRui Paulo 		 * find the AP on the new channel and fall back to a
12532176cfdSRui Paulo 		 * normal scan.
12632176cfdSRui Paulo 		 */
12732176cfdSRui Paulo 		ieee80211_csa_completeswitch(ic);
12832176cfdSRui Paulo 		return;
12932176cfdSRui Paulo 	}
13032176cfdSRui Paulo 	if (++vap->iv_bmiss_count < vap->iv_bmiss_max) {
13132176cfdSRui Paulo 		/*
13232176cfdSRui Paulo 		 * Send a directed probe req before falling back to a
13332176cfdSRui Paulo 		 * scan; if we receive a response ic_bmiss_count will
13432176cfdSRui Paulo 		 * be reset.  Some cards mistakenly report beacon miss
13532176cfdSRui Paulo 		 * so this avoids the expensive scan if the ap is
13632176cfdSRui Paulo 		 * still there.
13732176cfdSRui Paulo 		 */
13832176cfdSRui Paulo 		ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr,
13932176cfdSRui Paulo 			vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid,
14032176cfdSRui Paulo 			vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen);
14132176cfdSRui Paulo 		return;
14232176cfdSRui Paulo 	}
14332176cfdSRui Paulo 	vap->iv_bmiss_count = 0;
14432176cfdSRui Paulo 	vap->iv_stats.is_beacon_miss++;
14532176cfdSRui Paulo 	if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
14632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
14732176cfdSRui Paulo 		struct ieee80211com *ic = vap->iv_ic;
14832176cfdSRui Paulo 
14932176cfdSRui Paulo 		/*
15032176cfdSRui Paulo 		 * If we receive a beacon miss interrupt when using
15132176cfdSRui Paulo 		 * dynamic turbo, attempt to switch modes before
15232176cfdSRui Paulo 		 * reassociating.
15332176cfdSRui Paulo 		 */
15432176cfdSRui Paulo 		if (IEEE80211_ATH_CAP(vap, vap->iv_bss, IEEE80211_NODE_TURBOP))
15532176cfdSRui Paulo 			ieee80211_dturbo_switch(vap,
15632176cfdSRui Paulo 			    ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO);
15732176cfdSRui Paulo #endif
15832176cfdSRui Paulo 		/*
15932176cfdSRui Paulo 		 * Try to reassociate before scanning for a new ap.
16032176cfdSRui Paulo 		 */
16132176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
16232176cfdSRui Paulo 	} else {
16332176cfdSRui Paulo 		/*
16432176cfdSRui Paulo 		 * Somebody else is controlling state changes (e.g.
16532176cfdSRui Paulo 		 * a user-mode app) don't do anything that would
16632176cfdSRui Paulo 		 * confuse them; just drop into scan mode so they'll
16732176cfdSRui Paulo 		 * notified of the state change and given control.
16832176cfdSRui Paulo 		 */
16932176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
17032176cfdSRui Paulo 	}
17132176cfdSRui Paulo }
17232176cfdSRui Paulo 
17332176cfdSRui Paulo /*
17432176cfdSRui Paulo  * Handle deauth with reason.  We retry only for
17532176cfdSRui Paulo  * the cases where we might succeed.  Otherwise
17632176cfdSRui Paulo  * we downgrade the ap and scan.
17732176cfdSRui Paulo  */
17832176cfdSRui Paulo static void
17932176cfdSRui Paulo sta_authretry(struct ieee80211vap *vap, struct ieee80211_node *ni, int reason)
18032176cfdSRui Paulo {
18132176cfdSRui Paulo 	switch (reason) {
18232176cfdSRui Paulo 	case IEEE80211_STATUS_SUCCESS:		/* NB: MLME assoc */
18332176cfdSRui Paulo 	case IEEE80211_STATUS_TIMEOUT:
18432176cfdSRui Paulo 	case IEEE80211_REASON_ASSOC_EXPIRE:
18532176cfdSRui Paulo 	case IEEE80211_REASON_NOT_AUTHED:
18632176cfdSRui Paulo 	case IEEE80211_REASON_NOT_ASSOCED:
18732176cfdSRui Paulo 	case IEEE80211_REASON_ASSOC_LEAVE:
18832176cfdSRui Paulo 	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
18932176cfdSRui Paulo 		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1);
19032176cfdSRui Paulo 		break;
19132176cfdSRui Paulo 	default:
19232176cfdSRui Paulo 		ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr, reason);
19332176cfdSRui Paulo 		if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
19432176cfdSRui Paulo 			ieee80211_check_scan_current(vap);
19532176cfdSRui Paulo 		break;
19632176cfdSRui Paulo 	}
19732176cfdSRui Paulo }
19832176cfdSRui Paulo 
19932176cfdSRui Paulo /*
20032176cfdSRui Paulo  * IEEE80211_M_STA vap state machine handler.
20132176cfdSRui Paulo  * This routine handles the main states in the 802.11 protocol.
20232176cfdSRui Paulo  */
20332176cfdSRui Paulo static int
20432176cfdSRui Paulo sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
20532176cfdSRui Paulo {
20632176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
20732176cfdSRui Paulo 	struct ieee80211_node *ni;
20832176cfdSRui Paulo 	enum ieee80211_state ostate;
20932176cfdSRui Paulo 
21032176cfdSRui Paulo 	IEEE80211_LOCK_ASSERT(ic);
21132176cfdSRui Paulo 
21232176cfdSRui Paulo 	ostate = vap->iv_state;
21332176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
21432176cfdSRui Paulo 	    __func__, ieee80211_state_name[ostate],
21532176cfdSRui Paulo 	    ieee80211_state_name[nstate], arg);
21632176cfdSRui Paulo 	vap->iv_state = nstate;			/* state transition */
21732176cfdSRui Paulo 	callout_stop(&vap->iv_mgtsend);		/* XXX callout_drain */
21832176cfdSRui Paulo 	if (ostate != IEEE80211_S_SCAN)
21932176cfdSRui Paulo 		ieee80211_cancel_scan(vap);	/* background scan */
22032176cfdSRui Paulo 	ni = vap->iv_bss;			/* NB: no reference held */
22132176cfdSRui Paulo 	if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
22232176cfdSRui Paulo 		callout_stop(&vap->iv_swbmiss);
22332176cfdSRui Paulo 	switch (nstate) {
22432176cfdSRui Paulo 	case IEEE80211_S_INIT:
22532176cfdSRui Paulo 		switch (ostate) {
22632176cfdSRui Paulo 		case IEEE80211_S_SLEEP:
22732176cfdSRui Paulo 			/* XXX wakeup */
22832176cfdSRui Paulo 		case IEEE80211_S_RUN:
22932176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
23032176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_DISASSOC,
23132176cfdSRui Paulo 			    IEEE80211_REASON_ASSOC_LEAVE);
23232176cfdSRui Paulo 			ieee80211_sta_leave(ni);
23332176cfdSRui Paulo 			break;
23432176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
23532176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
23632176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_DEAUTH,
23732176cfdSRui Paulo 			    IEEE80211_REASON_AUTH_LEAVE);
23832176cfdSRui Paulo 			break;
23932176cfdSRui Paulo 		case IEEE80211_S_SCAN:
24032176cfdSRui Paulo 			ieee80211_cancel_scan(vap);
24132176cfdSRui Paulo 			break;
24232176cfdSRui Paulo 		default:
24332176cfdSRui Paulo 			goto invalid;
24432176cfdSRui Paulo 		}
24532176cfdSRui Paulo 		if (ostate != IEEE80211_S_INIT) {
24632176cfdSRui Paulo 			/* NB: optimize INIT -> INIT case */
24732176cfdSRui Paulo 			ieee80211_reset_bss(vap);
24832176cfdSRui Paulo 		}
24932176cfdSRui Paulo 		if (vap->iv_auth->ia_detach != NULL)
25032176cfdSRui Paulo 			vap->iv_auth->ia_detach(vap);
25132176cfdSRui Paulo 		break;
25232176cfdSRui Paulo 	case IEEE80211_S_SCAN:
25332176cfdSRui Paulo 		switch (ostate) {
25432176cfdSRui Paulo 		case IEEE80211_S_INIT:
25532176cfdSRui Paulo 			/*
25632176cfdSRui Paulo 			 * Initiate a scan.  We can come here as a result
25732176cfdSRui Paulo 			 * of an IEEE80211_IOC_SCAN_REQ too in which case
25832176cfdSRui Paulo 			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
25932176cfdSRui Paulo 			 * and the scan request parameters will be present
26032176cfdSRui Paulo 			 * in iv_scanreq.  Otherwise we do the default.
26132176cfdSRui Paulo 			 */
26232176cfdSRui Paulo 			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
26332176cfdSRui Paulo 				ieee80211_check_scan(vap,
26432176cfdSRui Paulo 				    vap->iv_scanreq_flags,
26532176cfdSRui Paulo 				    vap->iv_scanreq_duration,
26632176cfdSRui Paulo 				    vap->iv_scanreq_mindwell,
26732176cfdSRui Paulo 				    vap->iv_scanreq_maxdwell,
26832176cfdSRui Paulo 				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
26932176cfdSRui Paulo 				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
27032176cfdSRui Paulo 			} else
27132176cfdSRui Paulo 				ieee80211_check_scan_current(vap);
27232176cfdSRui Paulo 			break;
27332176cfdSRui Paulo 		case IEEE80211_S_SCAN:
27432176cfdSRui Paulo 		case IEEE80211_S_AUTH:
27532176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
27632176cfdSRui Paulo 			/*
27732176cfdSRui Paulo 			 * These can happen either because of a timeout
27832176cfdSRui Paulo 			 * on an assoc/auth response or because of a
27932176cfdSRui Paulo 			 * change in state that requires a reset.  For
28032176cfdSRui Paulo 			 * the former we're called with a non-zero arg
28132176cfdSRui Paulo 			 * that is the cause for the failure; pass this
28232176cfdSRui Paulo 			 * to the scan code so it can update state.
28332176cfdSRui Paulo 			 * Otherwise trigger a new scan unless we're in
28432176cfdSRui Paulo 			 * manual roaming mode in which case an application
28532176cfdSRui Paulo 			 * must issue an explicit scan request.
28632176cfdSRui Paulo 			 */
28732176cfdSRui Paulo 			if (arg != 0)
28832176cfdSRui Paulo 				ieee80211_scan_assoc_fail(vap,
28932176cfdSRui Paulo 					vap->iv_bss->ni_macaddr, arg);
29032176cfdSRui Paulo 			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
29132176cfdSRui Paulo 				ieee80211_check_scan_current(vap);
29232176cfdSRui Paulo 			break;
29332176cfdSRui Paulo 		case IEEE80211_S_RUN:		/* beacon miss */
29432176cfdSRui Paulo 			/*
29532176cfdSRui Paulo 			 * Beacon miss.  Notify user space and if not
29632176cfdSRui Paulo 			 * under control of a user application (roaming
29732176cfdSRui Paulo 			 * manual) kick off a scan to re-connect.
29832176cfdSRui Paulo 			 */
29932176cfdSRui Paulo 			ieee80211_sta_leave(ni);
30032176cfdSRui Paulo 			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
30132176cfdSRui Paulo 				ieee80211_check_scan_current(vap);
30232176cfdSRui Paulo 			break;
30332176cfdSRui Paulo 		default:
30432176cfdSRui Paulo 			goto invalid;
30532176cfdSRui Paulo 		}
30632176cfdSRui Paulo 		break;
30732176cfdSRui Paulo 	case IEEE80211_S_AUTH:
30832176cfdSRui Paulo 		switch (ostate) {
30932176cfdSRui Paulo 		case IEEE80211_S_INIT:
31032176cfdSRui Paulo 		case IEEE80211_S_SCAN:
31132176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
31232176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_AUTH, 1);
31332176cfdSRui Paulo 			break;
31432176cfdSRui Paulo 		case IEEE80211_S_AUTH:
31532176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
31632176cfdSRui Paulo 			switch (arg & 0xff) {
31732176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_AUTH:
31832176cfdSRui Paulo 				/* ??? */
31932176cfdSRui Paulo 				IEEE80211_SEND_MGMT(ni,
32032176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
32132176cfdSRui Paulo 				break;
32232176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
32332176cfdSRui Paulo 				sta_authretry(vap, ni, arg>>8);
32432176cfdSRui Paulo 				break;
32532176cfdSRui Paulo 			}
32632176cfdSRui Paulo 			break;
32732176cfdSRui Paulo 		case IEEE80211_S_RUN:
32832176cfdSRui Paulo 			switch (arg & 0xff) {
32932176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_AUTH:
33032176cfdSRui Paulo 				IEEE80211_SEND_MGMT(ni,
33132176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
33232176cfdSRui Paulo 				vap->iv_state = ostate;	/* stay RUN */
33332176cfdSRui Paulo 				break;
33432176cfdSRui Paulo 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
33532176cfdSRui Paulo 				ieee80211_sta_leave(ni);
33632176cfdSRui Paulo 				if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
33732176cfdSRui Paulo 					/* try to reauth */
33832176cfdSRui Paulo 					IEEE80211_SEND_MGMT(ni,
33932176cfdSRui Paulo 					    IEEE80211_FC0_SUBTYPE_AUTH, 1);
34032176cfdSRui Paulo 				}
34132176cfdSRui Paulo 				break;
34232176cfdSRui Paulo 			}
34332176cfdSRui Paulo 			break;
34432176cfdSRui Paulo 		default:
34532176cfdSRui Paulo 			goto invalid;
34632176cfdSRui Paulo 		}
34732176cfdSRui Paulo 		break;
34832176cfdSRui Paulo 	case IEEE80211_S_ASSOC:
34932176cfdSRui Paulo 		switch (ostate) {
35032176cfdSRui Paulo 		case IEEE80211_S_AUTH:
35132176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
35232176cfdSRui Paulo 			IEEE80211_SEND_MGMT(ni,
35332176cfdSRui Paulo 			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
35432176cfdSRui Paulo 			break;
35532176cfdSRui Paulo 		case IEEE80211_S_SLEEP:		/* cannot happen */
35632176cfdSRui Paulo 		case IEEE80211_S_RUN:
35732176cfdSRui Paulo 			ieee80211_sta_leave(ni);
35832176cfdSRui Paulo 			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
35932176cfdSRui Paulo 				IEEE80211_SEND_MGMT(ni, arg ?
36032176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_REASSOC_REQ :
36132176cfdSRui Paulo 				    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
36232176cfdSRui Paulo 			}
36332176cfdSRui Paulo 			break;
36432176cfdSRui Paulo 		default:
36532176cfdSRui Paulo 			goto invalid;
36632176cfdSRui Paulo 		}
36732176cfdSRui Paulo 		break;
36832176cfdSRui Paulo 	case IEEE80211_S_RUN:
36932176cfdSRui Paulo 		if (vap->iv_flags & IEEE80211_F_WPA) {
37032176cfdSRui Paulo 			/* XXX validate prerequisites */
37132176cfdSRui Paulo 		}
37232176cfdSRui Paulo 		switch (ostate) {
37332176cfdSRui Paulo 		case IEEE80211_S_RUN:
37432176cfdSRui Paulo 		case IEEE80211_S_CSA:
37532176cfdSRui Paulo 			break;
37632176cfdSRui Paulo 		case IEEE80211_S_AUTH:		/* when join is done in fw */
37732176cfdSRui Paulo 		case IEEE80211_S_ASSOC:
37832176cfdSRui Paulo #ifdef IEEE80211_DEBUG
37932176cfdSRui Paulo 			if (ieee80211_msg_debug(vap)) {
380*6168f72eSRui Paulo 				ieee80211_note(vap, "%s with %6D ssid ",
38132176cfdSRui Paulo 				    (vap->iv_opmode == IEEE80211_M_STA ?
38232176cfdSRui Paulo 				    "associated" : "synchronized"),
383*6168f72eSRui Paulo 				    ni->ni_bssid, ":");
38432176cfdSRui Paulo 				ieee80211_print_essid(vap->iv_bss->ni_essid,
38532176cfdSRui Paulo 				    ni->ni_esslen);
38632176cfdSRui Paulo 				/* XXX MCS/HT */
387*6168f72eSRui Paulo 				kprintf(" channel %d start %uMb\n",
38832176cfdSRui Paulo 				    ieee80211_chan2ieee(ic, ic->ic_curchan),
38932176cfdSRui Paulo 				    IEEE80211_RATE2MBS(ni->ni_txrate));
39032176cfdSRui Paulo 			}
39132176cfdSRui Paulo #endif
39232176cfdSRui Paulo 			ieee80211_scan_assoc_success(vap, ni->ni_macaddr);
39332176cfdSRui Paulo 			ieee80211_notify_node_join(ni,
39432176cfdSRui Paulo 			    arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
39532176cfdSRui Paulo 			break;
39632176cfdSRui Paulo 		case IEEE80211_S_SLEEP:
39732176cfdSRui Paulo 			ieee80211_sta_pwrsave(vap, 0);
39832176cfdSRui Paulo 			break;
39932176cfdSRui Paulo 		default:
40032176cfdSRui Paulo 			goto invalid;
40132176cfdSRui Paulo 		}
40232176cfdSRui Paulo 		ieee80211_sync_curchan(ic);
40332176cfdSRui Paulo 		if (ostate != IEEE80211_S_RUN &&
40432176cfdSRui Paulo 		    (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
40532176cfdSRui Paulo 			/*
40632176cfdSRui Paulo 			 * Start s/w beacon miss timer for devices w/o
40732176cfdSRui Paulo 			 * hardware support.  We fudge a bit here since
40832176cfdSRui Paulo 			 * we're doing this in software.
40932176cfdSRui Paulo 			 */
41032176cfdSRui Paulo 			vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
41132176cfdSRui Paulo 				2 * vap->iv_bmissthreshold * ni->ni_intval);
41232176cfdSRui Paulo 			vap->iv_swbmiss_count = 0;
41332176cfdSRui Paulo 			callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
41432176cfdSRui Paulo 				ieee80211_swbmiss, vap);
41532176cfdSRui Paulo 		}
41632176cfdSRui Paulo 		/*
41732176cfdSRui Paulo 		 * When 802.1x is not in use mark the port authorized
41832176cfdSRui Paulo 		 * at this point so traffic can flow.
41932176cfdSRui Paulo 		 */
42032176cfdSRui Paulo 		if (ni->ni_authmode != IEEE80211_AUTH_8021X)
42132176cfdSRui Paulo 			ieee80211_node_authorize(ni);
42232176cfdSRui Paulo 		/*
42332176cfdSRui Paulo 		 * Fake association when joining an existing bss.
42432176cfdSRui Paulo 		 */
42532176cfdSRui Paulo 		if (ic->ic_newassoc != NULL)
42632176cfdSRui Paulo 			ic->ic_newassoc(vap->iv_bss, ostate != IEEE80211_S_RUN);
42732176cfdSRui Paulo 		break;
42832176cfdSRui Paulo 	case IEEE80211_S_CSA:
42932176cfdSRui Paulo 		if (ostate != IEEE80211_S_RUN)
43032176cfdSRui Paulo 			goto invalid;
43132176cfdSRui Paulo 		break;
43232176cfdSRui Paulo 	case IEEE80211_S_SLEEP:
43332176cfdSRui Paulo 		ieee80211_sta_pwrsave(vap, 1);
43432176cfdSRui Paulo 		break;
43532176cfdSRui Paulo 	default:
43632176cfdSRui Paulo 	invalid:
43732176cfdSRui Paulo 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
43832176cfdSRui Paulo 		    "%s: unexpected state transition %s -> %s\n", __func__,
43932176cfdSRui Paulo 		    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
44032176cfdSRui Paulo 		break;
44132176cfdSRui Paulo 	}
44232176cfdSRui Paulo 	return 0;
44332176cfdSRui Paulo }
44432176cfdSRui Paulo 
44532176cfdSRui Paulo /*
44632176cfdSRui Paulo  * Return non-zero if the frame is an echo of a multicast
44732176cfdSRui Paulo  * frame sent by ourself.  The dir is known to be DSTODS.
44832176cfdSRui Paulo  */
44932176cfdSRui Paulo static __inline int
45032176cfdSRui Paulo isdstods_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
45132176cfdSRui Paulo {
45232176cfdSRui Paulo #define	QWH4(wh)	((const struct ieee80211_qosframe_addr4 *)wh)
45332176cfdSRui Paulo #define	WH4(wh)		((const struct ieee80211_frame_addr4 *)wh)
45432176cfdSRui Paulo 	const uint8_t *sa;
45532176cfdSRui Paulo 
45632176cfdSRui Paulo 	KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode"));
45732176cfdSRui Paulo 
45832176cfdSRui Paulo 	if (!IEEE80211_IS_MULTICAST(wh->i_addr3))
45932176cfdSRui Paulo 		return 0;
46032176cfdSRui Paulo 	sa = IEEE80211_QOS_HAS_SEQ(wh) ? QWH4(wh)->i_addr4 : WH4(wh)->i_addr4;
46132176cfdSRui Paulo 	return IEEE80211_ADDR_EQ(sa, vap->iv_myaddr);
46232176cfdSRui Paulo #undef WH4
46332176cfdSRui Paulo #undef QWH4
46432176cfdSRui Paulo }
46532176cfdSRui Paulo 
46632176cfdSRui Paulo /*
46732176cfdSRui Paulo  * Return non-zero if the frame is an echo of a multicast
46832176cfdSRui Paulo  * frame sent by ourself.  The dir is known to be FROMDS.
46932176cfdSRui Paulo  */
47032176cfdSRui Paulo static __inline int
47132176cfdSRui Paulo isfromds_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
47232176cfdSRui Paulo {
47332176cfdSRui Paulo 	KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode"));
47432176cfdSRui Paulo 
47532176cfdSRui Paulo 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
47632176cfdSRui Paulo 		return 0;
47732176cfdSRui Paulo 	return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
47832176cfdSRui Paulo }
47932176cfdSRui Paulo 
48032176cfdSRui Paulo /*
48132176cfdSRui Paulo  * Decide if a received management frame should be
48232176cfdSRui Paulo  * printed when debugging is enabled.  This filters some
48332176cfdSRui Paulo  * of the less interesting frames that come frequently
48432176cfdSRui Paulo  * (e.g. beacons).
48532176cfdSRui Paulo  */
48632176cfdSRui Paulo static __inline int
48732176cfdSRui Paulo doprint(struct ieee80211vap *vap, int subtype)
48832176cfdSRui Paulo {
48932176cfdSRui Paulo 	switch (subtype) {
49032176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_BEACON:
49132176cfdSRui Paulo 		return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN);
49232176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
49332176cfdSRui Paulo 		return 0;
49432176cfdSRui Paulo 	}
49532176cfdSRui Paulo 	return 1;
49632176cfdSRui Paulo }
49732176cfdSRui Paulo 
49832176cfdSRui Paulo /*
49932176cfdSRui Paulo  * Process a received frame.  The node associated with the sender
50032176cfdSRui Paulo  * should be supplied.  If nothing was found in the node table then
50132176cfdSRui Paulo  * the caller is assumed to supply a reference to iv_bss instead.
50232176cfdSRui Paulo  * The RSSI and a timestamp are also supplied.  The RSSI data is used
50332176cfdSRui Paulo  * during AP scanning to select a AP to associate with; it can have
50432176cfdSRui Paulo  * any units so long as values have consistent units and higher values
50532176cfdSRui Paulo  * mean ``better signal''.  The receive timestamp is currently not used
50632176cfdSRui Paulo  * by the 802.11 layer.
50732176cfdSRui Paulo  */
50832176cfdSRui Paulo static int
50932176cfdSRui Paulo sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
51032176cfdSRui Paulo {
51132176cfdSRui Paulo #define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
51232176cfdSRui Paulo #define	HAS_SEQ(type)	((type & 0x4) == 0)
51332176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
51432176cfdSRui Paulo 	struct ieee80211com *ic = ni->ni_ic;
51532176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
51632176cfdSRui Paulo 	struct ieee80211_frame *wh;
51732176cfdSRui Paulo 	struct ieee80211_key *key;
51832176cfdSRui Paulo 	struct ether_header *eh;
51932176cfdSRui Paulo 	int hdrspace, need_tap = 1;	/* mbuf need to be tapped. */
52032176cfdSRui Paulo 	uint8_t dir, type, subtype, qos;
52132176cfdSRui Paulo 	uint8_t *bssid;
52232176cfdSRui Paulo 	uint16_t rxseq;
52332176cfdSRui Paulo 
52432176cfdSRui Paulo 	if (m->m_flags & M_AMPDU_MPDU) {
52532176cfdSRui Paulo 		/*
52632176cfdSRui Paulo 		 * Fastpath for A-MPDU reorder q resubmission.  Frames
52732176cfdSRui Paulo 		 * w/ M_AMPDU_MPDU marked have already passed through
52832176cfdSRui Paulo 		 * here but were received out of order and been held on
52932176cfdSRui Paulo 		 * the reorder queue.  When resubmitted they are marked
53032176cfdSRui Paulo 		 * with the M_AMPDU_MPDU flag and we can bypass most of
53132176cfdSRui Paulo 		 * the normal processing.
53232176cfdSRui Paulo 		 */
53332176cfdSRui Paulo 		wh = mtod(m, struct ieee80211_frame *);
53432176cfdSRui Paulo 		type = IEEE80211_FC0_TYPE_DATA;
53532176cfdSRui Paulo 		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
53632176cfdSRui Paulo 		subtype = IEEE80211_FC0_SUBTYPE_QOS;
53732176cfdSRui Paulo 		hdrspace = ieee80211_hdrspace(ic, wh);	/* XXX optimize? */
53832176cfdSRui Paulo 		goto resubmit_ampdu;
53932176cfdSRui Paulo 	}
54032176cfdSRui Paulo 
54132176cfdSRui Paulo 	KASSERT(ni != NULL, ("null node"));
54232176cfdSRui Paulo 	ni->ni_inact = ni->ni_inact_reload;
54332176cfdSRui Paulo 
54432176cfdSRui Paulo 	type = -1;			/* undefined */
54532176cfdSRui Paulo 
54632176cfdSRui Paulo 	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
54732176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
54832176cfdSRui Paulo 		    ni->ni_macaddr, NULL,
54932176cfdSRui Paulo 		    "too short (1): len %u", m->m_pkthdr.len);
55032176cfdSRui Paulo 		vap->iv_stats.is_rx_tooshort++;
55132176cfdSRui Paulo 		goto out;
55232176cfdSRui Paulo 	}
55332176cfdSRui Paulo 	/*
55432176cfdSRui Paulo 	 * Bit of a cheat here, we use a pointer for a 3-address
55532176cfdSRui Paulo 	 * frame format but don't reference fields past outside
55632176cfdSRui Paulo 	 * ieee80211_frame_min w/o first validating the data is
55732176cfdSRui Paulo 	 * present.
55832176cfdSRui Paulo 	 */
55932176cfdSRui Paulo 	wh = mtod(m, struct ieee80211_frame *);
56032176cfdSRui Paulo 
56132176cfdSRui Paulo 	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
56232176cfdSRui Paulo 	    IEEE80211_FC0_VERSION_0) {
56332176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
56432176cfdSRui Paulo 		    ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x",
56532176cfdSRui Paulo 		    wh->i_fc[0], wh->i_fc[1]);
56632176cfdSRui Paulo 		vap->iv_stats.is_rx_badversion++;
56732176cfdSRui Paulo 		goto err;
56832176cfdSRui Paulo 	}
56932176cfdSRui Paulo 
57032176cfdSRui Paulo 	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
57132176cfdSRui Paulo 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
57232176cfdSRui Paulo 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
57332176cfdSRui Paulo 	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
57432176cfdSRui Paulo 		bssid = wh->i_addr2;
57532176cfdSRui Paulo 		if (!IEEE80211_ADDR_EQ(bssid, ni->ni_bssid)) {
57632176cfdSRui Paulo 			/* not interested in */
57732176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
57832176cfdSRui Paulo 			    bssid, NULL, "%s", "not to bss");
57932176cfdSRui Paulo 			vap->iv_stats.is_rx_wrongbss++;
58032176cfdSRui Paulo 			goto out;
58132176cfdSRui Paulo 		}
58232176cfdSRui Paulo 		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
58332176cfdSRui Paulo 		ni->ni_noise = nf;
58432176cfdSRui Paulo 		if (HAS_SEQ(type)) {
58532176cfdSRui Paulo 			uint8_t tid = ieee80211_gettid(wh);
58632176cfdSRui Paulo 			if (IEEE80211_QOS_HAS_SEQ(wh) &&
58732176cfdSRui Paulo 			    TID_TO_WME_AC(tid) >= WME_AC_VI)
58832176cfdSRui Paulo 				ic->ic_wme.wme_hipri_traffic++;
58932176cfdSRui Paulo 			rxseq = le16toh(*(uint16_t *)wh->i_seq);
59032176cfdSRui Paulo 			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
59132176cfdSRui Paulo 			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
59232176cfdSRui Paulo 			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
59332176cfdSRui Paulo 				/* duplicate, discard */
59432176cfdSRui Paulo 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
59532176cfdSRui Paulo 				    bssid, "duplicate",
59632176cfdSRui Paulo 				    "seqno <%u,%u> fragno <%u,%u> tid %u",
59732176cfdSRui Paulo 				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
59832176cfdSRui Paulo 				    ni->ni_rxseqs[tid] >>
59932176cfdSRui Paulo 					IEEE80211_SEQ_SEQ_SHIFT,
60032176cfdSRui Paulo 				    rxseq & IEEE80211_SEQ_FRAG_MASK,
60132176cfdSRui Paulo 				    ni->ni_rxseqs[tid] &
60232176cfdSRui Paulo 					IEEE80211_SEQ_FRAG_MASK,
60332176cfdSRui Paulo 				    tid);
60432176cfdSRui Paulo 				vap->iv_stats.is_rx_dup++;
60532176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_dup);
60632176cfdSRui Paulo 				goto out;
60732176cfdSRui Paulo 			}
60832176cfdSRui Paulo 			ni->ni_rxseqs[tid] = rxseq;
60932176cfdSRui Paulo 		}
61032176cfdSRui Paulo 	}
61132176cfdSRui Paulo 
61232176cfdSRui Paulo 	switch (type) {
61332176cfdSRui Paulo 	case IEEE80211_FC0_TYPE_DATA:
61432176cfdSRui Paulo 		hdrspace = ieee80211_hdrspace(ic, wh);
61532176cfdSRui Paulo 		if (m->m_len < hdrspace &&
61632176cfdSRui Paulo 		    (m = m_pullup(m, hdrspace)) == NULL) {
61732176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
61832176cfdSRui Paulo 			    ni->ni_macaddr, NULL,
61932176cfdSRui Paulo 			    "data too short: expecting %u", hdrspace);
62032176cfdSRui Paulo 			vap->iv_stats.is_rx_tooshort++;
62132176cfdSRui Paulo 			goto out;		/* XXX */
62232176cfdSRui Paulo 		}
62332176cfdSRui Paulo 		/*
62432176cfdSRui Paulo 		 * Handle A-MPDU re-ordering.  If the frame is to be
62532176cfdSRui Paulo 		 * processed directly then ieee80211_ampdu_reorder
62632176cfdSRui Paulo 		 * will return 0; otherwise it has consumed the mbuf
62732176cfdSRui Paulo 		 * and we should do nothing more with it.
62832176cfdSRui Paulo 		 */
62932176cfdSRui Paulo 		if ((m->m_flags & M_AMPDU) &&
63032176cfdSRui Paulo 		    (dir == IEEE80211_FC1_DIR_FROMDS ||
63132176cfdSRui Paulo 		     dir == IEEE80211_FC1_DIR_DSTODS) &&
63232176cfdSRui Paulo 		    ieee80211_ampdu_reorder(ni, m) != 0) {
63332176cfdSRui Paulo 			m = NULL;
63432176cfdSRui Paulo 			goto out;
63532176cfdSRui Paulo 		}
63632176cfdSRui Paulo 	resubmit_ampdu:
63732176cfdSRui Paulo 		if (dir == IEEE80211_FC1_DIR_FROMDS) {
63832176cfdSRui Paulo 			if ((ifp->if_flags & IFF_SIMPLEX) &&
63932176cfdSRui Paulo 			    isfromds_mcastecho(vap, wh)) {
64032176cfdSRui Paulo 				/*
64132176cfdSRui Paulo 				 * In IEEE802.11 network, multicast
64232176cfdSRui Paulo 				 * packets sent from "me" are broadcast
64332176cfdSRui Paulo 				 * from the AP; silently discard for
64432176cfdSRui Paulo 				 * SIMPLEX interface.
64532176cfdSRui Paulo 				 */
64632176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
64732176cfdSRui Paulo 				    wh, "data", "%s", "multicast echo");
64832176cfdSRui Paulo 				vap->iv_stats.is_rx_mcastecho++;
64932176cfdSRui Paulo 				goto out;
65032176cfdSRui Paulo 			}
65132176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_DWDS) &&
65232176cfdSRui Paulo 			    IEEE80211_IS_MULTICAST(wh->i_addr1)) {
65332176cfdSRui Paulo 				/*
65432176cfdSRui Paulo 				 * DWDS sta's must drop 3-address mcast frames
65532176cfdSRui Paulo 				 * as they will be sent separately as a 4-addr
65632176cfdSRui Paulo 				 * frame.  Accepting the 3-addr frame will
65732176cfdSRui Paulo 				 * confuse the bridge into thinking the sending
65832176cfdSRui Paulo 				 * sta is located at the end of WDS link.
65932176cfdSRui Paulo 				 */
66032176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
66132176cfdSRui Paulo 				    "3-address data", "%s", "DWDS enabled");
66232176cfdSRui Paulo 				vap->iv_stats.is_rx_mcastecho++;
66332176cfdSRui Paulo 				goto out;
66432176cfdSRui Paulo 			}
66532176cfdSRui Paulo 		} else if (dir == IEEE80211_FC1_DIR_DSTODS) {
66632176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_DWDS) == 0) {
66732176cfdSRui Paulo 				IEEE80211_DISCARD(vap,
66832176cfdSRui Paulo 				    IEEE80211_MSG_INPUT, wh, "4-address data",
66932176cfdSRui Paulo 				    "%s", "DWDS not enabled");
67032176cfdSRui Paulo 				vap->iv_stats.is_rx_wrongdir++;
67132176cfdSRui Paulo 				goto out;
67232176cfdSRui Paulo 			}
67332176cfdSRui Paulo 			if ((ifp->if_flags & IFF_SIMPLEX) &&
67432176cfdSRui Paulo 			    isdstods_mcastecho(vap, wh)) {
67532176cfdSRui Paulo 				/*
67632176cfdSRui Paulo 				 * In IEEE802.11 network, multicast
67732176cfdSRui Paulo 				 * packets sent from "me" are broadcast
67832176cfdSRui Paulo 				 * from the AP; silently discard for
67932176cfdSRui Paulo 				 * SIMPLEX interface.
68032176cfdSRui Paulo 				 */
68132176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
68232176cfdSRui Paulo 				    "4-address data", "%s", "multicast echo");
68332176cfdSRui Paulo 				vap->iv_stats.is_rx_mcastecho++;
68432176cfdSRui Paulo 				goto out;
68532176cfdSRui Paulo 			}
68632176cfdSRui Paulo 		} else {
68732176cfdSRui Paulo 			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh,
68832176cfdSRui Paulo 			    "data", "incorrect dir 0x%x", dir);
68932176cfdSRui Paulo 			vap->iv_stats.is_rx_wrongdir++;
69032176cfdSRui Paulo 			goto out;
69132176cfdSRui Paulo 		}
69232176cfdSRui Paulo 
69332176cfdSRui Paulo 		/*
69432176cfdSRui Paulo 		 * Handle privacy requirements.  Note that we
69532176cfdSRui Paulo 		 * must not be preempted from here until after
69632176cfdSRui Paulo 		 * we (potentially) call ieee80211_crypto_demic;
69732176cfdSRui Paulo 		 * otherwise we may violate assumptions in the
69832176cfdSRui Paulo 		 * crypto cipher modules used to do delayed update
69932176cfdSRui Paulo 		 * of replay sequence numbers.
70032176cfdSRui Paulo 		 */
70132176cfdSRui Paulo 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
70232176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
70332176cfdSRui Paulo 				/*
70432176cfdSRui Paulo 				 * Discard encrypted frames when privacy is off.
70532176cfdSRui Paulo 				 */
70632176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
70732176cfdSRui Paulo 				    wh, "WEP", "%s", "PRIVACY off");
70832176cfdSRui Paulo 				vap->iv_stats.is_rx_noprivacy++;
70932176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_noprivacy);
71032176cfdSRui Paulo 				goto out;
71132176cfdSRui Paulo 			}
71232176cfdSRui Paulo 			key = ieee80211_crypto_decap(ni, m, hdrspace);
71332176cfdSRui Paulo 			if (key == NULL) {
71432176cfdSRui Paulo 				/* NB: stats+msgs handled in crypto_decap */
71532176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_wepfail);
71632176cfdSRui Paulo 				goto out;
71732176cfdSRui Paulo 			}
71832176cfdSRui Paulo 			wh = mtod(m, struct ieee80211_frame *);
71932176cfdSRui Paulo 			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
72032176cfdSRui Paulo 		} else {
72132176cfdSRui Paulo 			/* XXX M_WEP and IEEE80211_F_PRIVACY */
72232176cfdSRui Paulo 			key = NULL;
72332176cfdSRui Paulo 		}
72432176cfdSRui Paulo 
72532176cfdSRui Paulo 		/*
72632176cfdSRui Paulo 		 * Save QoS bits for use below--before we strip the header.
72732176cfdSRui Paulo 		 */
72832176cfdSRui Paulo 		if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
72932176cfdSRui Paulo 			qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
73032176cfdSRui Paulo 			    ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
73132176cfdSRui Paulo 			    ((struct ieee80211_qosframe *)wh)->i_qos[0];
73232176cfdSRui Paulo 		} else
73332176cfdSRui Paulo 			qos = 0;
73432176cfdSRui Paulo 
73532176cfdSRui Paulo 		/*
73632176cfdSRui Paulo 		 * Next up, any fragmentation.
73732176cfdSRui Paulo 		 */
73832176cfdSRui Paulo 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
73932176cfdSRui Paulo 			m = ieee80211_defrag(ni, m, hdrspace);
74032176cfdSRui Paulo 			if (m == NULL) {
74132176cfdSRui Paulo 				/* Fragment dropped or frame not complete yet */
74232176cfdSRui Paulo 				goto out;
74332176cfdSRui Paulo 			}
74432176cfdSRui Paulo 		}
74532176cfdSRui Paulo 		wh = NULL;		/* no longer valid, catch any uses */
74632176cfdSRui Paulo 
74732176cfdSRui Paulo 		/*
74832176cfdSRui Paulo 		 * Next strip any MSDU crypto bits.
74932176cfdSRui Paulo 		 */
75032176cfdSRui Paulo 		if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) {
75132176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
75232176cfdSRui Paulo 			    ni->ni_macaddr, "data", "%s", "demic error");
75332176cfdSRui Paulo 			vap->iv_stats.is_rx_demicfail++;
75432176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_demicfail);
75532176cfdSRui Paulo 			goto out;
75632176cfdSRui Paulo 		}
75732176cfdSRui Paulo 
75832176cfdSRui Paulo 		/* copy to listener after decrypt */
75932176cfdSRui Paulo 		if (ieee80211_radiotap_active_vap(vap))
76032176cfdSRui Paulo 			ieee80211_radiotap_rx(vap, m);
76132176cfdSRui Paulo 		need_tap = 0;
76232176cfdSRui Paulo 
76332176cfdSRui Paulo 		/*
76432176cfdSRui Paulo 		 * Finally, strip the 802.11 header.
76532176cfdSRui Paulo 		 */
76632176cfdSRui Paulo 		m = ieee80211_decap(vap, m, hdrspace);
76732176cfdSRui Paulo 		if (m == NULL) {
76832176cfdSRui Paulo 			/* XXX mask bit to check for both */
76932176cfdSRui Paulo 			/* don't count Null data frames as errors */
77032176cfdSRui Paulo 			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA ||
77132176cfdSRui Paulo 			    subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)
77232176cfdSRui Paulo 				goto out;
77332176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
77432176cfdSRui Paulo 			    ni->ni_macaddr, "data", "%s", "decap error");
77532176cfdSRui Paulo 			vap->iv_stats.is_rx_decap++;
77632176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_decap);
77732176cfdSRui Paulo 			goto err;
77832176cfdSRui Paulo 		}
77932176cfdSRui Paulo 		eh = mtod(m, struct ether_header *);
78032176cfdSRui Paulo 		if (!ieee80211_node_is_authorized(ni)) {
78132176cfdSRui Paulo 			/*
78232176cfdSRui Paulo 			 * Deny any non-PAE frames received prior to
78332176cfdSRui Paulo 			 * authorization.  For open/shared-key
78432176cfdSRui Paulo 			 * authentication the port is mark authorized
78532176cfdSRui Paulo 			 * after authentication completes.  For 802.1x
78632176cfdSRui Paulo 			 * the port is not marked authorized by the
78732176cfdSRui Paulo 			 * authenticator until the handshake has completed.
78832176cfdSRui Paulo 			 */
78932176cfdSRui Paulo 			if (eh->ether_type != htons(ETHERTYPE_PAE)) {
79032176cfdSRui Paulo 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
79132176cfdSRui Paulo 				    eh->ether_shost, "data",
79232176cfdSRui Paulo 				    "unauthorized port: ether type 0x%x len %u",
79332176cfdSRui Paulo 				    eh->ether_type, m->m_pkthdr.len);
79432176cfdSRui Paulo 				vap->iv_stats.is_rx_unauth++;
79532176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_unauth);
79632176cfdSRui Paulo 				goto err;
79732176cfdSRui Paulo 			}
79832176cfdSRui Paulo 		} else {
79932176cfdSRui Paulo 			/*
80032176cfdSRui Paulo 			 * When denying unencrypted frames, discard
80132176cfdSRui Paulo 			 * any non-PAE frames received without encryption.
80232176cfdSRui Paulo 			 */
80332176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
80432176cfdSRui Paulo 			    (key == NULL && (m->m_flags & M_WEP) == 0) &&
80532176cfdSRui Paulo 			    eh->ether_type != htons(ETHERTYPE_PAE)) {
80632176cfdSRui Paulo 				/*
80732176cfdSRui Paulo 				 * Drop unencrypted frames.
80832176cfdSRui Paulo 				 */
80932176cfdSRui Paulo 				vap->iv_stats.is_rx_unencrypted++;
81032176cfdSRui Paulo 				IEEE80211_NODE_STAT(ni, rx_unencrypted);
81132176cfdSRui Paulo 				goto out;
81232176cfdSRui Paulo 			}
81332176cfdSRui Paulo 		}
81432176cfdSRui Paulo 		/* XXX require HT? */
81532176cfdSRui Paulo 		if (qos & IEEE80211_QOS_AMSDU) {
81632176cfdSRui Paulo 			m = ieee80211_decap_amsdu(ni, m);
81732176cfdSRui Paulo 			if (m == NULL)
81832176cfdSRui Paulo 				return IEEE80211_FC0_TYPE_DATA;
81932176cfdSRui Paulo 		} else {
82032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
82132176cfdSRui Paulo 			m = ieee80211_decap_fastframe(vap, ni, m);
82232176cfdSRui Paulo 			if (m == NULL)
82332176cfdSRui Paulo 				return IEEE80211_FC0_TYPE_DATA;
82432176cfdSRui Paulo #endif
82532176cfdSRui Paulo 		}
82632176cfdSRui Paulo 		ieee80211_deliver_data(vap, ni, m);
82732176cfdSRui Paulo 		return IEEE80211_FC0_TYPE_DATA;
82832176cfdSRui Paulo 
82932176cfdSRui Paulo 	case IEEE80211_FC0_TYPE_MGT:
83032176cfdSRui Paulo 		vap->iv_stats.is_rx_mgmt++;
83132176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_mgmt);
83232176cfdSRui Paulo 		if (dir != IEEE80211_FC1_DIR_NODS) {
83332176cfdSRui Paulo 			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
83432176cfdSRui Paulo 			    wh, "data", "incorrect dir 0x%x", dir);
83532176cfdSRui Paulo 			vap->iv_stats.is_rx_wrongdir++;
83632176cfdSRui Paulo 			goto err;
83732176cfdSRui Paulo 		}
83832176cfdSRui Paulo 		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
83932176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
84032176cfdSRui Paulo 			    ni->ni_macaddr, "mgt", "too short: len %u",
84132176cfdSRui Paulo 			    m->m_pkthdr.len);
84232176cfdSRui Paulo 			vap->iv_stats.is_rx_tooshort++;
84332176cfdSRui Paulo 			goto out;
84432176cfdSRui Paulo 		}
84532176cfdSRui Paulo #ifdef IEEE80211_DEBUG
84632176cfdSRui Paulo 		if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) ||
84732176cfdSRui Paulo 		    ieee80211_msg_dumppkts(vap)) {
848*6168f72eSRui Paulo 			if_printf(ifp, "received %s from %6D rssi %d\n",
84932176cfdSRui Paulo 			    ieee80211_mgt_subtype_name[subtype >>
85032176cfdSRui Paulo 				IEEE80211_FC0_SUBTYPE_SHIFT],
851*6168f72eSRui Paulo 			    wh->i_addr2, ":", rssi);
85232176cfdSRui Paulo 		}
85332176cfdSRui Paulo #endif
85432176cfdSRui Paulo 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
85532176cfdSRui Paulo 			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
85632176cfdSRui Paulo 				/*
85732176cfdSRui Paulo 				 * Only shared key auth frames with a challenge
85832176cfdSRui Paulo 				 * should be encrypted, discard all others.
85932176cfdSRui Paulo 				 */
86032176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
86132176cfdSRui Paulo 				    wh, ieee80211_mgt_subtype_name[subtype >>
86232176cfdSRui Paulo 					IEEE80211_FC0_SUBTYPE_SHIFT],
86332176cfdSRui Paulo 				    "%s", "WEP set but not permitted");
86432176cfdSRui Paulo 				vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
86532176cfdSRui Paulo 				goto out;
86632176cfdSRui Paulo 			}
86732176cfdSRui Paulo 			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
86832176cfdSRui Paulo 				/*
86932176cfdSRui Paulo 				 * Discard encrypted frames when privacy is off.
87032176cfdSRui Paulo 				 */
87132176cfdSRui Paulo 				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
87232176cfdSRui Paulo 				    wh, "mgt", "%s", "WEP set but PRIVACY off");
87332176cfdSRui Paulo 				vap->iv_stats.is_rx_noprivacy++;
87432176cfdSRui Paulo 				goto out;
87532176cfdSRui Paulo 			}
87632176cfdSRui Paulo 			hdrspace = ieee80211_hdrspace(ic, wh);
87732176cfdSRui Paulo 			key = ieee80211_crypto_decap(ni, m, hdrspace);
87832176cfdSRui Paulo 			if (key == NULL) {
87932176cfdSRui Paulo 				/* NB: stats+msgs handled in crypto_decap */
88032176cfdSRui Paulo 				goto out;
88132176cfdSRui Paulo 			}
88232176cfdSRui Paulo 			wh = mtod(m, struct ieee80211_frame *);
88332176cfdSRui Paulo 			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
88432176cfdSRui Paulo 		}
88532176cfdSRui Paulo 		vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
88632176cfdSRui Paulo 		goto out;
88732176cfdSRui Paulo 
88832176cfdSRui Paulo 	case IEEE80211_FC0_TYPE_CTL:
88932176cfdSRui Paulo 		vap->iv_stats.is_rx_ctl++;
89032176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_ctrl);
89132176cfdSRui Paulo 		vap->iv_recv_ctl(ni, m, subtype);
89232176cfdSRui Paulo 		goto out;
89332176cfdSRui Paulo 
89432176cfdSRui Paulo 	default:
89532176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
89632176cfdSRui Paulo 		    wh, NULL, "bad frame type 0x%x", type);
89732176cfdSRui Paulo 		/* should not come here */
89832176cfdSRui Paulo 		break;
89932176cfdSRui Paulo 	}
90032176cfdSRui Paulo err:
90132176cfdSRui Paulo 	ifp->if_ierrors++;
90232176cfdSRui Paulo out:
90332176cfdSRui Paulo 	if (m != NULL) {
90432176cfdSRui Paulo 		if (need_tap && ieee80211_radiotap_active_vap(vap))
90532176cfdSRui Paulo 			ieee80211_radiotap_rx(vap, m);
90632176cfdSRui Paulo 		m_freem(m);
90732176cfdSRui Paulo 	}
90832176cfdSRui Paulo 	return type;
90932176cfdSRui Paulo #undef SEQ_LEQ
91032176cfdSRui Paulo }
91132176cfdSRui Paulo 
91232176cfdSRui Paulo static void
91332176cfdSRui Paulo sta_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
91432176cfdSRui Paulo     int rssi, int nf, uint16_t seq, uint16_t status)
91532176cfdSRui Paulo {
91632176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
91732176cfdSRui Paulo 
91832176cfdSRui Paulo 	if (ni->ni_authmode == IEEE80211_AUTH_SHARED) {
91932176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
92032176cfdSRui Paulo 		    ni->ni_macaddr, "open auth",
92132176cfdSRui Paulo 		    "bad sta auth mode %u", ni->ni_authmode);
92232176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;	/* XXX */
92332176cfdSRui Paulo 		return;
92432176cfdSRui Paulo 	}
92532176cfdSRui Paulo 	if (vap->iv_state != IEEE80211_S_AUTH ||
92632176cfdSRui Paulo 	    seq != IEEE80211_AUTH_OPEN_RESPONSE) {
92732176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;
92832176cfdSRui Paulo 		return;
92932176cfdSRui Paulo 	}
93032176cfdSRui Paulo 	if (status != 0) {
93132176cfdSRui Paulo 		IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
93232176cfdSRui Paulo 		    ni, "open auth failed (reason %d)", status);
93332176cfdSRui Paulo 		vap->iv_stats.is_rx_auth_fail++;
93432176cfdSRui Paulo 		vap->iv_stats.is_rx_authfail_code = status;
93532176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_SCAN,
93632176cfdSRui Paulo 		    IEEE80211_SCAN_FAIL_STATUS);
93732176cfdSRui Paulo 	} else
93832176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
93932176cfdSRui Paulo }
94032176cfdSRui Paulo 
94132176cfdSRui Paulo static void
94232176cfdSRui Paulo sta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
94332176cfdSRui Paulo     uint8_t *frm, uint8_t *efrm, int rssi, int nf,
94432176cfdSRui Paulo     uint16_t seq, uint16_t status)
94532176cfdSRui Paulo {
94632176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
94732176cfdSRui Paulo 	uint8_t *challenge;
94832176cfdSRui Paulo 	int estatus;
94932176cfdSRui Paulo 
95032176cfdSRui Paulo 	/*
95132176cfdSRui Paulo 	 * NB: this can happen as we allow pre-shared key
95232176cfdSRui Paulo 	 * authentication to be enabled w/o wep being turned
95332176cfdSRui Paulo 	 * on so that configuration of these can be done
95432176cfdSRui Paulo 	 * in any order.  It may be better to enforce the
95532176cfdSRui Paulo 	 * ordering in which case this check would just be
95632176cfdSRui Paulo 	 * for sanity/consistency.
95732176cfdSRui Paulo 	 */
95832176cfdSRui Paulo 	if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
95932176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
96032176cfdSRui Paulo 		    ni->ni_macaddr, "shared key auth",
96132176cfdSRui Paulo 		    "%s", " PRIVACY is disabled");
96232176cfdSRui Paulo 		estatus = IEEE80211_STATUS_ALG;
96332176cfdSRui Paulo 		goto bad;
96432176cfdSRui Paulo 	}
96532176cfdSRui Paulo 	/*
96632176cfdSRui Paulo 	 * Pre-shared key authentication is evil; accept
96732176cfdSRui Paulo 	 * it only if explicitly configured (it is supported
96832176cfdSRui Paulo 	 * mainly for compatibility with clients like OS X).
96932176cfdSRui Paulo 	 */
97032176cfdSRui Paulo 	if (ni->ni_authmode != IEEE80211_AUTH_AUTO &&
97132176cfdSRui Paulo 	    ni->ni_authmode != IEEE80211_AUTH_SHARED) {
97232176cfdSRui Paulo 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
97332176cfdSRui Paulo 		    ni->ni_macaddr, "shared key auth",
97432176cfdSRui Paulo 		    "bad sta auth mode %u", ni->ni_authmode);
97532176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;	/* XXX maybe a unique error? */
97632176cfdSRui Paulo 		estatus = IEEE80211_STATUS_ALG;
97732176cfdSRui Paulo 		goto bad;
97832176cfdSRui Paulo 	}
97932176cfdSRui Paulo 
98032176cfdSRui Paulo 	challenge = NULL;
98132176cfdSRui Paulo 	if (frm + 1 < efrm) {
98232176cfdSRui Paulo 		if ((frm[1] + 2) > (efrm - frm)) {
98332176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
98432176cfdSRui Paulo 			    ni->ni_macaddr, "shared key auth",
98532176cfdSRui Paulo 			    "ie %d/%d too long",
98632176cfdSRui Paulo 			    frm[0], (frm[1] + 2) - (efrm - frm));
98732176cfdSRui Paulo 			vap->iv_stats.is_rx_bad_auth++;
98832176cfdSRui Paulo 			estatus = IEEE80211_STATUS_CHALLENGE;
98932176cfdSRui Paulo 			goto bad;
99032176cfdSRui Paulo 		}
99132176cfdSRui Paulo 		if (*frm == IEEE80211_ELEMID_CHALLENGE)
99232176cfdSRui Paulo 			challenge = frm;
99332176cfdSRui Paulo 		frm += frm[1] + 2;
99432176cfdSRui Paulo 	}
99532176cfdSRui Paulo 	switch (seq) {
99632176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_CHALLENGE:
99732176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_RESPONSE:
99832176cfdSRui Paulo 		if (challenge == NULL) {
99932176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
100032176cfdSRui Paulo 			    ni->ni_macaddr, "shared key auth",
100132176cfdSRui Paulo 			    "%s", "no challenge");
100232176cfdSRui Paulo 			vap->iv_stats.is_rx_bad_auth++;
100332176cfdSRui Paulo 			estatus = IEEE80211_STATUS_CHALLENGE;
100432176cfdSRui Paulo 			goto bad;
100532176cfdSRui Paulo 		}
100632176cfdSRui Paulo 		if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
100732176cfdSRui Paulo 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
100832176cfdSRui Paulo 			    ni->ni_macaddr, "shared key auth",
100932176cfdSRui Paulo 			    "bad challenge len %d", challenge[1]);
101032176cfdSRui Paulo 			vap->iv_stats.is_rx_bad_auth++;
101132176cfdSRui Paulo 			estatus = IEEE80211_STATUS_CHALLENGE;
101232176cfdSRui Paulo 			goto bad;
101332176cfdSRui Paulo 		}
101432176cfdSRui Paulo 	default:
101532176cfdSRui Paulo 		break;
101632176cfdSRui Paulo 	}
101732176cfdSRui Paulo 	if (vap->iv_state != IEEE80211_S_AUTH)
101832176cfdSRui Paulo 		return;
101932176cfdSRui Paulo 	switch (seq) {
102032176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_PASS:
102132176cfdSRui Paulo 		if (ni->ni_challenge != NULL) {
102232176cfdSRui Paulo 			kfree(ni->ni_challenge, M_80211_NODE);
102332176cfdSRui Paulo 			ni->ni_challenge = NULL;
102432176cfdSRui Paulo 		}
102532176cfdSRui Paulo 		if (status != 0) {
102632176cfdSRui Paulo 			IEEE80211_NOTE_FRAME(vap,
102732176cfdSRui Paulo 			    IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, wh,
102832176cfdSRui Paulo 			    "shared key auth failed (reason %d)", status);
102932176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_fail++;
103032176cfdSRui Paulo 			vap->iv_stats.is_rx_authfail_code = status;
103132176cfdSRui Paulo 			return;
103232176cfdSRui Paulo 		}
103332176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
103432176cfdSRui Paulo 		break;
103532176cfdSRui Paulo 	case IEEE80211_AUTH_SHARED_CHALLENGE:
103632176cfdSRui Paulo 		if (!ieee80211_alloc_challenge(ni))
103732176cfdSRui Paulo 			return;
103832176cfdSRui Paulo 		/* XXX could optimize by passing recvd challenge */
103932176cfdSRui Paulo 		memcpy(ni->ni_challenge, &challenge[2], challenge[1]);
104032176cfdSRui Paulo 		IEEE80211_SEND_MGMT(ni,
104132176cfdSRui Paulo 			IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
104232176cfdSRui Paulo 		break;
104332176cfdSRui Paulo 	default:
104432176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_AUTH,
104532176cfdSRui Paulo 		    wh, "shared key auth", "bad seq %d", seq);
104632176cfdSRui Paulo 		vap->iv_stats.is_rx_bad_auth++;
104732176cfdSRui Paulo 		return;
104832176cfdSRui Paulo 	}
104932176cfdSRui Paulo 	return;
105032176cfdSRui Paulo bad:
105132176cfdSRui Paulo 	/*
105232176cfdSRui Paulo 	 * Kick the state machine.  This short-circuits
105332176cfdSRui Paulo 	 * using the mgt frame timeout to trigger the
105432176cfdSRui Paulo 	 * state transition.
105532176cfdSRui Paulo 	 */
105632176cfdSRui Paulo 	if (vap->iv_state == IEEE80211_S_AUTH)
105732176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_SCAN,
105832176cfdSRui Paulo 		    IEEE80211_SCAN_FAIL_STATUS);
105932176cfdSRui Paulo }
106032176cfdSRui Paulo 
106132176cfdSRui Paulo static int
106232176cfdSRui Paulo ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
106332176cfdSRui Paulo 	const struct ieee80211_frame *wh)
106432176cfdSRui Paulo {
106532176cfdSRui Paulo #define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
106632176cfdSRui Paulo 	struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme;
106732176cfdSRui Paulo 	u_int len = frm[1], qosinfo;
106832176cfdSRui Paulo 	int i;
106932176cfdSRui Paulo 
107032176cfdSRui Paulo 	if (len < sizeof(struct ieee80211_wme_param)-2) {
107132176cfdSRui Paulo 		IEEE80211_DISCARD_IE(vap,
107232176cfdSRui Paulo 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
107332176cfdSRui Paulo 		    wh, "WME", "too short, len %u", len);
107432176cfdSRui Paulo 		return -1;
107532176cfdSRui Paulo 	}
107632176cfdSRui Paulo 	qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)];
107732176cfdSRui Paulo 	qosinfo &= WME_QOSINFO_COUNT;
107832176cfdSRui Paulo 	/* XXX do proper check for wraparound */
107932176cfdSRui Paulo 	if (qosinfo == wme->wme_wmeChanParams.cap_info)
108032176cfdSRui Paulo 		return 0;
108132176cfdSRui Paulo 	frm += __offsetof(struct ieee80211_wme_param, params_acParams);
108232176cfdSRui Paulo 	for (i = 0; i < WME_NUM_AC; i++) {
108332176cfdSRui Paulo 		struct wmeParams *wmep =
108432176cfdSRui Paulo 			&wme->wme_wmeChanParams.cap_wmeParams[i];
108532176cfdSRui Paulo 		/* NB: ACI not used */
108632176cfdSRui Paulo 		wmep->wmep_acm = MS(frm[0], WME_PARAM_ACM);
108732176cfdSRui Paulo 		wmep->wmep_aifsn = MS(frm[0], WME_PARAM_AIFSN);
108832176cfdSRui Paulo 		wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN);
108932176cfdSRui Paulo 		wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX);
109032176cfdSRui Paulo 		wmep->wmep_txopLimit = LE_READ_2(frm+2);
109132176cfdSRui Paulo 		frm += 4;
109232176cfdSRui Paulo 	}
109332176cfdSRui Paulo 	wme->wme_wmeChanParams.cap_info = qosinfo;
109432176cfdSRui Paulo 	return 1;
109532176cfdSRui Paulo #undef MS
109632176cfdSRui Paulo }
109732176cfdSRui Paulo 
109832176cfdSRui Paulo /*
109932176cfdSRui Paulo  * Process 11h Channel Switch Announcement (CSA) ie.  If this
110032176cfdSRui Paulo  * is the first CSA then initiate the switch.  Otherwise we
110132176cfdSRui Paulo  * track state and trigger completion and/or cancel of the switch.
110232176cfdSRui Paulo  * XXX should be public for IBSS use
110332176cfdSRui Paulo  */
110432176cfdSRui Paulo static void
110532176cfdSRui Paulo ieee80211_parse_csaparams(struct ieee80211vap *vap, uint8_t *frm,
110632176cfdSRui Paulo 	const struct ieee80211_frame *wh)
110732176cfdSRui Paulo {
110832176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
110932176cfdSRui Paulo 	const struct ieee80211_csa_ie *csa =
111032176cfdSRui Paulo 	    (const struct ieee80211_csa_ie *) frm;
111132176cfdSRui Paulo 
111232176cfdSRui Paulo 	KASSERT(vap->iv_state >= IEEE80211_S_RUN,
111332176cfdSRui Paulo 	    ("state %s", ieee80211_state_name[vap->iv_state]));
111432176cfdSRui Paulo 
111532176cfdSRui Paulo 	if (csa->csa_mode > 1) {
111632176cfdSRui Paulo 		IEEE80211_DISCARD_IE(vap,
111732176cfdSRui Paulo 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
111832176cfdSRui Paulo 		    wh, "CSA", "invalid mode %u", csa->csa_mode);
111932176cfdSRui Paulo 		return;
112032176cfdSRui Paulo 	}
112132176cfdSRui Paulo 	IEEE80211_LOCK(ic);
112232176cfdSRui Paulo 	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
112332176cfdSRui Paulo 		/*
112432176cfdSRui Paulo 		 * Convert the channel number to a channel reference.  We
112532176cfdSRui Paulo 		 * try first to preserve turbo attribute of the current
112632176cfdSRui Paulo 		 * channel then fallback.  Note this will not work if the
112732176cfdSRui Paulo 		 * CSA specifies a channel that requires a band switch (e.g.
112832176cfdSRui Paulo 		 * 11a => 11g).  This is intentional as 11h is defined only
112932176cfdSRui Paulo 		 * for 5GHz/11a and because the switch does not involve a
113032176cfdSRui Paulo 		 * reassociation, protocol state (capabilities, negotated
113132176cfdSRui Paulo 		 * rates, etc) may/will be wrong.
113232176cfdSRui Paulo 		 */
113332176cfdSRui Paulo 		struct ieee80211_channel *c =
113432176cfdSRui Paulo 		    ieee80211_find_channel_byieee(ic, csa->csa_newchan,
113532176cfdSRui Paulo 			(ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALLTURBO));
113632176cfdSRui Paulo 		if (c == NULL) {
113732176cfdSRui Paulo 			c = ieee80211_find_channel_byieee(ic,
113832176cfdSRui Paulo 			    csa->csa_newchan,
113932176cfdSRui Paulo 			    (ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALL));
114032176cfdSRui Paulo 			if (c == NULL) {
114132176cfdSRui Paulo 				IEEE80211_DISCARD_IE(vap,
114232176cfdSRui Paulo 				    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
114332176cfdSRui Paulo 				    wh, "CSA", "invalid channel %u",
114432176cfdSRui Paulo 				    csa->csa_newchan);
114532176cfdSRui Paulo 				goto done;
114632176cfdSRui Paulo 			}
114732176cfdSRui Paulo 		}
114832176cfdSRui Paulo #if IEEE80211_CSA_COUNT_MIN > 0
114932176cfdSRui Paulo 		if (csa->csa_count < IEEE80211_CSA_COUNT_MIN) {
115032176cfdSRui Paulo 			/*
115132176cfdSRui Paulo 			 * Require at least IEEE80211_CSA_COUNT_MIN count to
115232176cfdSRui Paulo 			 * reduce the risk of being redirected by a fabricated
115332176cfdSRui Paulo 			 * CSA.  If a valid CSA is dropped we'll still get a
115432176cfdSRui Paulo 			 * beacon miss when the AP leaves the channel so we'll
115532176cfdSRui Paulo 			 * eventually follow to the new channel.
115632176cfdSRui Paulo 			 *
115732176cfdSRui Paulo 			 * NOTE: this violates the 11h spec that states that
115832176cfdSRui Paulo 			 * count may be any value and if 0 then a switch
115932176cfdSRui Paulo 			 * should happen asap.
116032176cfdSRui Paulo 			 */
116132176cfdSRui Paulo 			IEEE80211_DISCARD_IE(vap,
116232176cfdSRui Paulo 			    IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH,
116332176cfdSRui Paulo 			    wh, "CSA", "count %u too small, must be >= %u",
116432176cfdSRui Paulo 			    csa->csa_count, IEEE80211_CSA_COUNT_MIN);
116532176cfdSRui Paulo 			goto done;
116632176cfdSRui Paulo 		}
116732176cfdSRui Paulo #endif
116832176cfdSRui Paulo 		ieee80211_csa_startswitch(ic, c, csa->csa_mode, csa->csa_count);
116932176cfdSRui Paulo 	} else {
117032176cfdSRui Paulo 		/*
117132176cfdSRui Paulo 		 * Validate this ie against the initial CSA.  We require
117232176cfdSRui Paulo 		 * mode and channel not change and the count must be
117332176cfdSRui Paulo 		 * monotonically decreasing.  This may be pointless and
117432176cfdSRui Paulo 		 * canceling the switch as a result may be too paranoid but
117532176cfdSRui Paulo 		 * in the worst case if we drop out of CSA because of this
117632176cfdSRui Paulo 		 * and the AP does move then we'll just end up taking a
117732176cfdSRui Paulo 		 * beacon miss and scan to find the AP.
117832176cfdSRui Paulo 		 *
117932176cfdSRui Paulo 		 * XXX may want <= on count as we also process ProbeResp
118032176cfdSRui Paulo 		 * frames and those may come in w/ the same count as the
118132176cfdSRui Paulo 		 * previous beacon; but doing so leaves us open to a stuck
118232176cfdSRui Paulo 		 * count until we add a dead-man timer
118332176cfdSRui Paulo 		 */
118432176cfdSRui Paulo 		if (!(csa->csa_count < ic->ic_csa_count &&
118532176cfdSRui Paulo 		      csa->csa_mode == ic->ic_csa_mode &&
118632176cfdSRui Paulo 		      csa->csa_newchan == ieee80211_chan2ieee(ic, ic->ic_csa_newchan))) {
118732176cfdSRui Paulo 			IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_DOTH, wh,
118832176cfdSRui Paulo 			    "CSA ie mismatch, initial ie <%d,%d,%d>, "
118932176cfdSRui Paulo 			    "this ie <%d,%d,%d>", ic->ic_csa_mode,
119032176cfdSRui Paulo 			    ic->ic_csa_newchan, ic->ic_csa_count,
119132176cfdSRui Paulo 			    csa->csa_mode, csa->csa_newchan, csa->csa_count);
119232176cfdSRui Paulo 			ieee80211_csa_cancelswitch(ic);
119332176cfdSRui Paulo 		} else {
119432176cfdSRui Paulo 			if (csa->csa_count <= 1)
119532176cfdSRui Paulo 				ieee80211_csa_completeswitch(ic);
119632176cfdSRui Paulo 			else
119732176cfdSRui Paulo 				ic->ic_csa_count = csa->csa_count;
119832176cfdSRui Paulo 		}
119932176cfdSRui Paulo 	}
120032176cfdSRui Paulo done:
120132176cfdSRui Paulo 	IEEE80211_UNLOCK(ic);
120232176cfdSRui Paulo }
120332176cfdSRui Paulo 
120432176cfdSRui Paulo /*
120532176cfdSRui Paulo  * Return non-zero if a background scan may be continued:
120632176cfdSRui Paulo  * o bg scan is active
120732176cfdSRui Paulo  * o no channel switch is pending
120832176cfdSRui Paulo  * o there has not been any traffic recently
120932176cfdSRui Paulo  *
121032176cfdSRui Paulo  * Note we do not check if there is an administrative enable;
121132176cfdSRui Paulo  * this is only done to start the scan.  We assume that any
121232176cfdSRui Paulo  * change in state will be accompanied by a request to cancel
121332176cfdSRui Paulo  * active scans which will otherwise cause this test to fail.
121432176cfdSRui Paulo  */
121532176cfdSRui Paulo static __inline int
121632176cfdSRui Paulo contbgscan(struct ieee80211vap *vap)
121732176cfdSRui Paulo {
121832176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
121932176cfdSRui Paulo 
122032176cfdSRui Paulo 	return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
122132176cfdSRui Paulo 	    (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
122232176cfdSRui Paulo 	    vap->iv_state == IEEE80211_S_RUN &&		/* XXX? */
122332176cfdSRui Paulo 	    time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
122432176cfdSRui Paulo }
122532176cfdSRui Paulo 
122632176cfdSRui Paulo /*
122732176cfdSRui Paulo  * Return non-zero if a backgrond scan may be started:
122832176cfdSRui Paulo  * o bg scanning is administratively enabled
122932176cfdSRui Paulo  * o no channel switch is pending
123032176cfdSRui Paulo  * o we are not boosted on a dynamic turbo channel
123132176cfdSRui Paulo  * o there has not been a scan recently
123232176cfdSRui Paulo  * o there has not been any traffic recently
123332176cfdSRui Paulo  */
123432176cfdSRui Paulo static __inline int
123532176cfdSRui Paulo startbgscan(struct ieee80211vap *vap)
123632176cfdSRui Paulo {
123732176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
123832176cfdSRui Paulo 
123932176cfdSRui Paulo 	return ((vap->iv_flags & IEEE80211_F_BGSCAN) &&
124032176cfdSRui Paulo 	    (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
124132176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
124232176cfdSRui Paulo 	    !IEEE80211_IS_CHAN_DTURBO(ic->ic_curchan) &&
124332176cfdSRui Paulo #endif
124432176cfdSRui Paulo 	    time_after(ticks, ic->ic_lastscan + vap->iv_bgscanintvl) &&
124532176cfdSRui Paulo 	    time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
124632176cfdSRui Paulo }
124732176cfdSRui Paulo 
124832176cfdSRui Paulo static void
124932176cfdSRui Paulo sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
125032176cfdSRui Paulo 	int subtype, int rssi, int nf)
125132176cfdSRui Paulo {
125232176cfdSRui Paulo #define	ISPROBE(_st)	((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
125332176cfdSRui Paulo #define	ISREASSOC(_st)	((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
125432176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
125532176cfdSRui Paulo 	struct ieee80211com *ic = ni->ni_ic;
125632176cfdSRui Paulo 	struct ieee80211_frame *wh;
125732176cfdSRui Paulo 	uint8_t *frm, *efrm;
125832176cfdSRui Paulo 	uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
125932176cfdSRui Paulo 	uint8_t rate;
126032176cfdSRui Paulo 
126132176cfdSRui Paulo 	wh = mtod(m0, struct ieee80211_frame *);
126232176cfdSRui Paulo 	frm = (uint8_t *)&wh[1];
126332176cfdSRui Paulo 	efrm = mtod(m0, uint8_t *) + m0->m_len;
126432176cfdSRui Paulo 	switch (subtype) {
126532176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
126632176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_BEACON: {
126732176cfdSRui Paulo 		struct ieee80211_scanparams scan;
126832176cfdSRui Paulo 		/*
126932176cfdSRui Paulo 		 * We process beacon/probe response frames:
127032176cfdSRui Paulo 		 *    o when scanning, or
127132176cfdSRui Paulo 		 *    o station mode when associated (to collect state
127232176cfdSRui Paulo 		 *      updates such as 802.11g slot time)
127332176cfdSRui Paulo 		 * Frames otherwise received are discarded.
127432176cfdSRui Paulo 		 */
127532176cfdSRui Paulo 		if (!((ic->ic_flags & IEEE80211_F_SCAN) || ni->ni_associd)) {
127632176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
127732176cfdSRui Paulo 			return;
127832176cfdSRui Paulo 		}
127932176cfdSRui Paulo 		/* XXX probe response in sta mode when !scanning? */
128032176cfdSRui Paulo 		if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
128132176cfdSRui Paulo 			return;
128232176cfdSRui Paulo 		/*
128332176cfdSRui Paulo 		 * Count frame now that we know it's to be processed.
128432176cfdSRui Paulo 		 */
128532176cfdSRui Paulo 		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
128632176cfdSRui Paulo 			vap->iv_stats.is_rx_beacon++;		/* XXX remove */
128732176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_beacons);
128832176cfdSRui Paulo 		} else
128932176cfdSRui Paulo 			IEEE80211_NODE_STAT(ni, rx_proberesp);
129032176cfdSRui Paulo 		/*
129132176cfdSRui Paulo 		 * When operating in station mode, check for state updates.
129232176cfdSRui Paulo 		 * Be careful to ignore beacons received while doing a
129332176cfdSRui Paulo 		 * background scan.  We consider only 11g/WMM stuff right now.
129432176cfdSRui Paulo 		 */
129532176cfdSRui Paulo 		if (ni->ni_associd != 0 &&
129632176cfdSRui Paulo 		    ((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
129732176cfdSRui Paulo 		     IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) {
129832176cfdSRui Paulo 			/* record tsf of last beacon */
129932176cfdSRui Paulo 			memcpy(ni->ni_tstamp.data, scan.tstamp,
130032176cfdSRui Paulo 				sizeof(ni->ni_tstamp));
130132176cfdSRui Paulo 			/* count beacon frame for s/w bmiss handling */
130232176cfdSRui Paulo 			vap->iv_swbmiss_count++;
130332176cfdSRui Paulo 			vap->iv_bmiss_count = 0;
130432176cfdSRui Paulo 			if (ni->ni_erp != scan.erp) {
130532176cfdSRui Paulo 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
130632176cfdSRui Paulo 				    wh->i_addr2,
130732176cfdSRui Paulo 				    "erp change: was 0x%x, now 0x%x",
130832176cfdSRui Paulo 				    ni->ni_erp, scan.erp);
130932176cfdSRui Paulo 				if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
131032176cfdSRui Paulo 				    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
131132176cfdSRui Paulo 					ic->ic_flags |= IEEE80211_F_USEPROT;
131232176cfdSRui Paulo 				else
131332176cfdSRui Paulo 					ic->ic_flags &= ~IEEE80211_F_USEPROT;
131432176cfdSRui Paulo 				ni->ni_erp = scan.erp;
131532176cfdSRui Paulo 				/* XXX statistic */
131632176cfdSRui Paulo 				/* XXX driver notification */
131732176cfdSRui Paulo 			}
131832176cfdSRui Paulo 			if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
131932176cfdSRui Paulo 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
132032176cfdSRui Paulo 				    wh->i_addr2,
132132176cfdSRui Paulo 				    "capabilities change: was 0x%x, now 0x%x",
132232176cfdSRui Paulo 				    ni->ni_capinfo, scan.capinfo);
132332176cfdSRui Paulo 				/*
132432176cfdSRui Paulo 				 * NB: we assume short preamble doesn't
132532176cfdSRui Paulo 				 *     change dynamically
132632176cfdSRui Paulo 				 */
132732176cfdSRui Paulo 				ieee80211_set_shortslottime(ic,
132832176cfdSRui Paulo 					IEEE80211_IS_CHAN_A(ic->ic_bsschan) ||
132932176cfdSRui Paulo 					(scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
133032176cfdSRui Paulo 				ni->ni_capinfo = (ni->ni_capinfo &~ IEEE80211_CAPINFO_SHORT_SLOTTIME)
133132176cfdSRui Paulo 					       | (scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME);
133232176cfdSRui Paulo 				/* XXX statistic */
133332176cfdSRui Paulo 			}
133432176cfdSRui Paulo 			if (scan.wme != NULL &&
133532176cfdSRui Paulo 			    (ni->ni_flags & IEEE80211_NODE_QOS) &&
133632176cfdSRui Paulo 			    ieee80211_parse_wmeparams(vap, scan.wme, wh) > 0)
133732176cfdSRui Paulo 				ieee80211_wme_updateparams(vap);
133832176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
133932176cfdSRui Paulo 			if (scan.ath != NULL)
134032176cfdSRui Paulo 				ieee80211_parse_athparams(ni, scan.ath, wh);
134132176cfdSRui Paulo #endif
134232176cfdSRui Paulo 			if (scan.htcap != NULL && scan.htinfo != NULL &&
134332176cfdSRui Paulo 			    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
134432176cfdSRui Paulo 				ieee80211_ht_updateparams(ni,
134532176cfdSRui Paulo 				    scan.htcap, scan.htinfo);
134632176cfdSRui Paulo 				/* XXX state changes? */
134732176cfdSRui Paulo 			}
134832176cfdSRui Paulo 			if (scan.tim != NULL) {
134932176cfdSRui Paulo 				struct ieee80211_tim_ie *tim =
135032176cfdSRui Paulo 				    (struct ieee80211_tim_ie *) scan.tim;
135132176cfdSRui Paulo #if 0
135232176cfdSRui Paulo 				int aid = IEEE80211_AID(ni->ni_associd);
135332176cfdSRui Paulo 				int ix = aid / NBBY;
135432176cfdSRui Paulo 				int min = tim->tim_bitctl &~ 1;
135532176cfdSRui Paulo 				int max = tim->tim_len + min - 4;
135632176cfdSRui Paulo 				if ((tim->tim_bitctl&1) ||
135732176cfdSRui Paulo 				    (min <= ix && ix <= max &&
135832176cfdSRui Paulo 				     isset(tim->tim_bitmap - min, aid))) {
135932176cfdSRui Paulo 					/*
136032176cfdSRui Paulo 					 * XXX Do not let bg scan kick off
136132176cfdSRui Paulo 					 * we are expecting data.
136232176cfdSRui Paulo 					 */
136332176cfdSRui Paulo 					ic->ic_lastdata = ticks;
136432176cfdSRui Paulo 					ieee80211_sta_pwrsave(vap, 0);
136532176cfdSRui Paulo 				}
136632176cfdSRui Paulo #endif
136732176cfdSRui Paulo 				ni->ni_dtim_count = tim->tim_count;
136832176cfdSRui Paulo 				ni->ni_dtim_period = tim->tim_period;
136932176cfdSRui Paulo 			}
137032176cfdSRui Paulo 			if (scan.csa != NULL &&
137132176cfdSRui Paulo 			    (vap->iv_flags & IEEE80211_F_DOTH))
137232176cfdSRui Paulo 				ieee80211_parse_csaparams(vap, scan.csa, wh);
137332176cfdSRui Paulo 			else if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
137432176cfdSRui Paulo 				/*
137532176cfdSRui Paulo 				 * No CSA ie or 11h disabled, but a channel
137632176cfdSRui Paulo 				 * switch is pending; drop out so we aren't
137732176cfdSRui Paulo 				 * stuck in CSA state.  If the AP really is
137832176cfdSRui Paulo 				 * moving we'll get a beacon miss and scan.
137932176cfdSRui Paulo 				 */
138032176cfdSRui Paulo 				IEEE80211_LOCK(ic);
138132176cfdSRui Paulo 				ieee80211_csa_cancelswitch(ic);
138232176cfdSRui Paulo 				IEEE80211_UNLOCK(ic);
138332176cfdSRui Paulo 			}
138432176cfdSRui Paulo 			/*
138532176cfdSRui Paulo 			 * If scanning, pass the info to the scan module.
138632176cfdSRui Paulo 			 * Otherwise, check if it's the right time to do
138732176cfdSRui Paulo 			 * a background scan.  Background scanning must
138832176cfdSRui Paulo 			 * be enabled and we must not be operating in the
138932176cfdSRui Paulo 			 * turbo phase of dynamic turbo mode.  Then,
139032176cfdSRui Paulo 			 * it's been a while since the last background
139132176cfdSRui Paulo 			 * scan and if no data frames have come through
139232176cfdSRui Paulo 			 * recently, kick off a scan.  Note that this
139332176cfdSRui Paulo 			 * is the mechanism by which a background scan
139432176cfdSRui Paulo 			 * is started _and_ continued each time we
139532176cfdSRui Paulo 			 * return on-channel to receive a beacon from
139632176cfdSRui Paulo 			 * our ap.
139732176cfdSRui Paulo 			 */
139832176cfdSRui Paulo 			if (ic->ic_flags & IEEE80211_F_SCAN) {
139932176cfdSRui Paulo 				ieee80211_add_scan(vap, &scan, wh,
140032176cfdSRui Paulo 					subtype, rssi, nf);
140132176cfdSRui Paulo 			} else if (contbgscan(vap)) {
140232176cfdSRui Paulo 				ieee80211_bg_scan(vap, 0);
140332176cfdSRui Paulo 			} else if (startbgscan(vap)) {
140432176cfdSRui Paulo 				vap->iv_stats.is_scan_bg++;
140532176cfdSRui Paulo #if 0
140632176cfdSRui Paulo 				/* wakeup if we are sleeing */
140732176cfdSRui Paulo 				ieee80211_set_pwrsave(vap, 0);
140832176cfdSRui Paulo #endif
140932176cfdSRui Paulo 				ieee80211_bg_scan(vap, 0);
141032176cfdSRui Paulo 			}
141132176cfdSRui Paulo 			return;
141232176cfdSRui Paulo 		}
141332176cfdSRui Paulo 		/*
141432176cfdSRui Paulo 		 * If scanning, just pass information to the scan module.
141532176cfdSRui Paulo 		 */
141632176cfdSRui Paulo 		if (ic->ic_flags & IEEE80211_F_SCAN) {
141732176cfdSRui Paulo 			if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
141832176cfdSRui Paulo 				/*
141932176cfdSRui Paulo 				 * Actively scanning a channel marked passive;
142032176cfdSRui Paulo 				 * send a probe request now that we know there
142132176cfdSRui Paulo 				 * is 802.11 traffic present.
142232176cfdSRui Paulo 				 *
142332176cfdSRui Paulo 				 * XXX check if the beacon we recv'd gives
142432176cfdSRui Paulo 				 * us what we need and suppress the probe req
142532176cfdSRui Paulo 				 */
142632176cfdSRui Paulo 				ieee80211_probe_curchan(vap, 1);
142732176cfdSRui Paulo 				ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
142832176cfdSRui Paulo 			}
142932176cfdSRui Paulo 			ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
143032176cfdSRui Paulo 			return;
143132176cfdSRui Paulo 		}
143232176cfdSRui Paulo 		break;
143332176cfdSRui Paulo 	}
143432176cfdSRui Paulo 
143532176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_AUTH: {
143632176cfdSRui Paulo 		uint16_t algo, seq, status;
143732176cfdSRui Paulo 		/*
143832176cfdSRui Paulo 		 * auth frame format
143932176cfdSRui Paulo 		 *	[2] algorithm
144032176cfdSRui Paulo 		 *	[2] sequence
144132176cfdSRui Paulo 		 *	[2] status
144232176cfdSRui Paulo 		 *	[tlv*] challenge
144332176cfdSRui Paulo 		 */
144432176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
144532176cfdSRui Paulo 		algo   = le16toh(*(uint16_t *)frm);
144632176cfdSRui Paulo 		seq    = le16toh(*(uint16_t *)(frm + 2));
144732176cfdSRui Paulo 		status = le16toh(*(uint16_t *)(frm + 4));
144832176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2,
144932176cfdSRui Paulo 		    "recv auth frame with algorithm %d seq %d", algo, seq);
145032176cfdSRui Paulo 
145132176cfdSRui Paulo 		if (vap->iv_flags & IEEE80211_F_COUNTERM) {
145232176cfdSRui Paulo 			IEEE80211_DISCARD(vap,
145332176cfdSRui Paulo 			    IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
145432176cfdSRui Paulo 			    wh, "auth", "%s", "TKIP countermeasures enabled");
145532176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_countermeasures++;
145632176cfdSRui Paulo 			if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
145732176cfdSRui Paulo 				ieee80211_send_error(ni, wh->i_addr2,
145832176cfdSRui Paulo 					IEEE80211_FC0_SUBTYPE_AUTH,
145932176cfdSRui Paulo 					IEEE80211_REASON_MIC_FAILURE);
146032176cfdSRui Paulo 			}
146132176cfdSRui Paulo 			return;
146232176cfdSRui Paulo 		}
146332176cfdSRui Paulo 		if (algo == IEEE80211_AUTH_ALG_SHARED)
146432176cfdSRui Paulo 			sta_auth_shared(ni, wh, frm + 6, efrm, rssi, nf,
146532176cfdSRui Paulo 			    seq, status);
146632176cfdSRui Paulo 		else if (algo == IEEE80211_AUTH_ALG_OPEN)
146732176cfdSRui Paulo 			sta_auth_open(ni, wh, rssi, nf, seq, status);
146832176cfdSRui Paulo 		else {
146932176cfdSRui Paulo 			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
147032176cfdSRui Paulo 			    wh, "auth", "unsupported alg %d", algo);
147132176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_unsupported++;
147232176cfdSRui Paulo 			return;
147332176cfdSRui Paulo 		}
147432176cfdSRui Paulo 		break;
147532176cfdSRui Paulo 	}
147632176cfdSRui Paulo 
147732176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
147832176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: {
147932176cfdSRui Paulo 		uint16_t capinfo, associd;
148032176cfdSRui Paulo 		uint16_t status;
148132176cfdSRui Paulo 
148232176cfdSRui Paulo 		if (vap->iv_state != IEEE80211_S_ASSOC) {
148332176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
148432176cfdSRui Paulo 			return;
148532176cfdSRui Paulo 		}
148632176cfdSRui Paulo 
148732176cfdSRui Paulo 		/*
148832176cfdSRui Paulo 		 * asresp frame format
148932176cfdSRui Paulo 		 *	[2] capability information
149032176cfdSRui Paulo 		 *	[2] status
149132176cfdSRui Paulo 		 *	[2] association ID
149232176cfdSRui Paulo 		 *	[tlv] supported rates
149332176cfdSRui Paulo 		 *	[tlv] extended supported rates
149432176cfdSRui Paulo 		 *	[tlv] WME
149532176cfdSRui Paulo 		 *	[tlv] HT capabilities
149632176cfdSRui Paulo 		 *	[tlv] HT info
149732176cfdSRui Paulo 		 */
149832176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
149932176cfdSRui Paulo 		ni = vap->iv_bss;
150032176cfdSRui Paulo 		capinfo = le16toh(*(uint16_t *)frm);
150132176cfdSRui Paulo 		frm += 2;
150232176cfdSRui Paulo 		status = le16toh(*(uint16_t *)frm);
150332176cfdSRui Paulo 		frm += 2;
150432176cfdSRui Paulo 		if (status != 0) {
150532176cfdSRui Paulo 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
150632176cfdSRui Paulo 			    wh->i_addr2, "%sassoc failed (reason %d)",
150732176cfdSRui Paulo 			    ISREASSOC(subtype) ?  "re" : "", status);
150832176cfdSRui Paulo 			vap->iv_stats.is_rx_auth_fail++;	/* XXX */
150932176cfdSRui Paulo 			return;
151032176cfdSRui Paulo 		}
151132176cfdSRui Paulo 		associd = le16toh(*(uint16_t *)frm);
151232176cfdSRui Paulo 		frm += 2;
151332176cfdSRui Paulo 
151432176cfdSRui Paulo 		rates = xrates = wme = htcap = htinfo = NULL;
151532176cfdSRui Paulo 		while (efrm - frm > 1) {
151632176cfdSRui Paulo 			IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
151732176cfdSRui Paulo 			switch (*frm) {
151832176cfdSRui Paulo 			case IEEE80211_ELEMID_RATES:
151932176cfdSRui Paulo 				rates = frm;
152032176cfdSRui Paulo 				break;
152132176cfdSRui Paulo 			case IEEE80211_ELEMID_XRATES:
152232176cfdSRui Paulo 				xrates = frm;
152332176cfdSRui Paulo 				break;
152432176cfdSRui Paulo 			case IEEE80211_ELEMID_HTCAP:
152532176cfdSRui Paulo 				htcap = frm;
152632176cfdSRui Paulo 				break;
152732176cfdSRui Paulo 			case IEEE80211_ELEMID_HTINFO:
152832176cfdSRui Paulo 				htinfo = frm;
152932176cfdSRui Paulo 				break;
153032176cfdSRui Paulo 			case IEEE80211_ELEMID_VENDOR:
153132176cfdSRui Paulo 				if (iswmeoui(frm))
153232176cfdSRui Paulo 					wme = frm;
153332176cfdSRui Paulo 				else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) {
153432176cfdSRui Paulo 					/*
153532176cfdSRui Paulo 					 * Accept pre-draft HT ie's if the
153632176cfdSRui Paulo 					 * standard ones have not been seen.
153732176cfdSRui Paulo 					 */
153832176cfdSRui Paulo 					if (ishtcapoui(frm)) {
153932176cfdSRui Paulo 						if (htcap == NULL)
154032176cfdSRui Paulo 							htcap = frm;
154132176cfdSRui Paulo 					} else if (ishtinfooui(frm)) {
154232176cfdSRui Paulo 						if (htinfo == NULL)
154332176cfdSRui Paulo 							htcap = frm;
154432176cfdSRui Paulo 					}
154532176cfdSRui Paulo 				}
154632176cfdSRui Paulo 				/* XXX Atheros OUI support */
154732176cfdSRui Paulo 				break;
154832176cfdSRui Paulo 			}
154932176cfdSRui Paulo 			frm += frm[1] + 2;
155032176cfdSRui Paulo 		}
155132176cfdSRui Paulo 
155232176cfdSRui Paulo 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return);
155332176cfdSRui Paulo 		if (xrates != NULL)
155432176cfdSRui Paulo 			IEEE80211_VERIFY_ELEMENT(xrates,
155532176cfdSRui Paulo 				IEEE80211_RATE_MAXSIZE - rates[1], return);
155632176cfdSRui Paulo 		rate = ieee80211_setup_rates(ni, rates, xrates,
155732176cfdSRui Paulo 				IEEE80211_F_JOIN |
155832176cfdSRui Paulo 				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
155932176cfdSRui Paulo 				IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
156032176cfdSRui Paulo 		if (rate & IEEE80211_RATE_BASIC) {
156132176cfdSRui Paulo 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
156232176cfdSRui Paulo 			    wh->i_addr2,
156332176cfdSRui Paulo 			    "%sassoc failed (rate set mismatch)",
156432176cfdSRui Paulo 			    ISREASSOC(subtype) ?  "re" : "");
156532176cfdSRui Paulo 			vap->iv_stats.is_rx_assoc_norate++;
156632176cfdSRui Paulo 			ieee80211_new_state(vap, IEEE80211_S_SCAN,
156732176cfdSRui Paulo 			    IEEE80211_SCAN_FAIL_STATUS);
156832176cfdSRui Paulo 			return;
156932176cfdSRui Paulo 		}
157032176cfdSRui Paulo 
157132176cfdSRui Paulo 		ni->ni_capinfo = capinfo;
157232176cfdSRui Paulo 		ni->ni_associd = associd;
157332176cfdSRui Paulo 		if (ni->ni_jointime == 0)
157432176cfdSRui Paulo 			ni->ni_jointime = time_second;
157532176cfdSRui Paulo 		if (wme != NULL &&
157632176cfdSRui Paulo 		    ieee80211_parse_wmeparams(vap, wme, wh) >= 0) {
157732176cfdSRui Paulo 			ni->ni_flags |= IEEE80211_NODE_QOS;
157832176cfdSRui Paulo 			ieee80211_wme_updateparams(vap);
157932176cfdSRui Paulo 		} else
158032176cfdSRui Paulo 			ni->ni_flags &= ~IEEE80211_NODE_QOS;
158132176cfdSRui Paulo 		/*
158232176cfdSRui Paulo 		 * Setup HT state according to the negotiation.
158332176cfdSRui Paulo 		 *
158432176cfdSRui Paulo 		 * NB: shouldn't need to check if HT use is enabled but some
158532176cfdSRui Paulo 		 *     ap's send back HT ie's even when we don't indicate we
158632176cfdSRui Paulo 		 *     are HT capable in our AssocReq.
158732176cfdSRui Paulo 		 */
158832176cfdSRui Paulo 		if (htcap != NULL && htinfo != NULL &&
158932176cfdSRui Paulo 		    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
159032176cfdSRui Paulo 			ieee80211_ht_node_init(ni);
159132176cfdSRui Paulo 			ieee80211_ht_updateparams(ni, htcap, htinfo);
159232176cfdSRui Paulo 			ieee80211_setup_htrates(ni, htcap,
159332176cfdSRui Paulo 			     IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
159432176cfdSRui Paulo 			ieee80211_setup_basic_htrates(ni, htinfo);
159532176cfdSRui Paulo 			ieee80211_node_setuptxparms(ni);
159632176cfdSRui Paulo 		} else {
159732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG
159832176cfdSRui Paulo 			if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_ATH))
159932176cfdSRui Paulo 				ieee80211_ff_node_init(ni);
160032176cfdSRui Paulo #endif
160132176cfdSRui Paulo 		}
160232176cfdSRui Paulo 		/*
160332176cfdSRui Paulo 		 * Configure state now that we are associated.
160432176cfdSRui Paulo 		 *
160532176cfdSRui Paulo 		 * XXX may need different/additional driver callbacks?
160632176cfdSRui Paulo 		 */
160732176cfdSRui Paulo 		if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
160832176cfdSRui Paulo 		    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
160932176cfdSRui Paulo 			ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
161032176cfdSRui Paulo 			ic->ic_flags &= ~IEEE80211_F_USEBARKER;
161132176cfdSRui Paulo 		} else {
161232176cfdSRui Paulo 			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
161332176cfdSRui Paulo 			ic->ic_flags |= IEEE80211_F_USEBARKER;
161432176cfdSRui Paulo 		}
161532176cfdSRui Paulo 		ieee80211_set_shortslottime(ic,
161632176cfdSRui Paulo 			IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
161732176cfdSRui Paulo 			(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
161832176cfdSRui Paulo 		/*
161932176cfdSRui Paulo 		 * Honor ERP protection.
162032176cfdSRui Paulo 		 *
162132176cfdSRui Paulo 		 * NB: ni_erp should zero for non-11g operation.
162232176cfdSRui Paulo 		 */
162332176cfdSRui Paulo 		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
162432176cfdSRui Paulo 		    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
162532176cfdSRui Paulo 			ic->ic_flags |= IEEE80211_F_USEPROT;
162632176cfdSRui Paulo 		else
162732176cfdSRui Paulo 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
162832176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap,
162932176cfdSRui Paulo 		    IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, wh->i_addr2,
163032176cfdSRui Paulo 		    "%sassoc success at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s",
163132176cfdSRui Paulo 		    ISREASSOC(subtype) ? "re" : "",
163232176cfdSRui Paulo 		    IEEE80211_NODE_AID(ni),
163332176cfdSRui Paulo 		    ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
163432176cfdSRui Paulo 		    ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
163532176cfdSRui Paulo 		    ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
163632176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
163732176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_HT ?
163832176cfdSRui Paulo 			(ni->ni_chw == 40 ? ", HT40" : ", HT20") : "",
163932176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
164032176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
164132176cfdSRui Paulo 			ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "",
164232176cfdSRui Paulo 		    ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "",
164332176cfdSRui Paulo 		    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ?
164432176cfdSRui Paulo 			", fast-frames" : "",
164532176cfdSRui Paulo 		    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ?
164632176cfdSRui Paulo 			", turbo" : ""
164732176cfdSRui Paulo 		);
164832176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_RUN, subtype);
164932176cfdSRui Paulo 		break;
165032176cfdSRui Paulo 	}
165132176cfdSRui Paulo 
165232176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_DEAUTH: {
165332176cfdSRui Paulo 		uint16_t reason;
165432176cfdSRui Paulo 
165532176cfdSRui Paulo 		if (vap->iv_state == IEEE80211_S_SCAN) {
165632176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
165732176cfdSRui Paulo 			return;
165832176cfdSRui Paulo 		}
165932176cfdSRui Paulo 		if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
166032176cfdSRui Paulo 			/* NB: can happen when in promiscuous mode */
166132176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
166232176cfdSRui Paulo 			break;
166332176cfdSRui Paulo 		}
166432176cfdSRui Paulo 
166532176cfdSRui Paulo 		/*
166632176cfdSRui Paulo 		 * deauth frame format
166732176cfdSRui Paulo 		 *	[2] reason
166832176cfdSRui Paulo 		 */
166932176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
167032176cfdSRui Paulo 		reason = le16toh(*(uint16_t *)frm);
167132176cfdSRui Paulo 
167232176cfdSRui Paulo 		vap->iv_stats.is_rx_deauth++;
167332176cfdSRui Paulo 		vap->iv_stats.is_rx_deauth_code = reason;
167432176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_deauth);
167532176cfdSRui Paulo 
167632176cfdSRui Paulo 		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
167732176cfdSRui Paulo 		    "recv deauthenticate (reason %d)", reason);
167832176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_AUTH,
167932176cfdSRui Paulo 		    (reason << 8) | IEEE80211_FC0_SUBTYPE_DEAUTH);
168032176cfdSRui Paulo 		break;
168132176cfdSRui Paulo 	}
168232176cfdSRui Paulo 
168332176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_DISASSOC: {
168432176cfdSRui Paulo 		uint16_t reason;
168532176cfdSRui Paulo 
168632176cfdSRui Paulo 		if (vap->iv_state != IEEE80211_S_RUN &&
168732176cfdSRui Paulo 		    vap->iv_state != IEEE80211_S_ASSOC &&
168832176cfdSRui Paulo 		    vap->iv_state != IEEE80211_S_AUTH) {
168932176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
169032176cfdSRui Paulo 			return;
169132176cfdSRui Paulo 		}
169232176cfdSRui Paulo 		if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
169332176cfdSRui Paulo 			/* NB: can happen when in promiscuous mode */
169432176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
169532176cfdSRui Paulo 			break;
169632176cfdSRui Paulo 		}
169732176cfdSRui Paulo 
169832176cfdSRui Paulo 		/*
169932176cfdSRui Paulo 		 * disassoc frame format
170032176cfdSRui Paulo 		 *	[2] reason
170132176cfdSRui Paulo 		 */
170232176cfdSRui Paulo 		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
170332176cfdSRui Paulo 		reason = le16toh(*(uint16_t *)frm);
170432176cfdSRui Paulo 
170532176cfdSRui Paulo 		vap->iv_stats.is_rx_disassoc++;
170632176cfdSRui Paulo 		vap->iv_stats.is_rx_disassoc_code = reason;
170732176cfdSRui Paulo 		IEEE80211_NODE_STAT(ni, rx_disassoc);
170832176cfdSRui Paulo 
170932176cfdSRui Paulo 		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
171032176cfdSRui Paulo 		    "recv disassociate (reason %d)", reason);
171132176cfdSRui Paulo 		ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
171232176cfdSRui Paulo 		break;
171332176cfdSRui Paulo 	}
171432176cfdSRui Paulo 
171532176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_ACTION:
171632176cfdSRui Paulo 		if (vap->iv_state == IEEE80211_S_RUN) {
171732176cfdSRui Paulo 			if (ieee80211_parse_action(ni, m0) == 0)
171832176cfdSRui Paulo 				ic->ic_recv_action(ni, wh, frm, efrm);
171932176cfdSRui Paulo 		} else
172032176cfdSRui Paulo 			vap->iv_stats.is_rx_mgtdiscard++;
172132176cfdSRui Paulo 		break;
172232176cfdSRui Paulo 
172332176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
172432176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
172532176cfdSRui Paulo 	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
172632176cfdSRui Paulo 		vap->iv_stats.is_rx_mgtdiscard++;
172732176cfdSRui Paulo 		return;
172832176cfdSRui Paulo 	default:
172932176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
173032176cfdSRui Paulo 		     wh, "mgt", "subtype 0x%x not handled", subtype);
173132176cfdSRui Paulo 		vap->iv_stats.is_rx_badsubtype++;
173232176cfdSRui Paulo 		break;
173332176cfdSRui Paulo 	}
173432176cfdSRui Paulo #undef ISREASSOC
173532176cfdSRui Paulo #undef ISPROBE
173632176cfdSRui Paulo }
173732176cfdSRui Paulo 
173832176cfdSRui Paulo static void
173932176cfdSRui Paulo sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype)
174032176cfdSRui Paulo {
174132176cfdSRui Paulo }
1742