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