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