ieee80211_hostap.c revision 296254
190075Sobrien/*-
2169689Skan * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
3169689Skan * All rights reserved.
490075Sobrien *
590075Sobrien * Redistribution and use in source and binary forms, with or without
690075Sobrien * modification, are permitted provided that the following conditions
7132718Skan * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
9132718Skan *    notice, this list of conditions and the following disclaimer.
1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1190075Sobrien *    notice, this list of conditions and the following disclaimer in the
1290075Sobrien *    documentation and/or other materials provided with the distribution.
1390075Sobrien *
14132718Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1590075Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1690075Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1790075Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1890075Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1990075Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20132718Skan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21169689Skan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22169689Skan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2390075Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2490075Sobrien */
2590075Sobrien
2690075Sobrien#include <sys/cdefs.h>
2790075Sobrien#ifdef __FreeBSD__
2890075Sobrien__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_hostap.c 296254 2016-03-01 06:47:21Z avos $");
2990075Sobrien#endif
3090075Sobrien
3190075Sobrien/*
3290075Sobrien * IEEE 802.11 HOSTAP mode support.
33117395Skan */
34117395Skan#include "opt_inet.h"
35117395Skan#include "opt_wlan.h"
36117395Skan
37117395Skan#include <sys/param.h>
38117395Skan#include <sys/systm.h>
39117395Skan#include <sys/mbuf.h>
40117395Skan#include <sys/malloc.h>
41117395Skan#include <sys/kernel.h>
42117395Skan
43117395Skan#include <sys/socket.h>
44117395Skan#include <sys/sockio.h>
45132718Skan#include <sys/endian.h>
46132718Skan#include <sys/errno.h>
47132718Skan#include <sys/proc.h>
48132718Skan#include <sys/sysctl.h>
4996263Sobrien
50132718Skan#include <net/if.h>
51132718Skan#include <net/if_var.h>
5290075Sobrien#include <net/if_media.h>
5390075Sobrien#include <net/if_llc.h>
5490075Sobrien#include <net/ethernet.h>
5596263Sobrien
5696263Sobrien#include <net/bpf.h>
57169689Skan
58169689Skan#include <net80211/ieee80211_var.h>
59169689Skan#include <net80211/ieee80211_hostap.h>
6096263Sobrien#include <net80211/ieee80211_input.h>
61132718Skan#ifdef IEEE80211_SUPPORT_SUPERG
62132718Skan#include <net80211/ieee80211_superg.h>
63132718Skan#endif
64132718Skan#include <net80211/ieee80211_wds.h>
65132718Skan
66132718Skan#define	IEEE80211_RATE2MBS(r)	(((r) & IEEE80211_RATE_VAL) / 2)
67132718Skan
68132718Skanstatic	void hostap_vattach(struct ieee80211vap *);
69132718Skanstatic	int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int);
70117395Skanstatic	int hostap_input(struct ieee80211_node *ni, struct mbuf *m,
71117395Skan	    const struct ieee80211_rx_stats *,
72117395Skan	    int rssi, int nf);
73117395Skanstatic void hostap_deliver_data(struct ieee80211vap *,
74132718Skan	    struct ieee80211_node *, struct mbuf *);
75117395Skanstatic void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *,
76117395Skan	    int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf);
77169689Skanstatic void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
78169689Skan
79169689Skanvoid
80169689Skanieee80211_hostap_attach(struct ieee80211com *ic)
81117395Skan{
82117395Skan	ic->ic_vattach[IEEE80211_M_HOSTAP] = hostap_vattach;
83117395Skan}
84117395Skan
85169689Skanvoid
86169689Skanieee80211_hostap_detach(struct ieee80211com *ic)
8790075Sobrien{
88169689Skan}
89169689Skan
90169689Skanstatic void
91169689Skanhostap_vdetach(struct ieee80211vap *vap)
92169689Skan{
93169689Skan}
9490075Sobrien
9590075Sobrienstatic void
9690075Sobrienhostap_vattach(struct ieee80211vap *vap)
9790075Sobrien{
98169689Skan	vap->iv_newstate = hostap_newstate;
9990075Sobrien	vap->iv_input = hostap_input;
10090075Sobrien	vap->iv_recv_mgmt = hostap_recv_mgmt;
10190075Sobrien	vap->iv_recv_ctl = hostap_recv_ctl;
10290075Sobrien	vap->iv_opdetach = hostap_vdetach;
10390075Sobrien	vap->iv_deliver_data = hostap_deliver_data;
10490075Sobrien	vap->iv_recv_pspoll = ieee80211_recv_pspoll;
105132718Skan}
106169689Skan
107132718Skanstatic void
108132718Skansta_disassoc(void *arg, struct ieee80211_node *ni)
109132718Skan{
110132718Skan	struct ieee80211vap *vap = arg;
111169689Skan
112132718Skan	if (ni->ni_vap == vap && ni->ni_associd != 0) {
113132718Skan		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC,
114132718Skan			IEEE80211_REASON_ASSOC_LEAVE);
115132718Skan		ieee80211_node_leave(ni);
116132718Skan	}
117132718Skan}
11890075Sobrien
11990075Sobrienstatic void
12090075Sobriensta_csa(void *arg, struct ieee80211_node *ni)
12190075Sobrien{
12290075Sobrien	struct ieee80211vap *vap = arg;
12390075Sobrien
12490075Sobrien	if (ni->ni_vap == vap && ni->ni_associd != 0)
12590075Sobrien		if (ni->ni_inact > vap->iv_inact_init) {
12690075Sobrien			ni->ni_inact = vap->iv_inact_init;
12790075Sobrien			IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
12890075Sobrien			    "%s: inact %u", __func__, ni->ni_inact);
12990075Sobrien		}
13090075Sobrien}
13190075Sobrien
13290075Sobrienstatic void
13390075Sobriensta_drop(void *arg, struct ieee80211_node *ni)
13490075Sobrien{
135132718Skan	struct ieee80211vap *vap = arg;
136132718Skan
137132718Skan	if (ni->ni_vap == vap && ni->ni_associd != 0)
13890075Sobrien		ieee80211_node_leave(ni);
13990075Sobrien}
14090075Sobrien
14190075Sobrien/*
142132718Skan * Does a channel change require associated stations to re-associate
143132718Skan * so protocol state is correct.  This is used when doing CSA across
144132718Skan * bands or similar (e.g. HT -> legacy).
14590075Sobrien */
14690075Sobrienstatic int
14790075Sobrienisbandchange(struct ieee80211com *ic)
14890075Sobrien{
14990075Sobrien	return ((ic->ic_bsschan->ic_flags ^ ic->ic_csa_newchan->ic_flags) &
15090075Sobrien	    (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HALF |
15190075Sobrien	     IEEE80211_CHAN_QUARTER | IEEE80211_CHAN_HT)) != 0;
15290075Sobrien}
15390075Sobrien
15490075Sobrien/*
15590075Sobrien * IEEE80211_M_HOSTAP vap state machine handler.
15690075Sobrien */
15790075Sobrienstatic int
15890075Sobrienhostap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
15990075Sobrien{
16090075Sobrien	struct ieee80211com *ic = vap->iv_ic;
16190075Sobrien	enum ieee80211_state ostate;
16290075Sobrien
16390075Sobrien	IEEE80211_LOCK_ASSERT(ic);
16490075Sobrien
16590075Sobrien	ostate = vap->iv_state;
16690075Sobrien	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
16790075Sobrien	    __func__, ieee80211_state_name[ostate],
16890075Sobrien	    ieee80211_state_name[nstate], arg);
16990075Sobrien	vap->iv_state = nstate;			/* state transition */
17090075Sobrien	if (ostate != IEEE80211_S_SCAN)
17190075Sobrien		ieee80211_cancel_scan(vap);	/* background scan */
17290075Sobrien	switch (nstate) {
17390075Sobrien	case IEEE80211_S_INIT:
174132718Skan		switch (ostate) {
17590075Sobrien		case IEEE80211_S_SCAN:
17690075Sobrien			ieee80211_cancel_scan(vap);
17790075Sobrien			break;
17890075Sobrien		case IEEE80211_S_CAC:
17990075Sobrien			ieee80211_dfs_cac_stop(vap);
18090075Sobrien			break;
18190075Sobrien		case IEEE80211_S_RUN:
18290075Sobrien			ieee80211_iterate_nodes(&ic->ic_sta, sta_disassoc, vap);
18390075Sobrien			break;
18490075Sobrien		default:
18590075Sobrien			break;
18690075Sobrien		}
18790075Sobrien		if (ostate != IEEE80211_S_INIT) {
18890075Sobrien			/* NB: optimize INIT -> INIT case */
18990075Sobrien			ieee80211_reset_bss(vap);
19090075Sobrien		}
19190075Sobrien		if (vap->iv_auth->ia_detach != NULL)
19290075Sobrien			vap->iv_auth->ia_detach(vap);
19390075Sobrien		break;
19490075Sobrien	case IEEE80211_S_SCAN:
19590075Sobrien		switch (ostate) {
19690075Sobrien		case IEEE80211_S_CSA:
19790075Sobrien		case IEEE80211_S_RUN:
19890075Sobrien			ieee80211_iterate_nodes(&ic->ic_sta, sta_disassoc, vap);
19990075Sobrien			/*
20090075Sobrien			 * Clear overlapping BSS state; the beacon frame
20190075Sobrien			 * will be reconstructed on transition to the RUN
20290075Sobrien			 * state and the timeout routines check if the flag
20390075Sobrien			 * is set before doing anything so this is sufficient.
20490075Sobrien			 */
20590075Sobrien			ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
20690075Sobrien			ic->ic_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
20790075Sobrien			/* fall thru... */
20890075Sobrien		case IEEE80211_S_CAC:
20990075Sobrien			/*
21090075Sobrien			 * NB: We may get here because of a manual channel
21190075Sobrien			 *     change in which case we need to stop CAC
21290075Sobrien			 * XXX no need to stop if ostate RUN but it's ok
21390075Sobrien			 */
21490075Sobrien			ieee80211_dfs_cac_stop(vap);
21590075Sobrien			/* fall thru... */
21690075Sobrien		case IEEE80211_S_INIT:
21790075Sobrien			if (vap->iv_des_chan != IEEE80211_CHAN_ANYC &&
21890075Sobrien			    !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
21990075Sobrien				/*
22090075Sobrien				 * Already have a channel; bypass the
22190075Sobrien				 * scan and startup immediately.
22290075Sobrien				 * ieee80211_create_ibss will call back to
22390075Sobrien				 * move us to RUN state.
22490075Sobrien				 */
22590075Sobrien				ieee80211_create_ibss(vap, vap->iv_des_chan);
22690075Sobrien				break;
22790075Sobrien			}
22890075Sobrien			/*
22990075Sobrien			 * Initiate a scan.  We can come here as a result
23090075Sobrien			 * of an IEEE80211_IOC_SCAN_REQ too in which case
23190075Sobrien			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
23290075Sobrien			 * and the scan request parameters will be present
23390075Sobrien			 * in iv_scanreq.  Otherwise we do the default.
23490075Sobrien			 */
235117395Skan			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
23690075Sobrien				ieee80211_check_scan(vap,
23790075Sobrien				    vap->iv_scanreq_flags,
238117395Skan				    vap->iv_scanreq_duration,
23990075Sobrien				    vap->iv_scanreq_mindwell,
24090075Sobrien				    vap->iv_scanreq_maxdwell,
24190075Sobrien				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
24290075Sobrien				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
24390075Sobrien			} else
24490075Sobrien				ieee80211_check_scan_current(vap);
24590075Sobrien			break;
24690075Sobrien		case IEEE80211_S_SCAN:
24790075Sobrien			/*
24890075Sobrien			 * A state change requires a reset; scan.
249117395Skan			 */
25090075Sobrien			ieee80211_check_scan_current(vap);
25196263Sobrien			break;
25290075Sobrien		default:
253117395Skan			break;
254117395Skan		}
255117395Skan		break;
256117395Skan	case IEEE80211_S_CAC:
257117395Skan		/*
258117395Skan		 * Start CAC on a DFS channel.  We come here when starting
259117395Skan		 * a bss on a DFS channel (see ieee80211_create_ibss).
260117395Skan		 */
261117395Skan		ieee80211_dfs_cac_start(vap);
262117395Skan		break;
263117395Skan	case IEEE80211_S_RUN:
264117395Skan		if (vap->iv_flags & IEEE80211_F_WPA) {
265117395Skan			/* XXX validate prerequisites */
266117395Skan		}
267117395Skan		switch (ostate) {
26890075Sobrien		case IEEE80211_S_INIT:
26990075Sobrien			/*
27090075Sobrien			 * Already have a channel; bypass the
27190075Sobrien			 * scan and startup immediately.
27290075Sobrien			 * Note that ieee80211_create_ibss will call
27390075Sobrien			 * back to do a RUN->RUN state change.
27490075Sobrien			 */
27590075Sobrien			ieee80211_create_ibss(vap,
27690075Sobrien			    ieee80211_ht_adjust_channel(ic,
27790075Sobrien				ic->ic_curchan, vap->iv_flags_ht));
27890075Sobrien			/* NB: iv_bss is changed on return */
27990075Sobrien			break;
28090075Sobrien		case IEEE80211_S_CAC:
28190075Sobrien			/*
28290075Sobrien			 * NB: This is the normal state change when CAC
283132718Skan			 * expires and no radar was detected; no need to
284169689Skan			 * clear the CAC timer as it's already expired.
28590075Sobrien			 */
286132718Skan			/* fall thru... */
287169689Skan		case IEEE80211_S_CSA:
28890075Sobrien			/*
28990075Sobrien			 * Shorten inactivity timer of associated stations
29090075Sobrien			 * to weed out sta's that don't follow a CSA.
29190075Sobrien			 */
29290075Sobrien			ieee80211_iterate_nodes(&ic->ic_sta, sta_csa, vap);
29390075Sobrien			/*
29490075Sobrien			 * Update bss node channel to reflect where
29590075Sobrien			 * we landed after CSA.
29690075Sobrien			 */
29790075Sobrien			ieee80211_node_set_chan(vap->iv_bss,
29890075Sobrien			    ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
29990075Sobrien				ieee80211_htchanflags(vap->iv_bss->ni_chan)));
30090075Sobrien			/* XXX bypass debug msgs */
30190075Sobrien			break;
30290075Sobrien		case IEEE80211_S_SCAN:
30390075Sobrien		case IEEE80211_S_RUN:
30490075Sobrien#ifdef IEEE80211_DEBUG
30590075Sobrien			if (ieee80211_msg_debug(vap)) {
30690075Sobrien				struct ieee80211_node *ni = vap->iv_bss;
30790075Sobrien				ieee80211_note(vap,
30890075Sobrien				    "synchronized with %s ssid ",
30990075Sobrien				    ether_sprintf(ni->ni_bssid));
31090075Sobrien				ieee80211_print_essid(ni->ni_essid,
31190075Sobrien				    ni->ni_esslen);
31290075Sobrien				/* XXX MCS/HT */
31390075Sobrien				printf(" channel %d start %uMb\n",
31490075Sobrien				    ieee80211_chan2ieee(ic, ic->ic_curchan),
31590075Sobrien				    IEEE80211_RATE2MBS(ni->ni_txrate));
31696263Sobrien			}
31790075Sobrien#endif
31890075Sobrien			break;
31990075Sobrien		default:
32090075Sobrien			break;
321122180Skan		}
32290075Sobrien		/*
32390075Sobrien		 * Start/stop the authenticator.  We delay until here
32490075Sobrien		 * to allow configuration to happen out of order.
32590075Sobrien		 */
32690075Sobrien		if (vap->iv_auth->ia_attach != NULL) {
327169689Skan			/* XXX check failure */
32890075Sobrien			vap->iv_auth->ia_attach(vap);
32990075Sobrien		} else if (vap->iv_auth->ia_detach != NULL) {
33090075Sobrien			vap->iv_auth->ia_detach(vap);
331122180Skan		}
33290075Sobrien		ieee80211_node_authorize(vap->iv_bss);
33390075Sobrien		break;
33490075Sobrien	case IEEE80211_S_CSA:
33590075Sobrien		if (ostate == IEEE80211_S_RUN && isbandchange(ic)) {
33690075Sobrien			/*
33790075Sobrien			 * On a ``band change'' silently drop associated
33890075Sobrien			 * stations as they must re-associate before they
33990075Sobrien			 * can pass traffic (as otherwise protocol state
34090075Sobrien			 * such as capabilities and the negotiated rate
341122180Skan			 * set may/will be wrong).
342122180Skan			 */
343122180Skan			ieee80211_iterate_nodes(&ic->ic_sta, sta_drop, vap);
344122180Skan		}
345122180Skan		break;
34690075Sobrien	default:
34790075Sobrien		break;
34890075Sobrien	}
34990075Sobrien	return 0;
35090075Sobrien}
35190075Sobrien
35290075Sobrienstatic void
35390075Sobrienhostap_deliver_data(struct ieee80211vap *vap,
35490075Sobrien	struct ieee80211_node *ni, struct mbuf *m)
35590075Sobrien{
35690075Sobrien	struct ether_header *eh = mtod(m, struct ether_header *);
35790075Sobrien	struct ifnet *ifp = vap->iv_ifp;
35890075Sobrien
35990075Sobrien	/* clear driver/net80211 flags before passing up */
36090075Sobrien	m->m_flags &= ~(M_MCAST | M_BCAST);
36190075Sobrien	m_clrprotoflags(m);
36290075Sobrien
36390075Sobrien	KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP,
36490075Sobrien	    ("gack, opmode %d", vap->iv_opmode));
36590075Sobrien	/*
36690075Sobrien	 * Do accounting.
36790075Sobrien	 */
36890075Sobrien	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
36990075Sobrien	IEEE80211_NODE_STAT(ni, rx_data);
37090075Sobrien	IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
37190075Sobrien	if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
37290075Sobrien		m->m_flags |= M_MCAST;		/* XXX M_BCAST? */
37390075Sobrien		IEEE80211_NODE_STAT(ni, rx_mcast);
37490075Sobrien	} else
37590075Sobrien		IEEE80211_NODE_STAT(ni, rx_ucast);
37690075Sobrien
37796263Sobrien	/* perform as a bridge within the AP */
37890075Sobrien	if ((vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0) {
37990075Sobrien		struct mbuf *mcopy = NULL;
38090075Sobrien
38190075Sobrien		if (m->m_flags & M_MCAST) {
38290075Sobrien			mcopy = m_dup(m, M_NOWAIT);
38390075Sobrien			if (mcopy == NULL)
38490075Sobrien				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
38590075Sobrien			else
38690075Sobrien				mcopy->m_flags |= M_MCAST;
38790075Sobrien		} else {
38890075Sobrien			/*
38990075Sobrien			 * Check if the destination is associated with the
39090075Sobrien			 * same vap and authorized to receive traffic.
39190075Sobrien			 * Beware of traffic destined for the vap itself;
39290075Sobrien			 * sending it will not work; just let it be delivered
39390075Sobrien			 * normally.
39490075Sobrien			 */
39590075Sobrien			struct ieee80211_node *sta = ieee80211_find_vap_node(
39690075Sobrien			     &vap->iv_ic->ic_sta, vap, eh->ether_dhost);
39790075Sobrien			if (sta != NULL) {
39890075Sobrien				if (ieee80211_node_is_authorized(sta)) {
39990075Sobrien					/*
40090075Sobrien					 * Beware of sending to ourself; this
40190075Sobrien					 * needs to happen via the normal
40290075Sobrien					 * input path.
40390075Sobrien					 */
40490075Sobrien					if (sta != vap->iv_bss) {
40590075Sobrien						mcopy = m;
40690075Sobrien						m = NULL;
40790075Sobrien					}
408122180Skan				} else {
409122180Skan					vap->iv_stats.is_rx_unauth++;
41090075Sobrien					IEEE80211_NODE_STAT(sta, rx_unauth);
41190075Sobrien				}
41290075Sobrien				ieee80211_free_node(sta);
41390075Sobrien			}
41490075Sobrien		}
41590075Sobrien		if (mcopy != NULL) {
41690075Sobrien			int len, err;
41790075Sobrien			len = mcopy->m_pkthdr.len;
41890075Sobrien			err = ieee80211_vap_xmitpkt(vap, mcopy);
41990075Sobrien			if (err) {
42090075Sobrien				/* NB: IFQ_HANDOFF reclaims mcopy */
42190075Sobrien			} else {
42290075Sobrien				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
42390075Sobrien			}
42490075Sobrien		}
42590075Sobrien	}
42690075Sobrien	if (m != NULL) {
42790075Sobrien		/*
42890075Sobrien		 * Mark frame as coming from vap's interface.
42990075Sobrien		 */
43090075Sobrien		m->m_pkthdr.rcvif = ifp;
43190075Sobrien		if (m->m_flags & M_MCAST) {
43290075Sobrien			/*
43390075Sobrien			 * Spam DWDS vap's w/ multicast traffic.
43490075Sobrien			 */
43590075Sobrien			/* XXX only if dwds in use? */
43690075Sobrien			ieee80211_dwds_mcast(vap, m);
43790075Sobrien		}
43890075Sobrien		if (ni->ni_vlan != 0) {
43990075Sobrien			/* attach vlan tag */
44090075Sobrien			m->m_pkthdr.ether_vtag = ni->ni_vlan;
44190075Sobrien			m->m_flags |= M_VLANTAG;
44290075Sobrien		}
443122180Skan		ifp->if_input(ifp, m);
444122180Skan	}
44590075Sobrien}
44690075Sobrien
44796263Sobrien/*
44890075Sobrien * Decide if a received management frame should be
44996263Sobrien * printed when debugging is enabled.  This filters some
45090075Sobrien * of the less interesting frames that come frequently
45196263Sobrien * (e.g. beacons).
452132718Skan */
45390075Sobrienstatic __inline int
45490075Sobriendoprint(struct ieee80211vap *vap, int subtype)
45590075Sobrien{
45690075Sobrien	switch (subtype) {
457169689Skan	case IEEE80211_FC0_SUBTYPE_BEACON:
45890075Sobrien		return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN);
45990075Sobrien	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
46090075Sobrien		return 0;
46190075Sobrien	}
46290075Sobrien	return 1;
46390075Sobrien}
46490075Sobrien
46590075Sobrien/*
466169689Skan * Process a received frame.  The node associated with the sender
46790075Sobrien * should be supplied.  If nothing was found in the node table then
46890075Sobrien * the caller is assumed to supply a reference to iv_bss instead.
46990075Sobrien * The RSSI and a timestamp are also supplied.  The RSSI data is used
47090075Sobrien * during AP scanning to select a AP to associate with; it can have
47190075Sobrien * any units so long as values have consistent units and higher values
47290075Sobrien * mean ``better signal''.  The receive timestamp is currently not used
47390075Sobrien * by the 802.11 layer.
47490075Sobrien */
475169689Skanstatic int
47690075Sobrienhostap_input(struct ieee80211_node *ni, struct mbuf *m,
47790075Sobrien    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
47890075Sobrien{
47990075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
48090075Sobrien	struct ieee80211com *ic = ni->ni_ic;
481122180Skan	struct ifnet *ifp = vap->iv_ifp;
482122180Skan	struct ieee80211_frame *wh;
48390075Sobrien	struct ieee80211_key *key;
48490075Sobrien	struct ether_header *eh;
48590075Sobrien	int hdrspace, need_tap = 1;	/* mbuf need to be tapped. */
48690075Sobrien	uint8_t dir, type, subtype, qos;
48790075Sobrien	uint8_t *bssid;
48890075Sobrien
48990075Sobrien	if (m->m_flags & M_AMPDU_MPDU) {
49090075Sobrien		/*
49190075Sobrien		 * Fastpath for A-MPDU reorder q resubmission.  Frames
49290075Sobrien		 * w/ M_AMPDU_MPDU marked have already passed through
49390075Sobrien		 * here but were received out of order and been held on
49490075Sobrien		 * the reorder queue.  When resubmitted they are marked
49590075Sobrien		 * with the M_AMPDU_MPDU flag and we can bypass most of
49690075Sobrien		 * the normal processing.
49790075Sobrien		 */
49890075Sobrien		wh = mtod(m, struct ieee80211_frame *);
49990075Sobrien		type = IEEE80211_FC0_TYPE_DATA;
50090075Sobrien		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
50190075Sobrien		subtype = IEEE80211_FC0_SUBTYPE_QOS;
50290075Sobrien		hdrspace = ieee80211_hdrspace(ic, wh);	/* XXX optimize? */
50390075Sobrien		goto resubmit_ampdu;
50490075Sobrien	}
50590075Sobrien
50690075Sobrien	KASSERT(ni != NULL, ("null node"));
50790075Sobrien	ni->ni_inact = ni->ni_inact_reload;
50890075Sobrien
509169689Skan	type = -1;			/* undefined */
51090075Sobrien
51190075Sobrien	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
51290075Sobrien		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
51390075Sobrien		    ni->ni_macaddr, NULL,
51490075Sobrien		    "too short (1): len %u", m->m_pkthdr.len);
51590075Sobrien		vap->iv_stats.is_rx_tooshort++;
516132718Skan		goto out;
51790075Sobrien	}
51890075Sobrien	/*
51990075Sobrien	 * Bit of a cheat here, we use a pointer for a 3-address
52090075Sobrien	 * frame format but don't reference fields past outside
52190075Sobrien	 * ieee80211_frame_min w/o first validating the data is
52290075Sobrien	 * present.
52390075Sobrien	 */
52490075Sobrien	wh = mtod(m, struct ieee80211_frame *);
52590075Sobrien
52690075Sobrien	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
52790075Sobrien	    IEEE80211_FC0_VERSION_0) {
52890075Sobrien		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
52990075Sobrien		    ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x",
53090075Sobrien		    wh->i_fc[0], wh->i_fc[1]);
53190075Sobrien		vap->iv_stats.is_rx_badversion++;
53290075Sobrien		goto err;
53390075Sobrien	}
53490075Sobrien
53590075Sobrien	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
53690075Sobrien	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
53790075Sobrien	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
53890075Sobrien	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
53990075Sobrien		if (dir != IEEE80211_FC1_DIR_NODS)
54090075Sobrien			bssid = wh->i_addr1;
54190075Sobrien		else if (type == IEEE80211_FC0_TYPE_CTL)
54290075Sobrien			bssid = wh->i_addr1;
54390075Sobrien		else {
54490075Sobrien			if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
54590075Sobrien				IEEE80211_DISCARD_MAC(vap,
54690075Sobrien				    IEEE80211_MSG_ANY, ni->ni_macaddr,
54790075Sobrien				    NULL, "too short (2): len %u",
54890075Sobrien				    m->m_pkthdr.len);
54990075Sobrien				vap->iv_stats.is_rx_tooshort++;
55090075Sobrien				goto out;
55190075Sobrien			}
55290075Sobrien			bssid = wh->i_addr3;
55390075Sobrien		}
55490075Sobrien		/*
55590075Sobrien		 * Validate the bssid.
55690075Sobrien		 */
55790075Sobrien		if (!(type == IEEE80211_FC0_TYPE_MGT &&
55890075Sobrien		      subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
55990075Sobrien		    !IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) &&
56090075Sobrien		    !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) {
56190075Sobrien			/* not interested in */
56290075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
56390075Sobrien			    bssid, NULL, "%s", "not to bss");
56490075Sobrien			vap->iv_stats.is_rx_wrongbss++;
56590075Sobrien			goto out;
56690075Sobrien		}
56790075Sobrien
56890075Sobrien		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
56990075Sobrien		ni->ni_noise = nf;
57090075Sobrien		if (IEEE80211_HAS_SEQ(type, subtype)) {
57190075Sobrien			uint8_t tid = ieee80211_gettid(wh);
57290075Sobrien			if (IEEE80211_QOS_HAS_SEQ(wh) &&
57390075Sobrien			    TID_TO_WME_AC(tid) >= WME_AC_VI)
57490075Sobrien				ic->ic_wme.wme_hipri_traffic++;
57590075Sobrien			if (! ieee80211_check_rxseq(ni, wh, bssid))
57690075Sobrien				goto out;
57790075Sobrien		}
57890075Sobrien	}
57990075Sobrien
58090075Sobrien	switch (type) {
58190075Sobrien	case IEEE80211_FC0_TYPE_DATA:
58290075Sobrien		hdrspace = ieee80211_hdrspace(ic, wh);
58390075Sobrien		if (m->m_len < hdrspace &&
58490075Sobrien		    (m = m_pullup(m, hdrspace)) == NULL) {
58590075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
58690075Sobrien			    ni->ni_macaddr, NULL,
58790075Sobrien			    "data too short: expecting %u", hdrspace);
58890075Sobrien			vap->iv_stats.is_rx_tooshort++;
58990075Sobrien			goto out;		/* XXX */
59090075Sobrien		}
59190075Sobrien		if (!(dir == IEEE80211_FC1_DIR_TODS ||
59290075Sobrien		     (dir == IEEE80211_FC1_DIR_DSTODS &&
59390075Sobrien		      (vap->iv_flags & IEEE80211_F_DWDS)))) {
59490075Sobrien			if (dir != IEEE80211_FC1_DIR_DSTODS) {
59590075Sobrien				IEEE80211_DISCARD(vap,
59690075Sobrien				    IEEE80211_MSG_INPUT, wh, "data",
59790075Sobrien				    "incorrect dir 0x%x", dir);
59890075Sobrien			} else {
59990075Sobrien				IEEE80211_DISCARD(vap,
60090075Sobrien				    IEEE80211_MSG_INPUT |
60190075Sobrien				    IEEE80211_MSG_WDS, wh,
60290075Sobrien				    "4-address data",
60390075Sobrien				    "%s", "DWDS not enabled");
60490075Sobrien			}
60590075Sobrien			vap->iv_stats.is_rx_wrongdir++;
60690075Sobrien			goto out;
60790075Sobrien		}
60890075Sobrien		/* check if source STA is associated */
60990075Sobrien		if (ni == vap->iv_bss) {
61090075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
61190075Sobrien			    wh, "data", "%s", "unknown src");
61290075Sobrien			ieee80211_send_error(ni, wh->i_addr2,
61390075Sobrien			    IEEE80211_FC0_SUBTYPE_DEAUTH,
61490075Sobrien			    IEEE80211_REASON_NOT_AUTHED);
61590075Sobrien			vap->iv_stats.is_rx_notassoc++;
61690075Sobrien			goto err;
61790075Sobrien		}
61890075Sobrien		if (ni->ni_associd == 0) {
61990075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
62090075Sobrien			    wh, "data", "%s", "unassoc src");
62190075Sobrien			IEEE80211_SEND_MGMT(ni,
62290075Sobrien			    IEEE80211_FC0_SUBTYPE_DISASSOC,
62390075Sobrien			    IEEE80211_REASON_NOT_ASSOCED);
62490075Sobrien			vap->iv_stats.is_rx_notassoc++;
62590075Sobrien			goto err;
626122180Skan		}
62790075Sobrien
62890075Sobrien		/*
62990075Sobrien		 * Check for power save state change.
63090075Sobrien		 * XXX out-of-order A-MPDU frames?
63190075Sobrien		 */
63290075Sobrien		if (((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^
63390075Sobrien		    (ni->ni_flags & IEEE80211_NODE_PWR_MGT)))
63490075Sobrien			vap->iv_node_ps(ni,
63590075Sobrien				wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);
63690075Sobrien		/*
63790075Sobrien		 * For 4-address packets handle WDS discovery
63890075Sobrien		 * notifications.  Once a WDS link is setup frames
63990075Sobrien		 * are just delivered to the WDS vap (see below).
64090075Sobrien		 */
64190075Sobrien		if (dir == IEEE80211_FC1_DIR_DSTODS && ni->ni_wdsvap == NULL) {
64290075Sobrien			if (!ieee80211_node_is_authorized(ni)) {
64390075Sobrien				IEEE80211_DISCARD(vap,
644132718Skan				    IEEE80211_MSG_INPUT |
645169689Skan				    IEEE80211_MSG_WDS, wh,
64690075Sobrien				    "4-address data",
64790075Sobrien				    "%s", "unauthorized port");
64890075Sobrien				vap->iv_stats.is_rx_unauth++;
64990075Sobrien				IEEE80211_NODE_STAT(ni, rx_unauth);
65090075Sobrien				goto err;
65190075Sobrien			}
65290075Sobrien			ieee80211_dwds_discover(ni, m);
65390075Sobrien			return type;
65490075Sobrien		}
65590075Sobrien
656132718Skan		/*
65790075Sobrien		 * Handle A-MPDU re-ordering.  If the frame is to be
65890075Sobrien		 * processed directly then ieee80211_ampdu_reorder
659169689Skan		 * will return 0; otherwise it has consumed the mbuf
660169689Skan		 * and we should do nothing more with it.
66190075Sobrien		 */
66290075Sobrien		if ((m->m_flags & M_AMPDU) &&
66390075Sobrien		    ieee80211_ampdu_reorder(ni, m) != 0) {
66490075Sobrien			m = NULL;
66590075Sobrien			goto out;
66690075Sobrien		}
66790075Sobrien	resubmit_ampdu:
66890075Sobrien
66990075Sobrien		/*
67090075Sobrien		 * Handle privacy requirements.  Note that we
67190075Sobrien		 * must not be preempted from here until after
67290075Sobrien		 * we (potentially) call ieee80211_crypto_demic;
673132718Skan		 * otherwise we may violate assumptions in the
67490075Sobrien		 * crypto cipher modules used to do delayed update
67590075Sobrien		 * of replay sequence numbers.
67690075Sobrien		 */
677169689Skan		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
678169689Skan			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
67990075Sobrien				/*
680132718Skan				 * Discard encrypted frames when privacy is off.
681132718Skan				 */
682132718Skan				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
683132718Skan				    wh, "WEP", "%s", "PRIVACY off");
684132718Skan				vap->iv_stats.is_rx_noprivacy++;
685132718Skan				IEEE80211_NODE_STAT(ni, rx_noprivacy);
686132718Skan				goto out;
68790075Sobrien			}
68890075Sobrien			key = ieee80211_crypto_decap(ni, m, hdrspace);
68990075Sobrien			if (key == NULL) {
69090075Sobrien				/* NB: stats+msgs handled in crypto_decap */
69190075Sobrien				IEEE80211_NODE_STAT(ni, rx_wepfail);
69290075Sobrien				goto out;
69390075Sobrien			}
69490075Sobrien			wh = mtod(m, struct ieee80211_frame *);
69590075Sobrien			wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
69690075Sobrien		} else {
69790075Sobrien			/* XXX M_WEP and IEEE80211_F_PRIVACY */
69890075Sobrien			key = NULL;
69990075Sobrien		}
70090075Sobrien
70190075Sobrien		/*
70290075Sobrien		 * Save QoS bits for use below--before we strip the header.
70390075Sobrien		 */
70490075Sobrien		if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
70590075Sobrien			qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
70690075Sobrien			    ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
70790075Sobrien			    ((struct ieee80211_qosframe *)wh)->i_qos[0];
70890075Sobrien		} else
70990075Sobrien			qos = 0;
71090075Sobrien
71190075Sobrien		/*
71290075Sobrien		 * Next up, any fragmentation.
71390075Sobrien		 */
71490075Sobrien		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
71590075Sobrien			m = ieee80211_defrag(ni, m, hdrspace);
71690075Sobrien			if (m == NULL) {
71790075Sobrien				/* Fragment dropped or frame not complete yet */
71890075Sobrien				goto out;
71990075Sobrien			}
72090075Sobrien		}
72190075Sobrien		wh = NULL;		/* no longer valid, catch any uses */
72290075Sobrien
72390075Sobrien		/*
724169689Skan		 * Next strip any MSDU crypto bits.
72590075Sobrien		 */
72690075Sobrien		if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) {
72790075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
72890075Sobrien			    ni->ni_macaddr, "data", "%s", "demic error");
72990075Sobrien			vap->iv_stats.is_rx_demicfail++;
73090075Sobrien			IEEE80211_NODE_STAT(ni, rx_demicfail);
73190075Sobrien			goto out;
73290075Sobrien		}
73390075Sobrien		/* copy to listener after decrypt */
73490075Sobrien		if (ieee80211_radiotap_active_vap(vap))
73590075Sobrien			ieee80211_radiotap_rx(vap, m);
73690075Sobrien		need_tap = 0;
73790075Sobrien		/*
73890075Sobrien		 * Finally, strip the 802.11 header.
73990075Sobrien		 */
74090075Sobrien		m = ieee80211_decap(vap, m, hdrspace);
741169689Skan		if (m == NULL) {
74290075Sobrien			/* XXX mask bit to check for both */
74390075Sobrien			/* don't count Null data frames as errors */
74490075Sobrien			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA ||
74590075Sobrien			    subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)
74690075Sobrien				goto out;
74790075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
74890075Sobrien			    ni->ni_macaddr, "data", "%s", "decap error");
74990075Sobrien			vap->iv_stats.is_rx_decap++;
75090075Sobrien			IEEE80211_NODE_STAT(ni, rx_decap);
75190075Sobrien			goto err;
75290075Sobrien		}
75390075Sobrien		eh = mtod(m, struct ether_header *);
75490075Sobrien		if (!ieee80211_node_is_authorized(ni)) {
75590075Sobrien			/*
75690075Sobrien			 * Deny any non-PAE frames received prior to
75790075Sobrien			 * authorization.  For open/shared-key
75890075Sobrien			 * authentication the port is mark authorized
75990075Sobrien			 * after authentication completes.  For 802.1x
76090075Sobrien			 * the port is not marked authorized by the
76190075Sobrien			 * authenticator until the handshake has completed.
76290075Sobrien			 */
76390075Sobrien			if (eh->ether_type != htons(ETHERTYPE_PAE)) {
76490075Sobrien				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
765122180Skan				    eh->ether_shost, "data",
76690075Sobrien				    "unauthorized port: ether type 0x%x len %u",
76790075Sobrien				    eh->ether_type, m->m_pkthdr.len);
76890075Sobrien				vap->iv_stats.is_rx_unauth++;
769122180Skan				IEEE80211_NODE_STAT(ni, rx_unauth);
77090075Sobrien				goto err;
77190075Sobrien			}
77290075Sobrien		} else {
77390075Sobrien			/*
77490075Sobrien			 * When denying unencrypted frames, discard
77590075Sobrien			 * any non-PAE frames received without encryption.
77690075Sobrien			 */
777122180Skan			if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
778169689Skan			    (key == NULL && (m->m_flags & M_WEP) == 0) &&
779169689Skan			    eh->ether_type != htons(ETHERTYPE_PAE)) {
780169689Skan				/*
781169689Skan				 * Drop unencrypted frames.
78290075Sobrien				 */
78390075Sobrien				vap->iv_stats.is_rx_unencrypted++;
78490075Sobrien				IEEE80211_NODE_STAT(ni, rx_unencrypted);
78590075Sobrien				goto out;
78690075Sobrien			}
78790075Sobrien		}
78890075Sobrien		/* XXX require HT? */
789122180Skan		if (qos & IEEE80211_QOS_AMSDU) {
79090075Sobrien			m = ieee80211_decap_amsdu(ni, m);
79190075Sobrien			if (m == NULL)
79290075Sobrien				return IEEE80211_FC0_TYPE_DATA;
793122180Skan		} else {
79490075Sobrien#ifdef IEEE80211_SUPPORT_SUPERG
79590075Sobrien			m = ieee80211_decap_fastframe(vap, ni, m);
79690075Sobrien			if (m == NULL)
797122180Skan				return IEEE80211_FC0_TYPE_DATA;
79890075Sobrien#endif
79990075Sobrien		}
80090075Sobrien		if (dir == IEEE80211_FC1_DIR_DSTODS && ni->ni_wdsvap != NULL)
80190075Sobrien			ieee80211_deliver_data(ni->ni_wdsvap, ni, m);
80290075Sobrien		else
80390075Sobrien			hostap_deliver_data(vap, ni, m);
80490075Sobrien		return IEEE80211_FC0_TYPE_DATA;
80590075Sobrien
80690075Sobrien	case IEEE80211_FC0_TYPE_MGT:
80790075Sobrien		vap->iv_stats.is_rx_mgmt++;
80890075Sobrien		IEEE80211_NODE_STAT(ni, rx_mgmt);
809169689Skan		if (dir != IEEE80211_FC1_DIR_NODS) {
810169689Skan			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
81190075Sobrien			    wh, "mgt", "incorrect dir 0x%x", dir);
81290075Sobrien			vap->iv_stats.is_rx_wrongdir++;
81390075Sobrien			goto err;
81490075Sobrien		}
81590075Sobrien		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
81690075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
81790075Sobrien			    ni->ni_macaddr, "mgt", "too short: len %u",
81890075Sobrien			    m->m_pkthdr.len);
81990075Sobrien			vap->iv_stats.is_rx_tooshort++;
82090075Sobrien			goto out;
82190075Sobrien		}
82290075Sobrien		if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
82390075Sobrien			/* ensure return frames are unicast */
82490075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
82590075Sobrien			    wh, NULL, "source is multicast: %s",
82690075Sobrien			    ether_sprintf(wh->i_addr2));
82790075Sobrien			vap->iv_stats.is_rx_mgtdiscard++;	/* XXX stat */
82890075Sobrien			goto out;
82990075Sobrien		}
83090075Sobrien#ifdef IEEE80211_DEBUG
83190075Sobrien		if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) ||
83290075Sobrien		    ieee80211_msg_dumppkts(vap)) {
83390075Sobrien			if_printf(ifp, "received %s from %s rssi %d\n",
83490075Sobrien			    ieee80211_mgt_subtype_name[subtype >>
83590075Sobrien				IEEE80211_FC0_SUBTYPE_SHIFT],
83690075Sobrien			    ether_sprintf(wh->i_addr2), rssi);
83790075Sobrien		}
83890075Sobrien#endif
83990075Sobrien		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
84090075Sobrien			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
841169689Skan				/*
84290075Sobrien				 * Only shared key auth frames with a challenge
84390075Sobrien				 * should be encrypted, discard all others.
84490075Sobrien				 */
84590075Sobrien				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
84690075Sobrien				    wh, NULL,
84790075Sobrien				    "%s", "WEP set but not permitted");
84890075Sobrien				vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
84990075Sobrien				goto out;
85090075Sobrien			}
85190075Sobrien			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
85290075Sobrien				/*
85390075Sobrien				 * Discard encrypted frames when privacy is off.
85490075Sobrien				 */
85590075Sobrien				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
85690075Sobrien				    wh, NULL, "%s", "WEP set but PRIVACY off");
85790075Sobrien				vap->iv_stats.is_rx_noprivacy++;
85890075Sobrien				goto out;
85990075Sobrien			}
86090075Sobrien			hdrspace = ieee80211_hdrspace(ic, wh);
86190075Sobrien			key = ieee80211_crypto_decap(ni, m, hdrspace);
862169689Skan			if (key == NULL) {
86390075Sobrien				/* NB: stats+msgs handled in crypto_decap */
86490075Sobrien				goto out;
86590075Sobrien			}
86690075Sobrien			wh = mtod(m, struct ieee80211_frame *);
86790075Sobrien			wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
86890075Sobrien		}
86990075Sobrien		/*
87090075Sobrien		 * Pass the packet to radiotap before calling iv_recv_mgmt().
87190075Sobrien		 * Otherwise iv_recv_mgmt() might pass another packet to
87290075Sobrien		 * radiotap, resulting in out of order packet captures.
87390075Sobrien		 */
87490075Sobrien		if (ieee80211_radiotap_active_vap(vap))
87590075Sobrien			ieee80211_radiotap_rx(vap, m);
876117395Skan		need_tap = 0;
87790075Sobrien		vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
87890075Sobrien		goto out;
87990075Sobrien
88090075Sobrien	case IEEE80211_FC0_TYPE_CTL:
88190075Sobrien		vap->iv_stats.is_rx_ctl++;
882132718Skan		IEEE80211_NODE_STAT(ni, rx_ctrl);
88390075Sobrien		vap->iv_recv_ctl(ni, m, subtype);
88490075Sobrien		goto out;
885132718Skan	default:
88690075Sobrien		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
887169689Skan		    wh, "bad", "frame type 0x%x", type);
888169689Skan		/* should not come here */
889169689Skan		break;
89090075Sobrien	}
89190075Sobrienerr:
89290075Sobrien	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
89390075Sobrienout:
89490075Sobrien	if (m != NULL) {
89590075Sobrien		if (need_tap && ieee80211_radiotap_active_vap(vap))
89690075Sobrien			ieee80211_radiotap_rx(vap, m);
89790075Sobrien		m_freem(m);
898169689Skan	}
899169689Skan	return type;
90090075Sobrien}
90190075Sobrien
902169689Skanstatic void
903169689Skanhostap_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
90490075Sobrien    int rssi, int nf, uint16_t seq, uint16_t status)
905169689Skan{
906169689Skan	struct ieee80211vap *vap = ni->ni_vap;
907117395Skan
90890075Sobrien	KASSERT(vap->iv_state == IEEE80211_S_RUN, ("state %d", vap->iv_state));
90990075Sobrien
91090075Sobrien	if (ni->ni_authmode == IEEE80211_AUTH_SHARED) {
91190075Sobrien		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
91290075Sobrien		    ni->ni_macaddr, "open auth",
91390075Sobrien		    "bad sta auth mode %u", ni->ni_authmode);
91490075Sobrien		vap->iv_stats.is_rx_bad_auth++;	/* XXX */
91590075Sobrien		/*
91690075Sobrien		 * Clear any challenge text that may be there if
91790075Sobrien		 * a previous shared key auth failed and then an
91890075Sobrien		 * open auth is attempted.
91990075Sobrien		 */
92090075Sobrien		if (ni->ni_challenge != NULL) {
92190075Sobrien			IEEE80211_FREE(ni->ni_challenge, M_80211_NODE);
92290075Sobrien			ni->ni_challenge = NULL;
92390075Sobrien		}
92490075Sobrien		/* XXX hack to workaround calling convention */
92590075Sobrien		ieee80211_send_error(ni, wh->i_addr2,
92690075Sobrien		    IEEE80211_FC0_SUBTYPE_AUTH,
92790075Sobrien		    (seq + 1) | (IEEE80211_STATUS_ALG<<16));
92890075Sobrien		return;
92990075Sobrien	}
93090075Sobrien	if (seq != IEEE80211_AUTH_OPEN_REQUEST) {
93190075Sobrien		vap->iv_stats.is_rx_bad_auth++;
93290075Sobrien		return;
933169689Skan	}
93490075Sobrien	/* always accept open authentication requests */
93590075Sobrien	if (ni == vap->iv_bss) {
93690075Sobrien		ni = ieee80211_dup_bss(vap, wh->i_addr2);
93790075Sobrien		if (ni == NULL)
93890075Sobrien			return;
93990075Sobrien	} else if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0)
94090075Sobrien		(void) ieee80211_ref_node(ni);
94190075Sobrien	/*
94290075Sobrien	 * Mark the node as referenced to reflect that it's
94390075Sobrien	 * reference count has been bumped to insure it remains
944169689Skan	 * after the transaction completes.
94590075Sobrien	 */
94690075Sobrien	ni->ni_flags |= IEEE80211_NODE_AREF;
94790075Sobrien	/*
94890075Sobrien	 * Mark the node as requiring a valid association id
94990075Sobrien	 * before outbound traffic is permitted.
950169689Skan	 */
951169689Skan	ni->ni_flags |= IEEE80211_NODE_ASSOCID;
95290075Sobrien
953169689Skan	if (vap->iv_acl != NULL &&
954169689Skan	    vap->iv_acl->iac_getpolicy(vap) == IEEE80211_MACCMD_POLICY_RADIUS) {
955169689Skan		/*
956169689Skan		 * When the ACL policy is set to RADIUS we defer the
957169689Skan		 * authorization to a user agent.  Dispatch an event,
958169689Skan		 * a subsequent MLME call will decide the fate of the
95990075Sobrien		 * station.  If the user agent is not present then the
96090075Sobrien		 * node will be reclaimed due to inactivity.
96190075Sobrien		 */
96290075Sobrien		IEEE80211_NOTE_MAC(vap,
96390075Sobrien		    IEEE80211_MSG_AUTH | IEEE80211_MSG_ACL, ni->ni_macaddr,
96490075Sobrien		    "%s", "station authentication defered (radius acl)");
96590075Sobrien		ieee80211_notify_node_auth(ni);
966169689Skan	} else {
967169689Skan		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
968169689Skan		IEEE80211_NOTE_MAC(vap,
96990075Sobrien		    IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni->ni_macaddr,
97090075Sobrien		    "%s", "station authenticated (open)");
97190075Sobrien		/*
97290075Sobrien		 * When 802.1x is not in use mark the port
97390075Sobrien		 * authorized at this point so traffic can flow.
97490075Sobrien		 */
97590075Sobrien		if (ni->ni_authmode != IEEE80211_AUTH_8021X)
97690075Sobrien			ieee80211_node_authorize(ni);
97790075Sobrien	}
97890075Sobrien}
97990075Sobrien
98090075Sobrienstatic void
98190075Sobrienhostap_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
98290075Sobrien    uint8_t *frm, uint8_t *efrm, int rssi, int nf,
98390075Sobrien    uint16_t seq, uint16_t status)
98490075Sobrien{
98590075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
98690075Sobrien	uint8_t *challenge;
98790075Sobrien	int allocbs, estatus;
98890075Sobrien
98990075Sobrien	KASSERT(vap->iv_state == IEEE80211_S_RUN, ("state %d", vap->iv_state));
99090075Sobrien
99190075Sobrien	/*
99290075Sobrien	 * NB: this can happen as we allow pre-shared key
993122180Skan	 * authentication to be enabled w/o wep being turned
99490075Sobrien	 * on so that configuration of these can be done
99590075Sobrien	 * in any order.  It may be better to enforce the
99690075Sobrien	 * ordering in which case this check would just be
99790075Sobrien	 * for sanity/consistency.
99890075Sobrien	 */
99990075Sobrien	if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
100090075Sobrien		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
100190075Sobrien		    ni->ni_macaddr, "shared key auth",
100290075Sobrien		    "%s", " PRIVACY is disabled");
100390075Sobrien		estatus = IEEE80211_STATUS_ALG;
100490075Sobrien		goto bad;
100590075Sobrien	}
100690075Sobrien	/*
100790075Sobrien	 * Pre-shared key authentication is evil; accept
100890075Sobrien	 * it only if explicitly configured (it is supported
100990075Sobrien	 * mainly for compatibility with clients like Mac OS X).
101090075Sobrien	 */
101190075Sobrien	if (ni->ni_authmode != IEEE80211_AUTH_AUTO &&
101290075Sobrien	    ni->ni_authmode != IEEE80211_AUTH_SHARED) {
101390075Sobrien		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
101490075Sobrien		    ni->ni_macaddr, "shared key auth",
101590075Sobrien		    "bad sta auth mode %u", ni->ni_authmode);
101690075Sobrien		vap->iv_stats.is_rx_bad_auth++;	/* XXX maybe a unique error? */
101790075Sobrien		estatus = IEEE80211_STATUS_ALG;
101890075Sobrien		goto bad;
1019169689Skan	}
1020169689Skan
1021169689Skan	challenge = NULL;
102290075Sobrien	if (frm + 1 < efrm) {
1023169689Skan		if ((frm[1] + 2) > (efrm - frm)) {
1024169689Skan			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
1025169689Skan			    ni->ni_macaddr, "shared key auth",
102690075Sobrien			    "ie %d/%d too long",
102790075Sobrien			    frm[0], (frm[1] + 2) - (efrm - frm));
102890075Sobrien			vap->iv_stats.is_rx_bad_auth++;
102990075Sobrien			estatus = IEEE80211_STATUS_CHALLENGE;
103090075Sobrien			goto bad;
103190075Sobrien		}
103290075Sobrien		if (*frm == IEEE80211_ELEMID_CHALLENGE)
103390075Sobrien			challenge = frm;
103490075Sobrien		frm += frm[1] + 2;
103590075Sobrien	}
103690075Sobrien	switch (seq) {
103790075Sobrien	case IEEE80211_AUTH_SHARED_CHALLENGE:
103890075Sobrien	case IEEE80211_AUTH_SHARED_RESPONSE:
103990075Sobrien		if (challenge == NULL) {
104090075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
104190075Sobrien			    ni->ni_macaddr, "shared key auth",
104290075Sobrien			    "%s", "no challenge");
104390075Sobrien			vap->iv_stats.is_rx_bad_auth++;
104490075Sobrien			estatus = IEEE80211_STATUS_CHALLENGE;
104590075Sobrien			goto bad;
104690075Sobrien		}
104790075Sobrien		if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
104890075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
104990075Sobrien			    ni->ni_macaddr, "shared key auth",
105090075Sobrien			    "bad challenge len %d", challenge[1]);
105196263Sobrien			vap->iv_stats.is_rx_bad_auth++;
105296263Sobrien			estatus = IEEE80211_STATUS_CHALLENGE;
105396263Sobrien			goto bad;
105496263Sobrien		}
105596263Sobrien	default:
105696263Sobrien		break;
105796263Sobrien	}
105896263Sobrien	switch (seq) {
105990075Sobrien	case IEEE80211_AUTH_SHARED_REQUEST:
106090075Sobrien		if (ni == vap->iv_bss) {
106190075Sobrien			ni = ieee80211_dup_bss(vap, wh->i_addr2);
106290075Sobrien			if (ni == NULL) {
106390075Sobrien				/* NB: no way to return an error */
106490075Sobrien				return;
106590075Sobrien			}
106690075Sobrien			allocbs = 1;
106790075Sobrien		} else {
106890075Sobrien			if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0)
106990075Sobrien				(void) ieee80211_ref_node(ni);
107090075Sobrien			allocbs = 0;
107190075Sobrien		}
107290075Sobrien		/*
107390075Sobrien		 * Mark the node as referenced to reflect that it's
107490075Sobrien		 * reference count has been bumped to insure it remains
107590075Sobrien		 * after the transaction completes.
107690075Sobrien		 */
107790075Sobrien		ni->ni_flags |= IEEE80211_NODE_AREF;
107890075Sobrien		/*
107990075Sobrien		 * Mark the node as requiring a valid associatio id
108090075Sobrien		 * before outbound traffic is permitted.
108190075Sobrien		 */
108290075Sobrien		ni->ni_flags |= IEEE80211_NODE_ASSOCID;
108390075Sobrien		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
1084117395Skan		ni->ni_noise = nf;
108590075Sobrien		if (!ieee80211_alloc_challenge(ni)) {
108690075Sobrien			/* NB: don't return error so they rexmit */
108790075Sobrien			return;
108890075Sobrien		}
108990075Sobrien		get_random_bytes(ni->ni_challenge,
109090075Sobrien			IEEE80211_CHALLENGE_LEN);
109190075Sobrien		IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
109290075Sobrien		    ni, "shared key %sauth request", allocbs ? "" : "re");
109390075Sobrien		/*
109490075Sobrien		 * When the ACL policy is set to RADIUS we defer the
109590075Sobrien		 * authorization to a user agent.  Dispatch an event,
109690075Sobrien		 * a subsequent MLME call will decide the fate of the
109790075Sobrien		 * station.  If the user agent is not present then the
109890075Sobrien		 * node will be reclaimed due to inactivity.
109990075Sobrien		 */
110090075Sobrien		if (vap->iv_acl != NULL &&
110190075Sobrien		    vap->iv_acl->iac_getpolicy(vap) == IEEE80211_MACCMD_POLICY_RADIUS) {
110290075Sobrien			IEEE80211_NOTE_MAC(vap,
110390075Sobrien			    IEEE80211_MSG_AUTH | IEEE80211_MSG_ACL,
110490075Sobrien			    ni->ni_macaddr,
110590075Sobrien			    "%s", "station authentication defered (radius acl)");
110690075Sobrien			ieee80211_notify_node_auth(ni);
110790075Sobrien			return;
110890075Sobrien		}
110990075Sobrien		break;
111090075Sobrien	case IEEE80211_AUTH_SHARED_RESPONSE:
111190075Sobrien		if (ni == vap->iv_bss) {
111290075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
111390075Sobrien			    ni->ni_macaddr, "shared key response",
111490075Sobrien			    "%s", "unknown station");
111590075Sobrien			/* NB: don't send a response */
111690075Sobrien			return;
111790075Sobrien		}
111890075Sobrien		if (ni->ni_challenge == NULL) {
111990075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
112090075Sobrien			    ni->ni_macaddr, "shared key response",
112190075Sobrien			    "%s", "no challenge recorded");
112290075Sobrien			vap->iv_stats.is_rx_bad_auth++;
112390075Sobrien			estatus = IEEE80211_STATUS_CHALLENGE;
112490075Sobrien			goto bad;
112590075Sobrien		}
112690075Sobrien		if (memcmp(ni->ni_challenge, &challenge[2],
112790075Sobrien			   challenge[1]) != 0) {
112890075Sobrien			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
112990075Sobrien			    ni->ni_macaddr, "shared key response",
113090075Sobrien			    "%s", "challenge mismatch");
113190075Sobrien			vap->iv_stats.is_rx_auth_fail++;
113290075Sobrien			estatus = IEEE80211_STATUS_CHALLENGE;
113390075Sobrien			goto bad;
113490075Sobrien		}
113590075Sobrien		IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
113690075Sobrien		    ni, "%s", "station authenticated (shared key)");
113790075Sobrien		ieee80211_node_authorize(ni);
113890075Sobrien		break;
113990075Sobrien	default:
114090075Sobrien		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
114190075Sobrien		    ni->ni_macaddr, "shared key auth",
114290075Sobrien		    "bad seq %d", seq);
114390075Sobrien		vap->iv_stats.is_rx_bad_auth++;
114490075Sobrien		estatus = IEEE80211_STATUS_SEQUENCE;
114596263Sobrien		goto bad;
114690075Sobrien	}
114790075Sobrien	IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
114890075Sobrien	return;
114990075Sobrienbad:
115090075Sobrien	/*
115190075Sobrien	 * Send an error response; but only when operating as an AP.
115290075Sobrien	 */
1153132718Skan	/* XXX hack to workaround calling convention */
115490075Sobrien	ieee80211_send_error(ni, wh->i_addr2,
115590075Sobrien	    IEEE80211_FC0_SUBTYPE_AUTH,
115696263Sobrien	    (seq + 1) | (estatus<<16));
115790075Sobrien}
115890075Sobrien
115990075Sobrien/*
116090075Sobrien * Convert a WPA cipher selector OUI to an internal
116190075Sobrien * cipher algorithm.  Where appropriate we also
116290075Sobrien * record any key length.
116390075Sobrien */
116490075Sobrienstatic int
116590075Sobrienwpa_cipher(const uint8_t *sel, uint8_t *keylen)
116690075Sobrien{
116790075Sobrien#define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
116890075Sobrien	uint32_t w = LE_READ_4(sel);
116990075Sobrien
117096263Sobrien	switch (w) {
117190075Sobrien	case WPA_SEL(WPA_CSE_NULL):
117290075Sobrien		return IEEE80211_CIPHER_NONE;
117390075Sobrien	case WPA_SEL(WPA_CSE_WEP40):
117490075Sobrien		if (keylen)
117590075Sobrien			*keylen = 40 / NBBY;
117690075Sobrien		return IEEE80211_CIPHER_WEP;
117790075Sobrien	case WPA_SEL(WPA_CSE_WEP104):
117890075Sobrien		if (keylen)
117990075Sobrien			*keylen = 104 / NBBY;
118090075Sobrien		return IEEE80211_CIPHER_WEP;
118190075Sobrien	case WPA_SEL(WPA_CSE_TKIP):
118290075Sobrien		return IEEE80211_CIPHER_TKIP;
118390075Sobrien	case WPA_SEL(WPA_CSE_CCMP):
118490075Sobrien		return IEEE80211_CIPHER_AES_CCM;
118590075Sobrien	}
1186169689Skan	return 32;		/* NB: so 1<< is discarded */
1187169689Skan#undef WPA_SEL
118890075Sobrien}
118990075Sobrien
1190169689Skan/*
119190075Sobrien * Convert a WPA key management/authentication algorithm
119290075Sobrien * to an internal code.
119390075Sobrien */
119490075Sobrienstatic int
119590075Sobrienwpa_keymgmt(const uint8_t *sel)
119690075Sobrien{
119790075Sobrien#define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
1198132718Skan	uint32_t w = LE_READ_4(sel);
119990075Sobrien
120090075Sobrien	switch (w) {
120190075Sobrien	case WPA_SEL(WPA_ASE_8021X_UNSPEC):
120290075Sobrien		return WPA_ASE_8021X_UNSPEC;
120390075Sobrien	case WPA_SEL(WPA_ASE_8021X_PSK):
120490075Sobrien		return WPA_ASE_8021X_PSK;
120590075Sobrien	case WPA_SEL(WPA_ASE_NONE):
120690075Sobrien		return WPA_ASE_NONE;
120790075Sobrien	}
120890075Sobrien	return 0;		/* NB: so is discarded */
120990075Sobrien#undef WPA_SEL
121090075Sobrien}
121190075Sobrien
121290075Sobrien/*
121390075Sobrien * Parse a WPA information element to collect parameters.
121490075Sobrien * Note that we do not validate security parameters; that
121590075Sobrien * is handled by the authenticator; the parsing done here
1216132718Skan * is just for internal use in making operational decisions.
121790075Sobrien */
121890075Sobrienstatic int
121990075Sobrienieee80211_parse_wpa(struct ieee80211vap *vap, const uint8_t *frm,
122090075Sobrien	struct ieee80211_rsnparms *rsn, const struct ieee80211_frame *wh)
122190075Sobrien{
122290075Sobrien	uint8_t len = frm[1];
122390075Sobrien	uint32_t w;
122496263Sobrien	int n;
122590075Sobrien
122690075Sobrien	/*
122790075Sobrien	 * Check the length once for fixed parts: OUI, type,
122890075Sobrien	 * version, mcast cipher, and 2 selector counts.
122990075Sobrien	 * Other, variable-length data, must be checked separately.
123090075Sobrien	 */
123190075Sobrien	if ((vap->iv_flags & IEEE80211_F_WPA1) == 0) {
123290075Sobrien		IEEE80211_DISCARD_IE(vap,
123390075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
123490075Sobrien		    wh, "WPA", "not WPA, flags 0x%x", vap->iv_flags);
123590075Sobrien		return IEEE80211_REASON_IE_INVALID;
123690075Sobrien	}
123790075Sobrien	if (len < 14) {
123890075Sobrien		IEEE80211_DISCARD_IE(vap,
123990075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
124090075Sobrien		    wh, "WPA", "too short, len %u", len);
124190075Sobrien		return IEEE80211_REASON_IE_INVALID;
124290075Sobrien	}
124390075Sobrien	frm += 6, len -= 4;		/* NB: len is payload only */
124490075Sobrien	/* NB: iswpaoui already validated the OUI and type */
124590075Sobrien	w = LE_READ_2(frm);
124690075Sobrien	if (w != WPA_VERSION) {
124790075Sobrien		IEEE80211_DISCARD_IE(vap,
124890075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
124990075Sobrien		    wh, "WPA", "bad version %u", w);
125090075Sobrien		return IEEE80211_REASON_IE_INVALID;
125190075Sobrien	}
125290075Sobrien	frm += 2, len -= 2;
125390075Sobrien
125490075Sobrien	memset(rsn, 0, sizeof(*rsn));
125590075Sobrien
125690075Sobrien	/* multicast/group cipher */
125790075Sobrien	rsn->rsn_mcastcipher = wpa_cipher(frm, &rsn->rsn_mcastkeylen);
125890075Sobrien	frm += 4, len -= 4;
125996263Sobrien
126096263Sobrien	/* unicast ciphers */
126196263Sobrien	n = LE_READ_2(frm);
126296263Sobrien	frm += 2, len -= 2;
126390075Sobrien	if (len < n*4+2) {
126490075Sobrien		IEEE80211_DISCARD_IE(vap,
126590075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
126690075Sobrien		    wh, "WPA", "ucast cipher data too short; len %u, n %u",
126790075Sobrien		    len, n);
126890075Sobrien		return IEEE80211_REASON_IE_INVALID;
1269117395Skan	}
1270117395Skan	w = 0;
1271117395Skan	for (; n > 0; n--) {
1272117395Skan		w |= 1<<wpa_cipher(frm, &rsn->rsn_ucastkeylen);
1273169689Skan		frm += 4, len -= 4;
127490075Sobrien	}
127590075Sobrien	if (w & (1<<IEEE80211_CIPHER_TKIP))
1276117395Skan		rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
1277117395Skan	else
127890075Sobrien		rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
127990075Sobrien
128090075Sobrien	/* key management algorithms */
128190075Sobrien	n = LE_READ_2(frm);
128290075Sobrien	frm += 2, len -= 2;
128390075Sobrien	if (len < n*4) {
128490075Sobrien		IEEE80211_DISCARD_IE(vap,
128590075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
128690075Sobrien		    wh, "WPA", "key mgmt alg data too short; len %u, n %u",
1287169689Skan		    len, n);
1288169689Skan		return IEEE80211_REASON_IE_INVALID;
128990075Sobrien	}
1290169689Skan	w = 0;
1291169689Skan	for (; n > 0; n--) {
129290075Sobrien		w |= wpa_keymgmt(frm);
129390075Sobrien		frm += 4, len -= 4;
129490075Sobrien	}
129590075Sobrien	if (w & WPA_ASE_8021X_UNSPEC)
129690075Sobrien		rsn->rsn_keymgmt = WPA_ASE_8021X_UNSPEC;
129790075Sobrien	else
129890075Sobrien		rsn->rsn_keymgmt = WPA_ASE_8021X_PSK;
129990075Sobrien
130090075Sobrien	if (len > 2)		/* optional capabilities */
130190075Sobrien		rsn->rsn_caps = LE_READ_2(frm);
130290075Sobrien
130390075Sobrien	return 0;
130490075Sobrien}
130590075Sobrien
130690075Sobrien/*
130790075Sobrien * Convert an RSN cipher selector OUI to an internal
130890075Sobrien * cipher algorithm.  Where appropriate we also
130990075Sobrien * record any key length.
131090075Sobrien */
131190075Sobrienstatic int
131290075Sobrienrsn_cipher(const uint8_t *sel, uint8_t *keylen)
131390075Sobrien{
131490075Sobrien#define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
131590075Sobrien	uint32_t w = LE_READ_4(sel);
131690075Sobrien
131790075Sobrien	switch (w) {
131890075Sobrien	case RSN_SEL(RSN_CSE_NULL):
131990075Sobrien		return IEEE80211_CIPHER_NONE;
132090075Sobrien	case RSN_SEL(RSN_CSE_WEP40):
132190075Sobrien		if (keylen)
132290075Sobrien			*keylen = 40 / NBBY;
132390075Sobrien		return IEEE80211_CIPHER_WEP;
132490075Sobrien	case RSN_SEL(RSN_CSE_WEP104):
132590075Sobrien		if (keylen)
132690075Sobrien			*keylen = 104 / NBBY;
132790075Sobrien		return IEEE80211_CIPHER_WEP;
132890075Sobrien	case RSN_SEL(RSN_CSE_TKIP):
132990075Sobrien		return IEEE80211_CIPHER_TKIP;
133090075Sobrien	case RSN_SEL(RSN_CSE_CCMP):
133190075Sobrien		return IEEE80211_CIPHER_AES_CCM;
133290075Sobrien	case RSN_SEL(RSN_CSE_WRAP):
133390075Sobrien		return IEEE80211_CIPHER_AES_OCB;
133490075Sobrien	}
133590075Sobrien	return 32;		/* NB: so 1<< is discarded */
133690075Sobrien#undef WPA_SEL
133790075Sobrien}
133890075Sobrien
133990075Sobrien/*
134090075Sobrien * Convert an RSN key management/authentication algorithm
134190075Sobrien * to an internal code.
134290075Sobrien */
134390075Sobrienstatic int
134490075Sobrienrsn_keymgmt(const uint8_t *sel)
134590075Sobrien{
134690075Sobrien#define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
134790075Sobrien	uint32_t w = LE_READ_4(sel);
134890075Sobrien
134990075Sobrien	switch (w) {
135090075Sobrien	case RSN_SEL(RSN_ASE_8021X_UNSPEC):
135190075Sobrien		return RSN_ASE_8021X_UNSPEC;
135290075Sobrien	case RSN_SEL(RSN_ASE_8021X_PSK):
135390075Sobrien		return RSN_ASE_8021X_PSK;
135490075Sobrien	case RSN_SEL(RSN_ASE_NONE):
135590075Sobrien		return RSN_ASE_NONE;
135690075Sobrien	}
135790075Sobrien	return 0;		/* NB: so is discarded */
135890075Sobrien#undef RSN_SEL
135990075Sobrien}
136090075Sobrien
136190075Sobrien/*
136290075Sobrien * Parse a WPA/RSN information element to collect parameters
136390075Sobrien * and validate the parameters against what has been
136490075Sobrien * configured for the system.
136590075Sobrien */
136690075Sobrienstatic int
136790075Sobrienieee80211_parse_rsn(struct ieee80211vap *vap, const uint8_t *frm,
136890075Sobrien	struct ieee80211_rsnparms *rsn, const struct ieee80211_frame *wh)
136990075Sobrien{
137090075Sobrien	uint8_t len = frm[1];
137190075Sobrien	uint32_t w;
137290075Sobrien	int n;
137390075Sobrien
137490075Sobrien	/*
137590075Sobrien	 * Check the length once for fixed parts:
137690075Sobrien	 * version, mcast cipher, and 2 selector counts.
137790075Sobrien	 * Other, variable-length data, must be checked separately.
137890075Sobrien	 */
137990075Sobrien	if ((vap->iv_flags & IEEE80211_F_WPA2) == 0) {
138090075Sobrien		IEEE80211_DISCARD_IE(vap,
138190075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
138290075Sobrien		    wh, "WPA", "not RSN, flags 0x%x", vap->iv_flags);
138390075Sobrien		return IEEE80211_REASON_IE_INVALID;
138490075Sobrien	}
138590075Sobrien	if (len < 10) {
138690075Sobrien		IEEE80211_DISCARD_IE(vap,
138790075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
138890075Sobrien		    wh, "RSN", "too short, len %u", len);
138990075Sobrien		return IEEE80211_REASON_IE_INVALID;
139090075Sobrien	}
139190075Sobrien	frm += 2;
139290075Sobrien	w = LE_READ_2(frm);
139390075Sobrien	if (w != RSN_VERSION) {
139490075Sobrien		IEEE80211_DISCARD_IE(vap,
139590075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
139690075Sobrien		    wh, "RSN", "bad version %u", w);
139790075Sobrien		return IEEE80211_REASON_IE_INVALID;
139890075Sobrien	}
139990075Sobrien	frm += 2, len -= 2;
140090075Sobrien
140190075Sobrien	memset(rsn, 0, sizeof(*rsn));
140290075Sobrien
140390075Sobrien	/* multicast/group cipher */
140490075Sobrien	rsn->rsn_mcastcipher = rsn_cipher(frm, &rsn->rsn_mcastkeylen);
140590075Sobrien	frm += 4, len -= 4;
140690075Sobrien
140790075Sobrien	/* unicast ciphers */
140890075Sobrien	n = LE_READ_2(frm);
140990075Sobrien	frm += 2, len -= 2;
141090075Sobrien	if (len < n*4+2) {
141190075Sobrien		IEEE80211_DISCARD_IE(vap,
141290075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
141390075Sobrien		    wh, "RSN", "ucast cipher data too short; len %u, n %u",
141490075Sobrien		    len, n);
141590075Sobrien		return IEEE80211_REASON_IE_INVALID;
1416169689Skan	}
141790075Sobrien	w = 0;
141890075Sobrien	for (; n > 0; n--) {
141990075Sobrien		w |= 1<<rsn_cipher(frm, &rsn->rsn_ucastkeylen);
142090075Sobrien		frm += 4, len -= 4;
142190075Sobrien	}
142290075Sobrien	if (w & (1<<IEEE80211_CIPHER_TKIP))
142390075Sobrien		rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
142490075Sobrien	else
142590075Sobrien		rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
142690075Sobrien
142790075Sobrien	/* key management algorithms */
142890075Sobrien	n = LE_READ_2(frm);
142990075Sobrien	frm += 2, len -= 2;
143090075Sobrien	if (len < n*4) {
143190075Sobrien		IEEE80211_DISCARD_IE(vap,
143290075Sobrien		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
143390075Sobrien		    wh, "RSN", "key mgmt alg data too short; len %u, n %u",
143490075Sobrien		    len, n);
143590075Sobrien		return IEEE80211_REASON_IE_INVALID;
1436169689Skan	}
143790075Sobrien	w = 0;
143890075Sobrien	for (; n > 0; n--) {
143990075Sobrien		w |= rsn_keymgmt(frm);
144096263Sobrien		frm += 4, len -= 4;
144190075Sobrien	}
144290075Sobrien	if (w & RSN_ASE_8021X_UNSPEC)
144390075Sobrien		rsn->rsn_keymgmt = RSN_ASE_8021X_UNSPEC;
144490075Sobrien	else
144590075Sobrien		rsn->rsn_keymgmt = RSN_ASE_8021X_PSK;
144690075Sobrien
144790075Sobrien	/* optional RSN capabilities */
144890075Sobrien	if (len > 2)
144990075Sobrien		rsn->rsn_caps = LE_READ_2(frm);
145090075Sobrien	/* XXXPMKID */
145190075Sobrien
145290075Sobrien	return 0;
145390075Sobrien}
145490075Sobrien
145590075Sobrien/*
145690075Sobrien * WPA/802.11i assocation request processing.
145790075Sobrien */
145890075Sobrienstatic int
145990075Sobrienwpa_assocreq(struct ieee80211_node *ni, struct ieee80211_rsnparms *rsnparms,
146090075Sobrien	const struct ieee80211_frame *wh, const uint8_t *wpa,
146190075Sobrien	const uint8_t *rsn, uint16_t capinfo)
146290075Sobrien{
146390075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
146490075Sobrien	uint8_t reason;
146590075Sobrien	int badwparsn;
146690075Sobrien
146790075Sobrien	ni->ni_flags &= ~(IEEE80211_NODE_WPS|IEEE80211_NODE_TSN);
146890075Sobrien	if (wpa == NULL && rsn == NULL) {
146990075Sobrien		if (vap->iv_flags_ext & IEEE80211_FEXT_WPS) {
147090075Sobrien			/*
147190075Sobrien			 * W-Fi Protected Setup (WPS) permits
147290075Sobrien			 * clients to associate and pass EAPOL frames
147390075Sobrien			 * to establish initial credentials.
147490075Sobrien			 */
147590075Sobrien			ni->ni_flags |= IEEE80211_NODE_WPS;
147690075Sobrien			return 1;
147790075Sobrien		}
147890075Sobrien		if ((vap->iv_flags_ext & IEEE80211_FEXT_TSN) &&
147990075Sobrien		    (capinfo & IEEE80211_CAPINFO_PRIVACY)) {
148090075Sobrien			/*
148190075Sobrien			 * Transitional Security Network.  Permits clients
148290075Sobrien			 * to associate and use WEP while WPA is configured.
148390075Sobrien			 */
148490075Sobrien			ni->ni_flags |= IEEE80211_NODE_TSN;
148590075Sobrien			return 1;
148690075Sobrien		}
148790075Sobrien		IEEE80211_DISCARD(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA,
148890075Sobrien		    wh, NULL, "%s", "no WPA/RSN IE in association request");
148990075Sobrien		vap->iv_stats.is_rx_assoc_badwpaie++;
149090075Sobrien		reason = IEEE80211_REASON_IE_INVALID;
149190075Sobrien		goto bad;
149290075Sobrien	}
149390075Sobrien	/* assert right association security credentials */
149490075Sobrien	badwparsn = 0;			/* NB: to silence compiler */
149590075Sobrien	switch (vap->iv_flags & IEEE80211_F_WPA) {
149690075Sobrien	case IEEE80211_F_WPA1:
149790075Sobrien		badwparsn = (wpa == NULL);
149890075Sobrien		break;
149990075Sobrien	case IEEE80211_F_WPA2:
150090075Sobrien		badwparsn = (rsn == NULL);
150190075Sobrien		break;
150290075Sobrien	case IEEE80211_F_WPA1|IEEE80211_F_WPA2:
150390075Sobrien		badwparsn = (wpa == NULL && rsn == NULL);
150490075Sobrien		break;
150590075Sobrien	}
150690075Sobrien	if (badwparsn) {
150790075Sobrien		IEEE80211_DISCARD(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA,
150890075Sobrien		    wh, NULL,
150990075Sobrien		    "%s", "missing WPA/RSN IE in association request");
151090075Sobrien		vap->iv_stats.is_rx_assoc_badwpaie++;
151190075Sobrien		reason = IEEE80211_REASON_IE_INVALID;
1512132718Skan		goto bad;
151390075Sobrien	}
151490075Sobrien	/*
151590075Sobrien	 * Parse WPA/RSN information element.
151690075Sobrien	 */
1517132718Skan	if (wpa != NULL)
151890075Sobrien		reason = ieee80211_parse_wpa(vap, wpa, rsnparms, wh);
151990075Sobrien	else
152090075Sobrien		reason = ieee80211_parse_rsn(vap, rsn, rsnparms, wh);
152190075Sobrien	if (reason != 0) {
152290075Sobrien		/* XXX distinguish WPA/RSN? */
152390075Sobrien		vap->iv_stats.is_rx_assoc_badwpaie++;
152490075Sobrien		goto bad;
152590075Sobrien	}
152690075Sobrien	IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA, ni,
152790075Sobrien	    "%s ie: mc %u/%u uc %u/%u key %u caps 0x%x",
152890075Sobrien	    wpa != NULL ? "WPA" : "RSN",
152990075Sobrien	    rsnparms->rsn_mcastcipher, rsnparms->rsn_mcastkeylen,
153090075Sobrien	    rsnparms->rsn_ucastcipher, rsnparms->rsn_ucastkeylen,
153190075Sobrien	    rsnparms->rsn_keymgmt, rsnparms->rsn_caps);
153290075Sobrien
153390075Sobrien	return 1;
153490075Sobrienbad:
153590075Sobrien	ieee80211_node_deauth(ni, reason);
153690075Sobrien	return 0;
153790075Sobrien}
153890075Sobrien
153990075Sobrien/* XXX find a better place for definition */
154090075Sobrienstruct l2_update_frame {
1541117395Skan	struct ether_header eh;
1542117395Skan	uint8_t dsap;
154390075Sobrien	uint8_t ssap;
154490075Sobrien	uint8_t control;
154590075Sobrien	uint8_t xid[3];
154690075Sobrien}  __packed;
154790075Sobrien
154890075Sobrien/*
154990075Sobrien * Deliver a TGf L2UF frame on behalf of a station.
155090075Sobrien * This primes any bridge when the station is roaming
155190075Sobrien * between ap's on the same wired network.
155290075Sobrien */
155390075Sobrienstatic void
155490075Sobrienieee80211_deliver_l2uf(struct ieee80211_node *ni)
155590075Sobrien{
155690075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
155790075Sobrien	struct ifnet *ifp = vap->iv_ifp;
155890075Sobrien	struct mbuf *m;
155990075Sobrien	struct l2_update_frame *l2uf;
156090075Sobrien	struct ether_header *eh;
1561132718Skan
156290075Sobrien	m = m_gethdr(M_NOWAIT, MT_DATA);
156390075Sobrien	if (m == NULL) {
156490075Sobrien		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
156590075Sobrien		    "%s", "no mbuf for l2uf frame");
156690075Sobrien		vap->iv_stats.is_rx_nobuf++;	/* XXX not right */
156790075Sobrien		return;
156890075Sobrien	}
156990075Sobrien	l2uf = mtod(m, struct l2_update_frame *);
157090075Sobrien	eh = &l2uf->eh;
157190075Sobrien	/* dst: Broadcast address */
157290075Sobrien	IEEE80211_ADDR_COPY(eh->ether_dhost, ifp->if_broadcastaddr);
157390075Sobrien	/* src: associated STA */
157490075Sobrien	IEEE80211_ADDR_COPY(eh->ether_shost, ni->ni_macaddr);
157590075Sobrien	eh->ether_type = htons(sizeof(*l2uf) - sizeof(*eh));
157690075Sobrien
157790075Sobrien	l2uf->dsap = 0;
157890075Sobrien	l2uf->ssap = 0;
157990075Sobrien	l2uf->control = 0xf5;
158090075Sobrien	l2uf->xid[0] = 0x81;
158190075Sobrien	l2uf->xid[1] = 0x80;
158290075Sobrien	l2uf->xid[2] = 0x00;
158390075Sobrien
158490075Sobrien	m->m_pkthdr.len = m->m_len = sizeof(*l2uf);
158590075Sobrien	hostap_deliver_data(vap, ni, m);
158690075Sobrien}
158790075Sobrien
1588132718Skanstatic void
158990075Sobrienratesetmismatch(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
159090075Sobrien	int reassoc, int resp, const char *tag, int rate)
159190075Sobrien{
159290075Sobrien	IEEE80211_NOTE_MAC(ni->ni_vap, IEEE80211_MSG_ANY, wh->i_addr2,
159390075Sobrien	    "deny %s request, %s rate set mismatch, rate/MCS %d",
159490075Sobrien	    reassoc ? "reassoc" : "assoc", tag, rate & IEEE80211_RATE_VAL);
159590075Sobrien	IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_BASIC_RATE);
159690075Sobrien	ieee80211_node_leave(ni);
159790075Sobrien}
159890075Sobrien
159990075Sobrienstatic void
160090075Sobriencapinfomismatch(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
160190075Sobrien	int reassoc, int resp, const char *tag, int capinfo)
160290075Sobrien{
160390075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
160490075Sobrien
160590075Sobrien	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ANY, wh->i_addr2,
160690075Sobrien	    "deny %s request, %s mismatch 0x%x",
160790075Sobrien	    reassoc ? "reassoc" : "assoc", tag, capinfo);
160890075Sobrien	IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_CAPINFO);
160990075Sobrien	ieee80211_node_leave(ni);
161090075Sobrien	vap->iv_stats.is_rx_assoc_capmismatch++;
161190075Sobrien}
161290075Sobrien
161390075Sobrienstatic void
161490075Sobrienhtcapmismatch(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
161590075Sobrien	int reassoc, int resp)
161690075Sobrien{
161790075Sobrien	IEEE80211_NOTE_MAC(ni->ni_vap, IEEE80211_MSG_ANY, wh->i_addr2,
161890075Sobrien	    "deny %s request, %s missing HT ie", reassoc ? "reassoc" : "assoc");
161990075Sobrien	/* XXX no better code */
162090075Sobrien	IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_MISSING_HT_CAPS);
162190075Sobrien	ieee80211_node_leave(ni);
162290075Sobrien}
162390075Sobrien
162490075Sobrienstatic void
162590075Sobrienauthalgreject(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
162690075Sobrien	int algo, int seq, int status)
162790075Sobrien{
162890075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
162990075Sobrien
163090075Sobrien	IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1631122180Skan	    wh, NULL, "unsupported alg %d", algo);
1632122180Skan	vap->iv_stats.is_rx_auth_unsupported++;
163390075Sobrien	ieee80211_send_error(ni, wh->i_addr2, IEEE80211_FC0_SUBTYPE_AUTH,
163490075Sobrien	    seq | (status << 16));
163590075Sobrien}
163690075Sobrien
163790075Sobrienstatic __inline int
163890075Sobrienishtmixed(const uint8_t *ie)
163990075Sobrien{
164090075Sobrien	const struct ieee80211_ie_htinfo *ht =
164190075Sobrien	    (const struct ieee80211_ie_htinfo *) ie;
164290075Sobrien	return (ht->hi_byte2 & IEEE80211_HTINFO_OPMODE) ==
164390075Sobrien	    IEEE80211_HTINFO_OPMODE_MIXED;
164490075Sobrien}
164590075Sobrien
164690075Sobrienstatic int
164790075Sobrienis11bclient(const uint8_t *rates, const uint8_t *xrates)
164890075Sobrien{
164990075Sobrien	static const uint32_t brates = (1<<2*1)|(1<<2*2)|(1<<11)|(1<<2*11);
165090075Sobrien	int i;
165190075Sobrien
165290075Sobrien	/* NB: the 11b clients we care about will not have xrates */
165390075Sobrien	if (xrates != NULL || rates == NULL)
165490075Sobrien		return 0;
165590075Sobrien	for (i = 0; i < rates[1]; i++) {
165690075Sobrien		int r = rates[2+i] & IEEE80211_RATE_VAL;
165790075Sobrien		if (r > 2*11 || ((1<<r) & brates) == 0)
165890075Sobrien			return 0;
165990075Sobrien	}
166090075Sobrien	return 1;
166190075Sobrien}
166290075Sobrien
166390075Sobrienstatic void
166490075Sobrienhostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
166590075Sobrien	int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
166690075Sobrien{
166790075Sobrien	struct ieee80211vap *vap = ni->ni_vap;
166890075Sobrien	struct ieee80211com *ic = ni->ni_ic;
166990075Sobrien	struct ieee80211_frame *wh;
167090075Sobrien	uint8_t *frm, *efrm, *sfrm;
167190075Sobrien	uint8_t *ssid, *rates, *xrates, *wpa, *rsn, *wme, *ath, *htcap;
167290075Sobrien	int reassoc, resp;
167390075Sobrien	uint8_t rate;
167490075Sobrien
167590075Sobrien	wh = mtod(m0, struct ieee80211_frame *);
167690075Sobrien	frm = (uint8_t *)&wh[1];
167790075Sobrien	efrm = mtod(m0, uint8_t *) + m0->m_len;
167890075Sobrien	switch (subtype) {
167990075Sobrien	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
168090075Sobrien	case IEEE80211_FC0_SUBTYPE_BEACON: {
168190075Sobrien		struct ieee80211_scanparams scan;
168290075Sobrien		/*
168390075Sobrien		 * We process beacon/probe response frames when scanning;
168490075Sobrien		 * otherwise we check beacon frames for overlapping non-ERP
168590075Sobrien		 * BSS in 11g and/or overlapping legacy BSS when in HT.
168690075Sobrien		 */
168790075Sobrien		if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
168890075Sobrien		    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
168990075Sobrien			vap->iv_stats.is_rx_mgtdiscard++;
169090075Sobrien			return;
169190075Sobrien		}
169290075Sobrien		/* NB: accept off-channel frames */
169390075Sobrien		/* XXX TODO: use rxstatus to determine off-channel details */
169490075Sobrien		if (ieee80211_parse_beacon(ni, m0, ic->ic_curchan, &scan) &~ IEEE80211_BPARSE_OFFCHAN)
169590075Sobrien			return;
169690075Sobrien		/*
169790075Sobrien		 * Count frame now that we know it's to be processed.
169890075Sobrien		 */
169990075Sobrien		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
170090075Sobrien			vap->iv_stats.is_rx_beacon++;		/* XXX remove */
170190075Sobrien			IEEE80211_NODE_STAT(ni, rx_beacons);
170290075Sobrien		} else
170390075Sobrien			IEEE80211_NODE_STAT(ni, rx_proberesp);
170490075Sobrien		/*
170590075Sobrien		 * If scanning, just pass information to the scan module.
170690075Sobrien		 */
170790075Sobrien		if (ic->ic_flags & IEEE80211_F_SCAN) {
170890075Sobrien			if (scan.status == 0 &&		/* NB: on channel */
170990075Sobrien			    (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN)) {
171090075Sobrien				/*
171190075Sobrien				 * Actively scanning a channel marked passive;
171290075Sobrien				 * send a probe request now that we know there
171390075Sobrien				 * is 802.11 traffic present.
171490075Sobrien				 *
171590075Sobrien				 * XXX check if the beacon we recv'd gives
171690075Sobrien				 * us what we need and suppress the probe req
171790075Sobrien				 */
171890075Sobrien				ieee80211_probe_curchan(vap, 1);
171990075Sobrien				ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
172090075Sobrien			}
172190075Sobrien			ieee80211_add_scan(vap, ic->ic_curchan, &scan, wh,
172290075Sobrien			    subtype, rssi, nf);
172390075Sobrien			return;
172490075Sobrien		}
172590075Sobrien		/*
172690075Sobrien		 * Check beacon for overlapping bss w/ non ERP stations.
172790075Sobrien		 * If we detect one and protection is configured but not
172890075Sobrien		 * enabled, enable it and start a timer that'll bring us
172990075Sobrien		 * out if we stop seeing the bss.
173090075Sobrien		 */
173190075Sobrien		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
173290075Sobrien		    scan.status == 0 &&			/* NB: on-channel */
173390075Sobrien		    ((scan.erp & 0x100) == 0 ||		/* NB: no ERP, 11b sta*/
173490075Sobrien		     (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) {
173590075Sobrien			ic->ic_lastnonerp = ticks;
173690075Sobrien			ic->ic_flags_ext |= IEEE80211_FEXT_NONERP_PR;
173790075Sobrien			if (ic->ic_protmode != IEEE80211_PROT_NONE &&
173890075Sobrien			    (ic->ic_flags & IEEE80211_F_USEPROT) == 0) {
173990075Sobrien				IEEE80211_NOTE_FRAME(vap,
174090075Sobrien				    IEEE80211_MSG_ASSOC, wh,
174190075Sobrien				    "non-ERP present on channel %d "
174290075Sobrien				    "(saw erp 0x%x from channel %d), "
174390075Sobrien				    "enable use of protection",
174490075Sobrien				    ic->ic_curchan->ic_ieee,
174590075Sobrien				    scan.erp, scan.chan);
174690075Sobrien				ic->ic_flags |= IEEE80211_F_USEPROT;
174790075Sobrien				ieee80211_notify_erp(ic);
174890075Sobrien			}
174990075Sobrien		}
175090075Sobrien		/*
175190075Sobrien		 * Check beacon for non-HT station on HT channel
175290075Sobrien		 * and update HT BSS occupancy as appropriate.
175390075Sobrien		 */
175490075Sobrien		if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) {
175590075Sobrien			if (scan.status & IEEE80211_BPARSE_OFFCHAN) {
175690075Sobrien				/*
175790075Sobrien				 * Off control channel; only check frames
175890075Sobrien				 * that come in the extension channel when
175990075Sobrien				 * operating w/ HT40.
176090075Sobrien				 */
176190075Sobrien				if (!IEEE80211_IS_CHAN_HT40(ic->ic_curchan))
176290075Sobrien					break;
176390075Sobrien				if (scan.chan != ic->ic_curchan->ic_extieee)
176490075Sobrien					break;
176590075Sobrien			}
176690075Sobrien			if (scan.htinfo == NULL) {
176790075Sobrien				ieee80211_htprot_update(ic,
176890075Sobrien				    IEEE80211_HTINFO_OPMODE_PROTOPT |
176990075Sobrien				    IEEE80211_HTINFO_NONHT_PRESENT);
177090075Sobrien			} else if (ishtmixed(scan.htinfo)) {
177190075Sobrien				/* XXX? take NONHT_PRESENT from beacon? */
177290075Sobrien				ieee80211_htprot_update(ic,
177390075Sobrien				    IEEE80211_HTINFO_OPMODE_MIXED |
177490075Sobrien				    IEEE80211_HTINFO_NONHT_PRESENT);
177590075Sobrien			}
177690075Sobrien		}
177790075Sobrien		break;
177890075Sobrien	}
1779117395Skan
1780117395Skan	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
1781117395Skan		if (vap->iv_state != IEEE80211_S_RUN) {
1782117395Skan			vap->iv_stats.is_rx_mgtdiscard++;
1783117395Skan			return;
1784117395Skan		}
1785117395Skan		/*
178690075Sobrien		 * Consult the ACL policy module if setup.
178790075Sobrien		 */
178890075Sobrien		if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
178990075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
179090075Sobrien			    wh, NULL, "%s", "disallowed by ACL");
179190075Sobrien			vap->iv_stats.is_rx_acl++;
179290075Sobrien			return;
179390075Sobrien		}
179490075Sobrien		/*
179590075Sobrien		 * prreq frame format
179690075Sobrien		 *	[tlv] ssid
179790075Sobrien		 *	[tlv] supported rates
179890075Sobrien		 *	[tlv] extended supported rates
1799117395Skan		 */
1800117395Skan		ssid = rates = xrates = NULL;
180190075Sobrien		sfrm = frm;
180290075Sobrien		while (efrm - frm > 1) {
180390075Sobrien			IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
180490075Sobrien			switch (*frm) {
180590075Sobrien			case IEEE80211_ELEMID_SSID:
180690075Sobrien				ssid = frm;
180790075Sobrien				break;
180890075Sobrien			case IEEE80211_ELEMID_RATES:
180990075Sobrien				rates = frm;
181090075Sobrien				break;
181190075Sobrien			case IEEE80211_ELEMID_XRATES:
181290075Sobrien				xrates = frm;
181390075Sobrien				break;
181490075Sobrien			}
181590075Sobrien			frm += frm[1] + 2;
181690075Sobrien		}
181790075Sobrien		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return);
181890075Sobrien		if (xrates != NULL)
181990075Sobrien			IEEE80211_VERIFY_ELEMENT(xrates,
182090075Sobrien				IEEE80211_RATE_MAXSIZE - rates[1], return);
182190075Sobrien		IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, return);
182290075Sobrien		IEEE80211_VERIFY_SSID(vap->iv_bss, ssid, return);
182390075Sobrien		if ((vap->iv_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) {
182490075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
182590075Sobrien			    wh, NULL,
182690075Sobrien			    "%s", "no ssid with ssid suppression enabled");
182790075Sobrien			vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/
182890075Sobrien			return;
182990075Sobrien		}
183090075Sobrien
183190075Sobrien		/* XXX find a better class or define it's own */
183290075Sobrien		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2,
183390075Sobrien		    "%s", "recv probe req");
183490075Sobrien		/*
183590075Sobrien		 * Some legacy 11b clients cannot hack a complete
183690075Sobrien		 * probe response frame.  When the request includes
183790075Sobrien		 * only a bare-bones rate set, communicate this to
183890075Sobrien		 * the transmit side.
183990075Sobrien		 */
184090075Sobrien		ieee80211_send_proberesp(vap, wh->i_addr2,
184190075Sobrien		    is11bclient(rates, xrates) ? IEEE80211_SEND_LEGACY_11B : 0);
184290075Sobrien		break;
184390075Sobrien
184490075Sobrien	case IEEE80211_FC0_SUBTYPE_AUTH: {
184590075Sobrien		uint16_t algo, seq, status;
184690075Sobrien
184790075Sobrien		if (vap->iv_state != IEEE80211_S_RUN) {
184890075Sobrien			vap->iv_stats.is_rx_mgtdiscard++;
184990075Sobrien			return;
185090075Sobrien		}
185190075Sobrien		if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) {
185290075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
185390075Sobrien			    wh, NULL, "%s", "wrong bssid");
185490075Sobrien			vap->iv_stats.is_rx_wrongbss++;	/*XXX unique stat?*/
185590075Sobrien			return;
185690075Sobrien		}
185790075Sobrien		/*
185890075Sobrien		 * auth frame format
185990075Sobrien		 *	[2] algorithm
186090075Sobrien		 *	[2] sequence
186190075Sobrien		 *	[2] status
186290075Sobrien		 *	[tlv*] challenge
186390075Sobrien		 */
186490075Sobrien		IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return);
186590075Sobrien		algo   = le16toh(*(uint16_t *)frm);
186690075Sobrien		seq    = le16toh(*(uint16_t *)(frm + 2));
186790075Sobrien		status = le16toh(*(uint16_t *)(frm + 4));
186890075Sobrien		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2,
186990075Sobrien		    "recv auth frame with algorithm %d seq %d", algo, seq);
1870132718Skan		/*
187190075Sobrien		 * Consult the ACL policy module if setup.
187290075Sobrien		 */
1873117395Skan		if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
187490075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
1875169689Skan			    wh, NULL, "%s", "disallowed by ACL");
1876169689Skan			vap->iv_stats.is_rx_acl++;
1877169689Skan			ieee80211_send_error(ni, wh->i_addr2,
1878169689Skan			    IEEE80211_FC0_SUBTYPE_AUTH,
1879169689Skan			    (seq+1) | (IEEE80211_STATUS_UNSPECIFIED<<16));
1880169689Skan			return;
188190075Sobrien		}
188290075Sobrien		if (vap->iv_flags & IEEE80211_F_COUNTERM) {
188390075Sobrien			IEEE80211_DISCARD(vap,
188490075Sobrien			    IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
1885132718Skan			    wh, NULL, "%s", "TKIP countermeasures enabled");
188690075Sobrien			vap->iv_stats.is_rx_auth_countermeasures++;
188790075Sobrien			ieee80211_send_error(ni, wh->i_addr2,
188890075Sobrien				IEEE80211_FC0_SUBTYPE_AUTH,
1889132718Skan				IEEE80211_REASON_MIC_FAILURE);
189090075Sobrien			return;
189190075Sobrien		}
189296263Sobrien		if (algo == IEEE80211_AUTH_ALG_SHARED)
189390075Sobrien			hostap_auth_shared(ni, wh, frm + 6, efrm, rssi, nf,
1894169689Skan			    seq, status);
1895169689Skan		else if (algo == IEEE80211_AUTH_ALG_OPEN)
1896169689Skan			hostap_auth_open(ni, wh, rssi, nf, seq, status);
1897169689Skan		else if (algo == IEEE80211_AUTH_ALG_LEAP) {
1898169689Skan			authalgreject(ni, wh, algo,
1899169689Skan			    seq+1, IEEE80211_STATUS_ALG);
190090075Sobrien			return;
190190075Sobrien		} else {
190290075Sobrien			/*
190390075Sobrien			 * We assume that an unknown algorithm is the result
190490075Sobrien			 * of a decryption failure on a shared key auth frame;
190590075Sobrien			 * return a status code appropriate for that instead
190690075Sobrien			 * of IEEE80211_STATUS_ALG.
190790075Sobrien			 *
190890075Sobrien			 * NB: a seq# of 4 is intentional; the decrypted
190990075Sobrien			 *     frame likely has a bogus seq value.
191090075Sobrien			 */
191190075Sobrien			authalgreject(ni, wh, algo,
191290075Sobrien			    4, IEEE80211_STATUS_CHALLENGE);
191390075Sobrien			return;
191490075Sobrien		}
191590075Sobrien		break;
191690075Sobrien	}
191790075Sobrien
191890075Sobrien	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
191990075Sobrien	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: {
192090075Sobrien		uint16_t capinfo, lintval;
192190075Sobrien		struct ieee80211_rsnparms rsnparms;
1922132718Skan
1923132718Skan		if (vap->iv_state != IEEE80211_S_RUN) {
1924132718Skan			vap->iv_stats.is_rx_mgtdiscard++;
1925132718Skan			return;
1926132718Skan		}
1927132718Skan		if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) {
192890075Sobrien			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
192990075Sobrien			    wh, NULL, "%s", "wrong bssid");
193090075Sobrien			vap->iv_stats.is_rx_assoc_bss++;
1931117395Skan			return;
193290075Sobrien		}
193390075Sobrien		if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
193490075Sobrien			reassoc = 1;
193590075Sobrien			resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
193690075Sobrien		} else {
193790075Sobrien			reassoc = 0;
193890075Sobrien			resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
193990075Sobrien		}
194090075Sobrien		if (ni == vap->iv_bss) {
194190075Sobrien			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ANY, wh->i_addr2,
194290075Sobrien			    "deny %s request, sta not authenticated",
194390075Sobrien			    reassoc ? "reassoc" : "assoc");
194490075Sobrien			ieee80211_send_error(ni, wh->i_addr2,
194590075Sobrien			    IEEE80211_FC0_SUBTYPE_DEAUTH,
194690075Sobrien			    IEEE80211_REASON_ASSOC_NOT_AUTHED);
194790075Sobrien			vap->iv_stats.is_rx_assoc_notauth++;
194890075Sobrien			return;
194990075Sobrien		}
195090075Sobrien
195190075Sobrien		/*
195290075Sobrien		 * asreq frame format
195390075Sobrien		 *	[2] capability information
195490075Sobrien		 *	[2] listen interval
195590075Sobrien		 *	[6*] current AP address (reassoc only)
195690075Sobrien		 *	[tlv] ssid
195790075Sobrien		 *	[tlv] supported rates
195890075Sobrien		 *	[tlv] extended supported rates
195990075Sobrien		 *	[tlv] WPA or RSN
196090075Sobrien		 *	[tlv] HT capabilities
196190075Sobrien		 *	[tlv] Atheros capabilities
196290075Sobrien		 */
196390075Sobrien		IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4), return);
196490075Sobrien		capinfo = le16toh(*(uint16_t *)frm);	frm += 2;
1965132718Skan		lintval = le16toh(*(uint16_t *)frm);	frm += 2;
196690075Sobrien		if (reassoc)
196790075Sobrien			frm += 6;	/* ignore current AP info */
196890075Sobrien		ssid = rates = xrates = wpa = rsn = wme = ath = htcap = NULL;
196990075Sobrien		sfrm = frm;
197090075Sobrien		while (efrm - frm > 1) {
197190075Sobrien			IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
197290075Sobrien			switch (*frm) {
197390075Sobrien			case IEEE80211_ELEMID_SSID:
197490075Sobrien				ssid = frm;
197590075Sobrien				break;
197690075Sobrien			case IEEE80211_ELEMID_RATES:
197790075Sobrien				rates = frm;
197890075Sobrien				break;
197990075Sobrien			case IEEE80211_ELEMID_XRATES:
198090075Sobrien				xrates = frm;
198190075Sobrien				break;
198290075Sobrien			case IEEE80211_ELEMID_RSN:
198390075Sobrien				rsn = frm;
198490075Sobrien				break;
198590075Sobrien			case IEEE80211_ELEMID_HTCAP:
198690075Sobrien				htcap = frm;
198790075Sobrien				break;
198890075Sobrien			case IEEE80211_ELEMID_VENDOR:
198990075Sobrien				if (iswpaoui(frm))
199090075Sobrien					wpa = frm;
199190075Sobrien				else if (iswmeinfo(frm))
199290075Sobrien					wme = frm;
199390075Sobrien#ifdef IEEE80211_SUPPORT_SUPERG
199490075Sobrien				else if (isatherosoui(frm))
1995117395Skan					ath = frm;
199690075Sobrien#endif
199790075Sobrien				else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) {
199890075Sobrien					if (ishtcapoui(frm) && htcap == NULL)
199990075Sobrien						htcap = frm;
200090075Sobrien				}
200190075Sobrien				break;
200290075Sobrien			}
200390075Sobrien			frm += frm[1] + 2;
200490075Sobrien		}
200590075Sobrien		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return);
2006169689Skan		if (xrates != NULL)
200790075Sobrien			IEEE80211_VERIFY_ELEMENT(xrates,
2008169689Skan				IEEE80211_RATE_MAXSIZE - rates[1], return);
2009169689Skan		IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, return);
201090075Sobrien		IEEE80211_VERIFY_SSID(vap->iv_bss, ssid, return);
201190075Sobrien		if (htcap != NULL) {
201290075Sobrien			IEEE80211_VERIFY_LENGTH(htcap[1],
2013117395Skan			     htcap[0] == IEEE80211_ELEMID_VENDOR ?
201490075Sobrien			         4 + sizeof(struct ieee80211_ie_htcap)-2 :
201590075Sobrien			         sizeof(struct ieee80211_ie_htcap)-2,
2016117395Skan			     return);		/* XXX just NULL out? */
201790075Sobrien		}
201890075Sobrien
2019117395Skan		if ((vap->iv_flags & IEEE80211_F_WPA) &&
202090075Sobrien		    !wpa_assocreq(ni, &rsnparms, wh, wpa, rsn, capinfo))
202190075Sobrien			return;
2022117395Skan		/* discard challenge after association */
202390075Sobrien		if (ni->ni_challenge != NULL) {
202490075Sobrien			IEEE80211_FREE(ni->ni_challenge, M_80211_NODE);
202590075Sobrien			ni->ni_challenge = NULL;
202690075Sobrien		}
2027169689Skan		/* NB: 802.11 spec says to ignore station's privacy bit */
2028169689Skan		if ((capinfo & IEEE80211_CAPINFO_ESS) == 0) {
202990075Sobrien			capinfomismatch(ni, wh, reassoc, resp,
203090075Sobrien			    "capability", capinfo);
203196263Sobrien			return;
203296263Sobrien		}
203396263Sobrien		/*
203496263Sobrien		 * Disallow re-associate w/ invalid slot time setting.
203596263Sobrien		 */
203696263Sobrien		if (ni->ni_associd != 0 &&
203796263Sobrien		    IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
2038169689Skan		    ((ni->ni_capinfo ^ capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME)) {
2039169689Skan			capinfomismatch(ni, wh, reassoc, resp,
2040169689Skan			    "slot time", capinfo);
2041132718Skan			return;
2042132718Skan		}
2043132718Skan		rate = ieee80211_setup_rates(ni, rates, xrates,
2044132718Skan				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
2045132718Skan				IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
2046169689Skan		if (rate & IEEE80211_RATE_BASIC) {
2047169689Skan			ratesetmismatch(ni, wh, reassoc, resp, "legacy", rate);
2048169689Skan			vap->iv_stats.is_rx_assoc_norate++;
2049169689Skan			return;
205090075Sobrien		}
2051		/*
2052		 * If constrained to 11g-only stations reject an
2053		 * 11b-only station.  We cheat a bit here by looking
2054		 * at the max negotiated xmit rate and assuming anyone
2055		 * with a best rate <24Mb/s is an 11b station.
2056		 */
2057		if ((vap->iv_flags & IEEE80211_F_PUREG) && rate < 48) {
2058			ratesetmismatch(ni, wh, reassoc, resp, "11g", rate);
2059			vap->iv_stats.is_rx_assoc_norate++;
2060			return;
2061		}
2062		/*
2063		 * Do HT rate set handling and setup HT node state.
2064		 */
2065		ni->ni_chan = vap->iv_bss->ni_chan;
2066		if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && htcap != NULL) {
2067			rate = ieee80211_setup_htrates(ni, htcap,
2068				IEEE80211_F_DOFMCS | IEEE80211_F_DONEGO |
2069				IEEE80211_F_DOBRS);
2070			if (rate & IEEE80211_RATE_BASIC) {
2071				ratesetmismatch(ni, wh, reassoc, resp,
2072				    "HT", rate);
2073				vap->iv_stats.is_ht_assoc_norate++;
2074				return;
2075			}
2076			ieee80211_ht_node_init(ni);
2077			ieee80211_ht_updatehtcap(ni, htcap);
2078		} else if (ni->ni_flags & IEEE80211_NODE_HT)
2079			ieee80211_ht_node_cleanup(ni);
2080#ifdef IEEE80211_SUPPORT_SUPERG
2081		else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
2082			ieee80211_ff_node_cleanup(ni);
2083#endif
2084		/*
2085		 * Allow AMPDU operation only with unencrypted traffic
2086		 * or AES-CCM; the 11n spec only specifies these ciphers
2087		 * so permitting any others is undefined and can lead
2088		 * to interoperability problems.
2089		 */
2090		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
2091		    (((vap->iv_flags & IEEE80211_F_WPA) &&
2092		      rsnparms.rsn_ucastcipher != IEEE80211_CIPHER_AES_CCM) ||
2093		     (vap->iv_flags & (IEEE80211_F_WPA|IEEE80211_F_PRIVACY)) == IEEE80211_F_PRIVACY)) {
2094			IEEE80211_NOTE(vap,
2095			    IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
2096			    "disallow HT use because WEP or TKIP requested, "
2097			    "capinfo 0x%x ucastcipher %d", capinfo,
2098			    rsnparms.rsn_ucastcipher);
2099			ieee80211_ht_node_cleanup(ni);
2100			vap->iv_stats.is_ht_assoc_downgrade++;
2101		}
2102		/*
2103		 * If constrained to 11n-only stations reject legacy stations.
2104		 */
2105		if ((vap->iv_flags_ht & IEEE80211_FHT_PUREN) &&
2106		    (ni->ni_flags & IEEE80211_NODE_HT) == 0) {
2107			htcapmismatch(ni, wh, reassoc, resp);
2108			vap->iv_stats.is_ht_assoc_nohtcap++;
2109			return;
2110		}
2111		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
2112		ni->ni_noise = nf;
2113		ni->ni_intval = lintval;
2114		ni->ni_capinfo = capinfo;
2115		ni->ni_fhdwell = vap->iv_bss->ni_fhdwell;
2116		ni->ni_fhindex = vap->iv_bss->ni_fhindex;
2117		/*
2118		 * Store the IEs.
2119		 * XXX maybe better to just expand
2120		 */
2121		if (ieee80211_ies_init(&ni->ni_ies, sfrm, efrm - sfrm)) {
2122#define	setie(_ie, _off)	ieee80211_ies_setie(ni->ni_ies, _ie, _off)
2123			if (wpa != NULL)
2124				setie(wpa_ie, wpa - sfrm);
2125			if (rsn != NULL)
2126				setie(rsn_ie, rsn - sfrm);
2127			if (htcap != NULL)
2128				setie(htcap_ie, htcap - sfrm);
2129			if (wme != NULL) {
2130				setie(wme_ie, wme - sfrm);
2131				/*
2132				 * Mark node as capable of QoS.
2133				 */
2134				ni->ni_flags |= IEEE80211_NODE_QOS;
2135			} else
2136				ni->ni_flags &= ~IEEE80211_NODE_QOS;
2137#ifdef IEEE80211_SUPPORT_SUPERG
2138			if (ath != NULL) {
2139				setie(ath_ie, ath - sfrm);
2140				/*
2141				 * Parse ATH station parameters.
2142				 */
2143				ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
2144			} else
2145#endif
2146				ni->ni_ath_flags = 0;
2147#undef setie
2148		} else {
2149			ni->ni_flags &= ~IEEE80211_NODE_QOS;
2150			ni->ni_ath_flags = 0;
2151		}
2152		ieee80211_node_join(ni, resp);
2153		ieee80211_deliver_l2uf(ni);
2154		break;
2155	}
2156
2157	case IEEE80211_FC0_SUBTYPE_DEAUTH:
2158	case IEEE80211_FC0_SUBTYPE_DISASSOC: {
2159		uint16_t reason;
2160
2161		if (vap->iv_state != IEEE80211_S_RUN ||
2162		    /* NB: can happen when in promiscuous mode */
2163		    !IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) {
2164			vap->iv_stats.is_rx_mgtdiscard++;
2165			break;
2166		}
2167		/*
2168		 * deauth/disassoc frame format
2169		 *	[2] reason
2170		 */
2171		IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return);
2172		reason = le16toh(*(uint16_t *)frm);
2173		if (subtype == IEEE80211_FC0_SUBTYPE_DEAUTH) {
2174			vap->iv_stats.is_rx_deauth++;
2175			IEEE80211_NODE_STAT(ni, rx_deauth);
2176		} else {
2177			vap->iv_stats.is_rx_disassoc++;
2178			IEEE80211_NODE_STAT(ni, rx_disassoc);
2179		}
2180		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
2181		    "recv %s (reason %d)", ieee80211_mgt_subtype_name[subtype >>
2182			IEEE80211_FC0_SUBTYPE_SHIFT], reason);
2183		if (ni != vap->iv_bss)
2184			ieee80211_node_leave(ni);
2185		break;
2186	}
2187
2188	case IEEE80211_FC0_SUBTYPE_ACTION:
2189	case IEEE80211_FC0_SUBTYPE_ACTION_NOACK:
2190		if (ni == vap->iv_bss) {
2191			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
2192			    wh, NULL, "%s", "unknown node");
2193			vap->iv_stats.is_rx_mgtdiscard++;
2194		} else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) &&
2195		    !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2196			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
2197			    wh, NULL, "%s", "not for us");
2198			vap->iv_stats.is_rx_mgtdiscard++;
2199		} else if (vap->iv_state != IEEE80211_S_RUN) {
2200			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
2201			    wh, NULL, "wrong state %s",
2202			    ieee80211_state_name[vap->iv_state]);
2203			vap->iv_stats.is_rx_mgtdiscard++;
2204		} else {
2205			if (ieee80211_parse_action(ni, m0) == 0)
2206				(void)ic->ic_recv_action(ni, wh, frm, efrm);
2207		}
2208		break;
2209
2210	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
2211	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
2212	case IEEE80211_FC0_SUBTYPE_TIMING_ADV:
2213	case IEEE80211_FC0_SUBTYPE_ATIM:
2214		IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
2215		    wh, NULL, "%s", "not handled");
2216		vap->iv_stats.is_rx_mgtdiscard++;
2217		break;
2218
2219	default:
2220		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
2221		    wh, "mgt", "subtype 0x%x not handled", subtype);
2222		vap->iv_stats.is_rx_badsubtype++;
2223		break;
2224	}
2225}
2226
2227static void
2228hostap_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype)
2229{
2230	switch (subtype) {
2231	case IEEE80211_FC0_SUBTYPE_PS_POLL:
2232		ni->ni_vap->iv_recv_pspoll(ni, m);
2233		break;
2234	case IEEE80211_FC0_SUBTYPE_BAR:
2235		ieee80211_recv_bar(ni, m);
2236		break;
2237	}
2238}
2239
2240/*
2241 * Process a received ps-poll frame.
2242 */
2243void
2244ieee80211_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m0)
2245{
2246	struct ieee80211vap *vap = ni->ni_vap;
2247	struct ieee80211com *ic = vap->iv_ic;
2248	struct ieee80211_frame_min *wh;
2249	struct mbuf *m;
2250	uint16_t aid;
2251	int qlen;
2252
2253	wh = mtod(m0, struct ieee80211_frame_min *);
2254	if (ni->ni_associd == 0) {
2255		IEEE80211_DISCARD(vap,
2256		    IEEE80211_MSG_POWER | IEEE80211_MSG_DEBUG,
2257		    (struct ieee80211_frame *) wh, NULL,
2258		    "%s", "unassociated station");
2259		vap->iv_stats.is_ps_unassoc++;
2260		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
2261			IEEE80211_REASON_NOT_ASSOCED);
2262		return;
2263	}
2264
2265	aid = le16toh(*(uint16_t *)wh->i_dur);
2266	if (aid != ni->ni_associd) {
2267		IEEE80211_DISCARD(vap,
2268		    IEEE80211_MSG_POWER | IEEE80211_MSG_DEBUG,
2269		    (struct ieee80211_frame *) wh, NULL,
2270		    "aid mismatch: sta aid 0x%x poll aid 0x%x",
2271		    ni->ni_associd, aid);
2272		vap->iv_stats.is_ps_badaid++;
2273		/*
2274		 * NB: We used to deauth the station but it turns out
2275		 * the Blackberry Curve 8230 (and perhaps other devices)
2276		 * sometimes send the wrong AID when WME is negotiated.
2277		 * Being more lenient here seems ok as we already check
2278		 * the station is associated and we only return frames
2279		 * queued for the station (i.e. we don't use the AID).
2280		 */
2281		return;
2282	}
2283
2284	/* Okay, take the first queued packet and put it out... */
2285	m = ieee80211_node_psq_dequeue(ni, &qlen);
2286	if (m == NULL) {
2287		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_POWER, wh->i_addr2,
2288		    "%s", "recv ps-poll, but queue empty");
2289		ieee80211_send_nulldata(ieee80211_ref_node(ni));
2290		vap->iv_stats.is_ps_qempty++;	/* XXX node stat */
2291		if (vap->iv_set_tim != NULL)
2292			vap->iv_set_tim(ni, 0);	/* just in case */
2293		return;
2294	}
2295	/*
2296	 * If there are more packets, set the more packets bit
2297	 * in the packet dispatched to the station; otherwise
2298	 * turn off the TIM bit.
2299	 */
2300	if (qlen != 0) {
2301		IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
2302		    "recv ps-poll, send packet, %u still queued", qlen);
2303		m->m_flags |= M_MORE_DATA;
2304	} else {
2305		IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
2306		    "%s", "recv ps-poll, send packet, queue empty");
2307		if (vap->iv_set_tim != NULL)
2308			vap->iv_set_tim(ni, 0);
2309	}
2310	m->m_flags |= M_PWR_SAV;		/* bypass PS handling */
2311
2312	/*
2313	 * Do the right thing; if it's an encap'ed frame then
2314	 * call ieee80211_parent_xmitpkt() else
2315	 * call ieee80211_vap_xmitpkt().
2316	 */
2317	if (m->m_flags & M_ENCAP) {
2318		(void) ieee80211_parent_xmitpkt(ic, m);
2319	} else {
2320		(void) ieee80211_vap_xmitpkt(vap, m);
2321	}
2322}
2323