132176cfdSRui Paulo /*- 2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 332176cfdSRui Paulo * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 4f186073cSJoerg Sonnenberger * All rights reserved. 5f186073cSJoerg Sonnenberger * 6f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 7f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions 8f186073cSJoerg Sonnenberger * are met: 9f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 10f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 11f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 12f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 13f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 14f186073cSJoerg Sonnenberger * 15f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25f186073cSJoerg Sonnenberger * 264028af95SRui Paulo * $FreeBSD: head/sys/net80211/ieee80211_node.c 206358 2010-04-07 15:29:13Z rpaulo $ 2732176cfdSRui Paulo * $DragonFly$ 28f186073cSJoerg Sonnenberger */ 29f186073cSJoerg Sonnenberger 3032176cfdSRui Paulo #include "opt_wlan.h" 3132176cfdSRui Paulo 32f186073cSJoerg Sonnenberger #include <sys/param.h> 33f186073cSJoerg Sonnenberger #include <sys/systm.h> 34f186073cSJoerg Sonnenberger #include <sys/mbuf.h> 35f186073cSJoerg Sonnenberger #include <sys/malloc.h> 36f186073cSJoerg Sonnenberger #include <sys/kernel.h> 37f186073cSJoerg Sonnenberger 38841ab66cSSepherosa Ziehau #include <sys/socket.h> 39f186073cSJoerg Sonnenberger 40f186073cSJoerg Sonnenberger #include <net/if.h> 41841ab66cSSepherosa Ziehau #include <net/if_media.h> 42f186073cSJoerg Sonnenberger #include <net/ethernet.h> 4332176cfdSRui Paulo #include <net/route.h> 44f186073cSJoerg Sonnenberger 45f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h> 4632176cfdSRui Paulo #include <netproto/802_11/ieee80211_input.h> 4732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 4832176cfdSRui Paulo #include <netproto/802_11/ieee80211_superg.h> 4932176cfdSRui Paulo #endif 5032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 5132176cfdSRui Paulo #include <netproto/802_11/ieee80211_tdma.h> 5232176cfdSRui Paulo #endif 5332176cfdSRui Paulo #include <netproto/802_11/ieee80211_wds.h> 5432176cfdSRui Paulo #include <netproto/802_11/ieee80211_mesh.h> 554028af95SRui Paulo #include <netproto/802_11/ieee80211_ratectl.h> 56f186073cSJoerg Sonnenberger 57f186073cSJoerg Sonnenberger #include <net/bpf.h> 58f186073cSJoerg Sonnenberger 59841ab66cSSepherosa Ziehau /* 6032176cfdSRui Paulo * IEEE80211_NODE_HASHSIZE must be a power of 2. 6132176cfdSRui Paulo */ 6232176cfdSRui Paulo CTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0); 6332176cfdSRui Paulo 6432176cfdSRui Paulo /* 65841ab66cSSepherosa Ziehau * Association id's are managed with a bit vector. 66841ab66cSSepherosa Ziehau */ 6732176cfdSRui Paulo #define IEEE80211_AID_SET(_vap, b) \ 6832176cfdSRui Paulo ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] |= \ 6932176cfdSRui Paulo (1 << (IEEE80211_AID(b) % 32))) 7032176cfdSRui Paulo #define IEEE80211_AID_CLR(_vap, b) \ 7132176cfdSRui Paulo ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] &= \ 7232176cfdSRui Paulo ~(1 << (IEEE80211_AID(b) % 32))) 7332176cfdSRui Paulo #define IEEE80211_AID_ISSET(_vap, b) \ 7432176cfdSRui Paulo ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32))) 75f186073cSJoerg Sonnenberger 765d004897SSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 775d004897SSepherosa Ziehau #define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line 785d004897SSepherosa Ziehau #else 795d004897SSepherosa Ziehau #define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__ 805d004897SSepherosa Ziehau #endif 815d004897SSepherosa Ziehau 8232176cfdSRui Paulo static int ieee80211_sta_join1(struct ieee80211_node *); 8332176cfdSRui Paulo 8432176cfdSRui Paulo static struct ieee80211_node *node_alloc(struct ieee80211vap *, 8532176cfdSRui Paulo const uint8_t [IEEE80211_ADDR_LEN]); 86841ab66cSSepherosa Ziehau static void node_cleanup(struct ieee80211_node *); 87841ab66cSSepherosa Ziehau static void node_free(struct ieee80211_node *); 8832176cfdSRui Paulo static void node_age(struct ieee80211_node *); 8932176cfdSRui Paulo static int8_t node_getrssi(const struct ieee80211_node *); 9032176cfdSRui Paulo static void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *); 9132176cfdSRui Paulo static void node_getmimoinfo(const struct ieee80211_node *, 9232176cfdSRui Paulo struct ieee80211_mimo_info *); 9347156d48SMatthew Dillon static void ieee80211_node_timeout_callout(void *arg); 94f186073cSJoerg Sonnenberger 95841ab66cSSepherosa Ziehau static void _ieee80211_free_node(struct ieee80211_node *); 96841ab66cSSepherosa Ziehau 97841ab66cSSepherosa Ziehau static void ieee80211_node_table_init(struct ieee80211com *ic, 98841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, const char *name, 9932176cfdSRui Paulo int inact, int keymaxix); 10032176cfdSRui Paulo static void ieee80211_node_table_reset(struct ieee80211_node_table *, 10132176cfdSRui Paulo struct ieee80211vap *); 102841ab66cSSepherosa Ziehau static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 10332176cfdSRui Paulo static void ieee80211_erp_timeout(struct ieee80211com *); 104f186073cSJoerg Sonnenberger 105f186073cSJoerg Sonnenberger MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 10632176cfdSRui Paulo MALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie"); 107f186073cSJoerg Sonnenberger 108f186073cSJoerg Sonnenberger void 109841ab66cSSepherosa Ziehau ieee80211_node_attach(struct ieee80211com *ic) 110f186073cSJoerg Sonnenberger { 11132176cfdSRui Paulo /* XXX really want maxlen enforced per-sta */ 11232176cfdSRui Paulo ieee80211_ageq_init(&ic->ic_stageq, ic->ic_max_keyix * 8, 11332176cfdSRui Paulo "802.11 staging q"); 11432176cfdSRui Paulo ieee80211_node_table_init(ic, &ic->ic_sta, "station", 11532176cfdSRui Paulo IEEE80211_INACT_INIT, ic->ic_max_keyix); 11634a60cf6SRui Paulo callout_init_mp(&ic->ic_inact); 11732176cfdSRui Paulo callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 11847156d48SMatthew Dillon ieee80211_node_timeout_callout, ic); 11932176cfdSRui Paulo 120841ab66cSSepherosa Ziehau ic->ic_node_alloc = node_alloc; 121841ab66cSSepherosa Ziehau ic->ic_node_free = node_free; 122841ab66cSSepherosa Ziehau ic->ic_node_cleanup = node_cleanup; 12332176cfdSRui Paulo ic->ic_node_age = node_age; 12432176cfdSRui Paulo ic->ic_node_drain = node_age; /* NB: same as age */ 125841ab66cSSepherosa Ziehau ic->ic_node_getrssi = node_getrssi; 12632176cfdSRui Paulo ic->ic_node_getsignal = node_getsignal; 12732176cfdSRui Paulo ic->ic_node_getmimoinfo = node_getmimoinfo; 128841ab66cSSepherosa Ziehau 129841ab66cSSepherosa Ziehau /* 13032176cfdSRui Paulo * Set flags to be propagated to all vap's; 13132176cfdSRui Paulo * these define default behaviour/configuration. 132841ab66cSSepherosa Ziehau */ 13332176cfdSRui Paulo ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */ 134f186073cSJoerg Sonnenberger } 135f186073cSJoerg Sonnenberger 136f186073cSJoerg Sonnenberger void 137841ab66cSSepherosa Ziehau ieee80211_node_detach(struct ieee80211com *ic) 138f186073cSJoerg Sonnenberger { 13932176cfdSRui Paulo 140dfcf81fdSRui Paulo callout_stop(&ic->ic_inact); 141841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_sta); 14232176cfdSRui Paulo ieee80211_ageq_cleanup(&ic->ic_stageq); 143841ab66cSSepherosa Ziehau } 14432176cfdSRui Paulo 14532176cfdSRui Paulo void 14632176cfdSRui Paulo ieee80211_node_vattach(struct ieee80211vap *vap) 14732176cfdSRui Paulo { 14832176cfdSRui Paulo /* NB: driver can override */ 14932176cfdSRui Paulo vap->iv_max_aid = IEEE80211_AID_DEF; 15032176cfdSRui Paulo 15132176cfdSRui Paulo /* default station inactivity timer setings */ 15232176cfdSRui Paulo vap->iv_inact_init = IEEE80211_INACT_INIT; 15332176cfdSRui Paulo vap->iv_inact_auth = IEEE80211_INACT_AUTH; 15432176cfdSRui Paulo vap->iv_inact_run = IEEE80211_INACT_RUN; 15532176cfdSRui Paulo vap->iv_inact_probe = IEEE80211_INACT_PROBE; 15632176cfdSRui Paulo 15732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_INACT, 15832176cfdSRui Paulo "%s: init %u auth %u run %u probe %u\n", __func__, 15932176cfdSRui Paulo vap->iv_inact_init, vap->iv_inact_auth, 16032176cfdSRui Paulo vap->iv_inact_run, vap->iv_inact_probe); 16132176cfdSRui Paulo } 16232176cfdSRui Paulo 16332176cfdSRui Paulo void 16432176cfdSRui Paulo ieee80211_node_latevattach(struct ieee80211vap *vap) 16532176cfdSRui Paulo { 16632176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 16732176cfdSRui Paulo /* XXX should we allow max aid to be zero? */ 16832176cfdSRui Paulo if (vap->iv_max_aid < IEEE80211_AID_MIN) { 16932176cfdSRui Paulo vap->iv_max_aid = IEEE80211_AID_MIN; 17032176cfdSRui Paulo if_printf(vap->iv_ifp, 17132176cfdSRui Paulo "WARNING: max aid too small, changed to %d\n", 17232176cfdSRui Paulo vap->iv_max_aid); 17332176cfdSRui Paulo } 17432176cfdSRui Paulo vap->iv_aid_bitmap = (uint32_t *) kmalloc( 17532176cfdSRui Paulo howmany(vap->iv_max_aid, 32) * sizeof(uint32_t), 176fcaa651dSRui Paulo M_80211_NODE, M_INTWAIT | M_ZERO); 17732176cfdSRui Paulo if (vap->iv_aid_bitmap == NULL) { 17832176cfdSRui Paulo /* XXX no way to recover */ 17932176cfdSRui Paulo kprintf("%s: no memory for AID bitmap, max aid %d!\n", 18032176cfdSRui Paulo __func__, vap->iv_max_aid); 18132176cfdSRui Paulo vap->iv_max_aid = 0; 18232176cfdSRui Paulo } 18332176cfdSRui Paulo } 18432176cfdSRui Paulo 18532176cfdSRui Paulo ieee80211_reset_bss(vap); 18632176cfdSRui Paulo 18732176cfdSRui Paulo vap->iv_auth = ieee80211_authenticator_get(vap->iv_bss->ni_authmode); 18832176cfdSRui Paulo } 18932176cfdSRui Paulo 19032176cfdSRui Paulo void 19132176cfdSRui Paulo ieee80211_node_vdetach(struct ieee80211vap *vap) 19232176cfdSRui Paulo { 19332176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 19432176cfdSRui Paulo 19532176cfdSRui Paulo ieee80211_node_table_reset(&ic->ic_sta, vap); 19632176cfdSRui Paulo if (vap->iv_bss != NULL) { 19732176cfdSRui Paulo ieee80211_free_node(vap->iv_bss); 19832176cfdSRui Paulo vap->iv_bss = NULL; 19932176cfdSRui Paulo } 20032176cfdSRui Paulo if (vap->iv_aid_bitmap != NULL) { 20132176cfdSRui Paulo kfree(vap->iv_aid_bitmap, M_80211_NODE); 20232176cfdSRui Paulo vap->iv_aid_bitmap = NULL; 203841ab66cSSepherosa Ziehau } 204841ab66cSSepherosa Ziehau } 205f186073cSJoerg Sonnenberger 206841ab66cSSepherosa Ziehau /* 207841ab66cSSepherosa Ziehau * Port authorize/unauthorize interfaces for use by an authenticator. 208841ab66cSSepherosa Ziehau */ 209841ab66cSSepherosa Ziehau 210841ab66cSSepherosa Ziehau void 211841ab66cSSepherosa Ziehau ieee80211_node_authorize(struct ieee80211_node *ni) 212841ab66cSSepherosa Ziehau { 21332176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 214841ab66cSSepherosa Ziehau 215841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_AUTH; 21632176cfdSRui Paulo ni->ni_inact_reload = vap->iv_inact_run; 21732176cfdSRui Paulo ni->ni_inact = ni->ni_inact_reload; 21832176cfdSRui Paulo 21932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 22032176cfdSRui Paulo "%s: inact_reload %u", __func__, ni->ni_inact_reload); 221841ab66cSSepherosa Ziehau } 222841ab66cSSepherosa Ziehau 223841ab66cSSepherosa Ziehau void 224841ab66cSSepherosa Ziehau ieee80211_node_unauthorize(struct ieee80211_node *ni) 225841ab66cSSepherosa Ziehau { 22632176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 22732176cfdSRui Paulo 228841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AUTH; 22932176cfdSRui Paulo ni->ni_inact_reload = vap->iv_inact_auth; 23032176cfdSRui Paulo if (ni->ni_inact > ni->ni_inact_reload) 23132176cfdSRui Paulo ni->ni_inact = ni->ni_inact_reload; 23232176cfdSRui Paulo 23332176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 23432176cfdSRui Paulo "%s: inact_reload %u inact %u", __func__, 23532176cfdSRui Paulo ni->ni_inact_reload, ni->ni_inact); 23632176cfdSRui Paulo } 23732176cfdSRui Paulo 23832176cfdSRui Paulo /* 23932176cfdSRui Paulo * Fix tx parameters for a node according to ``association state''. 24032176cfdSRui Paulo */ 24132176cfdSRui Paulo void 24232176cfdSRui Paulo ieee80211_node_setuptxparms(struct ieee80211_node *ni) 24332176cfdSRui Paulo { 24432176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 24532176cfdSRui Paulo enum ieee80211_phymode mode; 24632176cfdSRui Paulo 24732176cfdSRui Paulo if (ni->ni_flags & IEEE80211_NODE_HT) { 24832176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 24932176cfdSRui Paulo mode = IEEE80211_MODE_11NA; 25032176cfdSRui Paulo else 25132176cfdSRui Paulo mode = IEEE80211_MODE_11NG; 25232176cfdSRui Paulo } else { /* legacy rate handling */ 25332176cfdSRui Paulo if (IEEE80211_IS_CHAN_ST(ni->ni_chan)) 25432176cfdSRui Paulo mode = IEEE80211_MODE_STURBO_A; 25532176cfdSRui Paulo else if (IEEE80211_IS_CHAN_HALF(ni->ni_chan)) 25632176cfdSRui Paulo mode = IEEE80211_MODE_HALF; 25732176cfdSRui Paulo else if (IEEE80211_IS_CHAN_QUARTER(ni->ni_chan)) 25832176cfdSRui Paulo mode = IEEE80211_MODE_QUARTER; 25932176cfdSRui Paulo /* NB: 108A should be handled as 11a */ 26032176cfdSRui Paulo else if (IEEE80211_IS_CHAN_A(ni->ni_chan)) 26132176cfdSRui Paulo mode = IEEE80211_MODE_11A; 26232176cfdSRui Paulo else if (IEEE80211_IS_CHAN_108G(ni->ni_chan) || 26332176cfdSRui Paulo (ni->ni_flags & IEEE80211_NODE_ERP)) 26432176cfdSRui Paulo mode = IEEE80211_MODE_11G; 26532176cfdSRui Paulo else 26632176cfdSRui Paulo mode = IEEE80211_MODE_11B; 26732176cfdSRui Paulo } 26832176cfdSRui Paulo ni->ni_txparms = &vap->iv_txparms[mode]; 269841ab66cSSepherosa Ziehau } 270841ab66cSSepherosa Ziehau 271841ab66cSSepherosa Ziehau /* 272841ab66cSSepherosa Ziehau * Set/change the channel. The rate set is also updated as 273841ab66cSSepherosa Ziehau * to insure a consistent view by drivers. 27432176cfdSRui Paulo * XXX should be private but hostap needs it to deal with CSA 275841ab66cSSepherosa Ziehau */ 27632176cfdSRui Paulo void 27732176cfdSRui Paulo ieee80211_node_set_chan(struct ieee80211_node *ni, 27832176cfdSRui Paulo struct ieee80211_channel *chan) 279841ab66cSSepherosa Ziehau { 28032176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 28132176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 28232176cfdSRui Paulo enum ieee80211_phymode mode; 28332176cfdSRui Paulo 28432176cfdSRui Paulo KASSERT(chan != IEEE80211_CHAN_ANYC, ("no channel")); 28532176cfdSRui Paulo 286841ab66cSSepherosa Ziehau ni->ni_chan = chan; 28732176cfdSRui Paulo mode = ieee80211_chan2mode(chan); 28832176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(chan)) { 28932176cfdSRui Paulo /* 29032176cfdSRui Paulo * XXX Gotta be careful here; the rate set returned by 29132176cfdSRui Paulo * ieee80211_get_suprates is actually any HT rate 29232176cfdSRui Paulo * set so blindly copying it will be bad. We must 29332176cfdSRui Paulo * install the legacy rate est in ni_rates and the 29432176cfdSRui Paulo * HT rate set in ni_htrates. 29532176cfdSRui Paulo */ 29632176cfdSRui Paulo ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); 29732176cfdSRui Paulo /* 29832176cfdSRui Paulo * Setup bss tx parameters based on operating mode. We 29932176cfdSRui Paulo * use legacy rates when operating in a mixed HT+non-HT bss 30032176cfdSRui Paulo * and non-ERP rates in 11g for mixed ERP+non-ERP bss. 30132176cfdSRui Paulo */ 30232176cfdSRui Paulo if (mode == IEEE80211_MODE_11NA && 30332176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) 30432176cfdSRui Paulo mode = IEEE80211_MODE_11A; 30532176cfdSRui Paulo else if (mode == IEEE80211_MODE_11NG && 30632176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) 30732176cfdSRui Paulo mode = IEEE80211_MODE_11G; 30832176cfdSRui Paulo if (mode == IEEE80211_MODE_11G && 30932176cfdSRui Paulo (vap->iv_flags & IEEE80211_F_PUREG) == 0) 31032176cfdSRui Paulo mode = IEEE80211_MODE_11B; 311f186073cSJoerg Sonnenberger } 31232176cfdSRui Paulo ni->ni_txparms = &vap->iv_txparms[mode]; 31332176cfdSRui Paulo ni->ni_rates = *ieee80211_get_suprates(ic, chan); 314841ab66cSSepherosa Ziehau } 315841ab66cSSepherosa Ziehau 316841ab66cSSepherosa Ziehau static __inline void 317841ab66cSSepherosa Ziehau copy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 318841ab66cSSepherosa Ziehau { 319841ab66cSSepherosa Ziehau /* propagate useful state */ 320841ab66cSSepherosa Ziehau nbss->ni_authmode = obss->ni_authmode; 321841ab66cSSepherosa Ziehau nbss->ni_txpower = obss->ni_txpower; 322841ab66cSSepherosa Ziehau nbss->ni_vlan = obss->ni_vlan; 323841ab66cSSepherosa Ziehau /* XXX statistics? */ 32432176cfdSRui Paulo /* XXX legacy WDS bssid? */ 325f186073cSJoerg Sonnenberger } 326f186073cSJoerg Sonnenberger 327f186073cSJoerg Sonnenberger void 32832176cfdSRui Paulo ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan) 329f186073cSJoerg Sonnenberger { 33032176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 331f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 332f186073cSJoerg Sonnenberger 33332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, 33432176cfdSRui Paulo "%s: creating %s on channel %u\n", __func__, 33532176cfdSRui Paulo ieee80211_opmode_name[vap->iv_opmode], 33632176cfdSRui Paulo ieee80211_chan2ieee(ic, chan)); 337841ab66cSSepherosa Ziehau 33832176cfdSRui Paulo ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 339841ab66cSSepherosa Ziehau if (ni == NULL) { 340841ab66cSSepherosa Ziehau /* XXX recovery? */ 341841ab66cSSepherosa Ziehau return; 342841ab66cSSepherosa Ziehau } 34332176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 34432176cfdSRui Paulo ni->ni_esslen = vap->iv_des_ssid[0].len; 34532176cfdSRui Paulo memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 34632176cfdSRui Paulo if (vap->iv_bss != NULL) 34732176cfdSRui Paulo copy_bss(ni, vap->iv_bss); 348841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 34932176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) 350f186073cSJoerg Sonnenberger ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 351f186073cSJoerg Sonnenberger if (ic->ic_phytype == IEEE80211_T_FH) { 352f186073cSJoerg Sonnenberger ni->ni_fhdwell = 200; /* XXX */ 353f186073cSJoerg Sonnenberger ni->ni_fhindex = 1; 354f186073cSJoerg Sonnenberger } 35532176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 35632176cfdSRui Paulo vap->iv_flags |= IEEE80211_F_SIBSS; 357841ab66cSSepherosa Ziehau ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 35832176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_DESBSSID) 35932176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 36032176cfdSRui Paulo else { 361215bf50cSSepherosa Ziehau get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN); 36232176cfdSRui Paulo /* clear group bit, add local bit */ 363215bf50cSSepherosa Ziehau ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02; 364215bf50cSSepherosa Ziehau } 36532176cfdSRui Paulo } else if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 36632176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_DESBSSID) 36732176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 368841ab66cSSepherosa Ziehau else 36932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 37032176cfdSRui Paulo if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 37132176cfdSRui Paulo #endif 372841ab66cSSepherosa Ziehau memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 37332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 37432176cfdSRui Paulo } else if (vap->iv_opmode == IEEE80211_M_MBSS) { 37532176cfdSRui Paulo ni->ni_meshidlen = vap->iv_mesh->ms_idlen; 37632176cfdSRui Paulo memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen); 37732176cfdSRui Paulo #endif 378841ab66cSSepherosa Ziehau } 379841ab66cSSepherosa Ziehau /* 380841ab66cSSepherosa Ziehau * Fix the channel and related attributes. 381841ab66cSSepherosa Ziehau */ 38232176cfdSRui Paulo /* clear DFS CAC state on previous channel */ 38332176cfdSRui Paulo if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && 38432176cfdSRui Paulo ic->ic_bsschan->ic_freq != chan->ic_freq && 38532176cfdSRui Paulo IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) 38632176cfdSRui Paulo ieee80211_dfs_cac_clear(ic, ic->ic_bsschan); 38732176cfdSRui Paulo ic->ic_bsschan = chan; 38832176cfdSRui Paulo ieee80211_node_set_chan(ni, chan); 38932176cfdSRui Paulo ic->ic_curmode = ieee80211_chan2mode(chan); 390841ab66cSSepherosa Ziehau /* 39132176cfdSRui Paulo * Do mode-specific setup. 392841ab66cSSepherosa Ziehau */ 39332176cfdSRui Paulo if (IEEE80211_IS_CHAN_FULL(chan)) { 39432176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(chan)) { 39532176cfdSRui Paulo /* 39632176cfdSRui Paulo * Use a mixed 11b/11g basic rate set. 39732176cfdSRui Paulo */ 39832176cfdSRui Paulo ieee80211_setbasicrates(&ni->ni_rates, 39932176cfdSRui Paulo IEEE80211_MODE_11G); 40032176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PUREG) { 40132176cfdSRui Paulo /* 40232176cfdSRui Paulo * Also mark OFDM rates basic so 11b 40332176cfdSRui Paulo * stations do not join (WiFi compliance). 40432176cfdSRui Paulo */ 40532176cfdSRui Paulo ieee80211_addbasicrates(&ni->ni_rates, 40632176cfdSRui Paulo IEEE80211_MODE_11A); 40732176cfdSRui Paulo } 40832176cfdSRui Paulo } else if (IEEE80211_IS_CHAN_B(chan)) { 40932176cfdSRui Paulo /* 41032176cfdSRui Paulo * Force pure 11b rate set. 41132176cfdSRui Paulo */ 41232176cfdSRui Paulo ieee80211_setbasicrates(&ni->ni_rates, 41332176cfdSRui Paulo IEEE80211_MODE_11B); 41432176cfdSRui Paulo } 415841ab66cSSepherosa Ziehau } 416841ab66cSSepherosa Ziehau 41732176cfdSRui Paulo (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); 41832176cfdSRui Paulo } 41932176cfdSRui Paulo 42032176cfdSRui Paulo /* 42132176cfdSRui Paulo * Reset bss state on transition to the INIT state. 42232176cfdSRui Paulo * Clear any stations from the table (they have been 42332176cfdSRui Paulo * deauth'd) and reset the bss node (clears key, rate 42432176cfdSRui Paulo * etc. state). 42532176cfdSRui Paulo */ 426841ab66cSSepherosa Ziehau void 42732176cfdSRui Paulo ieee80211_reset_bss(struct ieee80211vap *vap) 428f186073cSJoerg Sonnenberger { 42932176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 430841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *obss; 431841ab66cSSepherosa Ziehau 43232176cfdSRui Paulo ieee80211_node_table_reset(&ic->ic_sta, vap); 43332176cfdSRui Paulo /* XXX multi-bss: wrong */ 43432176cfdSRui Paulo ieee80211_reset_erp(ic); 435841ab66cSSepherosa Ziehau 43632176cfdSRui Paulo ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 4374d770dcfSSascha Wildner KASSERT(ni != NULL, ("unable to setup initial BSS node")); 43832176cfdSRui Paulo obss = vap->iv_bss; 43932176cfdSRui Paulo vap->iv_bss = ieee80211_ref_node(ni); 440841ab66cSSepherosa Ziehau if (obss != NULL) { 441841ab66cSSepherosa Ziehau copy_bss(ni, obss); 442841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 443841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 44432176cfdSRui Paulo } else 44532176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 446841ab66cSSepherosa Ziehau } 447841ab66cSSepherosa Ziehau 448841ab66cSSepherosa Ziehau static int 44932176cfdSRui Paulo match_ssid(const struct ieee80211_node *ni, 45032176cfdSRui Paulo int nssid, const struct ieee80211_scan_ssid ssids[]) 451841ab66cSSepherosa Ziehau { 45232176cfdSRui Paulo int i; 45332176cfdSRui Paulo 45432176cfdSRui Paulo for (i = 0; i < nssid; i++) { 45532176cfdSRui Paulo if (ni->ni_esslen == ssids[i].len && 45632176cfdSRui Paulo memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0) 45732176cfdSRui Paulo return 1; 45832176cfdSRui Paulo } 45932176cfdSRui Paulo return 0; 46032176cfdSRui Paulo } 46132176cfdSRui Paulo 46232176cfdSRui Paulo /* 46332176cfdSRui Paulo * Test a node for suitability/compatibility. 46432176cfdSRui Paulo */ 46532176cfdSRui Paulo static int 46632176cfdSRui Paulo check_bss(struct ieee80211vap *vap, struct ieee80211_node *ni) 46732176cfdSRui Paulo { 46832176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 46932176cfdSRui Paulo uint8_t rate; 47032176cfdSRui Paulo 47132176cfdSRui Paulo if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 47232176cfdSRui Paulo return 0; 47332176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 47432176cfdSRui Paulo if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 47532176cfdSRui Paulo return 0; 47632176cfdSRui Paulo } else { 47732176cfdSRui Paulo if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 47832176cfdSRui Paulo return 0; 47932176cfdSRui Paulo } 48032176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) { 48132176cfdSRui Paulo if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 48232176cfdSRui Paulo return 0; 48332176cfdSRui Paulo } else { 48432176cfdSRui Paulo /* XXX does this mean privacy is supported or required? */ 48532176cfdSRui Paulo if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 48632176cfdSRui Paulo return 0; 48732176cfdSRui Paulo } 48832176cfdSRui Paulo rate = ieee80211_fix_rate(ni, &ni->ni_rates, 48932176cfdSRui Paulo IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 49032176cfdSRui Paulo if (rate & IEEE80211_RATE_BASIC) 49132176cfdSRui Paulo return 0; 49232176cfdSRui Paulo if (vap->iv_des_nssid != 0 && 49332176cfdSRui Paulo !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 49432176cfdSRui Paulo return 0; 49532176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 49632176cfdSRui Paulo !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 49732176cfdSRui Paulo return 0; 49832176cfdSRui Paulo return 1; 49932176cfdSRui Paulo } 50032176cfdSRui Paulo 50132176cfdSRui Paulo #ifdef IEEE80211_DEBUG 50232176cfdSRui Paulo /* 50332176cfdSRui Paulo * Display node suitability/compatibility. 50432176cfdSRui Paulo */ 50532176cfdSRui Paulo static void 50632176cfdSRui Paulo check_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni) 50732176cfdSRui Paulo { 50832176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 509f186073cSJoerg Sonnenberger uint8_t rate; 510f186073cSJoerg Sonnenberger int fail; 511f186073cSJoerg Sonnenberger 512f186073cSJoerg Sonnenberger fail = 0; 513f186073cSJoerg Sonnenberger if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 514f186073cSJoerg Sonnenberger fail |= 0x01; 51532176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 516f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 517f186073cSJoerg Sonnenberger fail |= 0x02; 518f186073cSJoerg Sonnenberger } else { 519f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 520f186073cSJoerg Sonnenberger fail |= 0x02; 521f186073cSJoerg Sonnenberger } 52232176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) { 523f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 524f186073cSJoerg Sonnenberger fail |= 0x04; 525f186073cSJoerg Sonnenberger } else { 526f186073cSJoerg Sonnenberger /* XXX does this mean privacy is supported or required? */ 527f186073cSJoerg Sonnenberger if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 528f186073cSJoerg Sonnenberger fail |= 0x04; 529f186073cSJoerg Sonnenberger } 53032176cfdSRui Paulo rate = ieee80211_fix_rate(ni, &ni->ni_rates, 53132176cfdSRui Paulo IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 532f186073cSJoerg Sonnenberger if (rate & IEEE80211_RATE_BASIC) 533f186073cSJoerg Sonnenberger fail |= 0x08; 53432176cfdSRui Paulo if (vap->iv_des_nssid != 0 && 53532176cfdSRui Paulo !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 536f186073cSJoerg Sonnenberger fail |= 0x10; 53732176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 53832176cfdSRui Paulo !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 539f186073cSJoerg Sonnenberger fail |= 0x20; 54032176cfdSRui Paulo 5416168f72eSRui Paulo kprintf(" %c %6D", fail ? '-' : '+', ni->ni_macaddr, ":"); 5426168f72eSRui Paulo kprintf(" %6D%c", ni->ni_bssid, ":", fail & 0x20 ? '!' : ' '); 54332176cfdSRui Paulo kprintf(" %3d%c", 54432176cfdSRui Paulo ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); 545a6ec04bcSSascha Wildner kprintf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 546f186073cSJoerg Sonnenberger fail & 0x08 ? '!' : ' '); 547a6ec04bcSSascha Wildner kprintf(" %4s%c", 548f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 549f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 550f186073cSJoerg Sonnenberger "????", 551f186073cSJoerg Sonnenberger fail & 0x02 ? '!' : ' '); 552a6ec04bcSSascha Wildner kprintf(" %3s%c ", 55332176cfdSRui Paulo (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no", 554f186073cSJoerg Sonnenberger fail & 0x04 ? '!' : ' '); 555f186073cSJoerg Sonnenberger ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 556a6ec04bcSSascha Wildner kprintf("%s\n", fail & 0x10 ? "!" : ""); 557f186073cSJoerg Sonnenberger } 55832176cfdSRui Paulo #endif /* IEEE80211_DEBUG */ 559841ab66cSSepherosa Ziehau 560841ab66cSSepherosa Ziehau /* 561841ab66cSSepherosa Ziehau * Handle 802.11 ad hoc network merge. The 562841ab66cSSepherosa Ziehau * convention, set by the Wireless Ethernet Compatibility Alliance 563841ab66cSSepherosa Ziehau * (WECA), is that an 802.11 station will change its BSSID to match 564841ab66cSSepherosa Ziehau * the "oldest" 802.11 ad hoc network, on the same channel, that 565841ab66cSSepherosa Ziehau * has the station's desired SSID. The "oldest" 802.11 network 566841ab66cSSepherosa Ziehau * sends beacons with the greatest TSF timestamp. 567841ab66cSSepherosa Ziehau * 568841ab66cSSepherosa Ziehau * The caller is assumed to validate TSF's before attempting a merge. 569841ab66cSSepherosa Ziehau * 570841ab66cSSepherosa Ziehau * Return !0 if the BSSID changed, 0 otherwise. 571841ab66cSSepherosa Ziehau */ 572841ab66cSSepherosa Ziehau int 573841ab66cSSepherosa Ziehau ieee80211_ibss_merge(struct ieee80211_node *ni) 574841ab66cSSepherosa Ziehau { 57532176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 57632176cfdSRui Paulo #ifdef IEEE80211_DEBUG 577841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 57832176cfdSRui Paulo #endif 579841ab66cSSepherosa Ziehau 58032176cfdSRui Paulo if (ni == vap->iv_bss || 58132176cfdSRui Paulo IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { 582841ab66cSSepherosa Ziehau /* unchanged, nothing to do */ 583841ab66cSSepherosa Ziehau return 0; 584841ab66cSSepherosa Ziehau } 58532176cfdSRui Paulo if (!check_bss(vap, ni)) { 58632176cfdSRui Paulo /* capabilities mismatch */ 58732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 588841ab66cSSepherosa Ziehau "%s: merge failed, capabilities mismatch\n", __func__); 58932176cfdSRui Paulo #ifdef IEEE80211_DEBUG 59032176cfdSRui Paulo if (ieee80211_msg_assoc(vap)) 59132176cfdSRui Paulo check_bss_debug(vap, ni); 59232176cfdSRui Paulo #endif 59332176cfdSRui Paulo vap->iv_stats.is_ibss_capmismatch++; 594841ab66cSSepherosa Ziehau return 0; 595841ab66cSSepherosa Ziehau } 59632176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 5976168f72eSRui Paulo "%s: new bssid %6D: %s preamble, %s slot time%s\n", __func__, 5986168f72eSRui Paulo ni->ni_bssid, ":", 599841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 600841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 601841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 602841ab66cSSepherosa Ziehau ); 60332176cfdSRui Paulo return ieee80211_sta_join1(ieee80211_ref_node(ni)); 60432176cfdSRui Paulo } 60532176cfdSRui Paulo 60632176cfdSRui Paulo /* 60732176cfdSRui Paulo * Calculate HT channel promotion flags for all vaps. 60832176cfdSRui Paulo * This assumes ni_chan have been setup for each vap. 60932176cfdSRui Paulo */ 61032176cfdSRui Paulo static int 61132176cfdSRui Paulo gethtadjustflags(struct ieee80211com *ic) 61232176cfdSRui Paulo { 61332176cfdSRui Paulo struct ieee80211vap *vap; 61432176cfdSRui Paulo int flags; 61532176cfdSRui Paulo 61632176cfdSRui Paulo flags = 0; 61732176cfdSRui Paulo /* XXX locking */ 61832176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 61932176cfdSRui Paulo if (vap->iv_state < IEEE80211_S_RUN) 62032176cfdSRui Paulo continue; 62132176cfdSRui Paulo switch (vap->iv_opmode) { 62232176cfdSRui Paulo case IEEE80211_M_WDS: 62332176cfdSRui Paulo case IEEE80211_M_STA: 62432176cfdSRui Paulo case IEEE80211_M_AHDEMO: 62532176cfdSRui Paulo case IEEE80211_M_HOSTAP: 62632176cfdSRui Paulo case IEEE80211_M_IBSS: 62732176cfdSRui Paulo case IEEE80211_M_MBSS: 62832176cfdSRui Paulo flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan); 62932176cfdSRui Paulo break; 63032176cfdSRui Paulo default: 63132176cfdSRui Paulo break; 63232176cfdSRui Paulo } 63332176cfdSRui Paulo } 63432176cfdSRui Paulo return flags; 63532176cfdSRui Paulo } 63632176cfdSRui Paulo 63732176cfdSRui Paulo /* 63832176cfdSRui Paulo * Check if the current channel needs to change based on whether 63932176cfdSRui Paulo * any vap's are using HT20/HT40. This is used to sync the state 64032176cfdSRui Paulo * of ic_curchan after a channel width change on a running vap. 64132176cfdSRui Paulo */ 64232176cfdSRui Paulo void 64332176cfdSRui Paulo ieee80211_sync_curchan(struct ieee80211com *ic) 64432176cfdSRui Paulo { 64532176cfdSRui Paulo struct ieee80211_channel *c; 64632176cfdSRui Paulo 64732176cfdSRui Paulo c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic)); 64832176cfdSRui Paulo if (c != ic->ic_curchan) { 64932176cfdSRui Paulo ic->ic_curchan = c; 65032176cfdSRui Paulo ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 65132176cfdSRui Paulo ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); 65232176cfdSRui Paulo ic->ic_set_channel(ic); 65332176cfdSRui Paulo ieee80211_radiotap_chan_change(ic); 65432176cfdSRui Paulo } 65532176cfdSRui Paulo } 65632176cfdSRui Paulo 65732176cfdSRui Paulo /* 65832176cfdSRui Paulo * Setup the current channel. The request channel may be 65932176cfdSRui Paulo * promoted if other vap's are operating with HT20/HT40. 66032176cfdSRui Paulo */ 66132176cfdSRui Paulo void 66232176cfdSRui Paulo ieee80211_setupcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 66332176cfdSRui Paulo { 66432176cfdSRui Paulo if (ic->ic_htcaps & IEEE80211_HTC_HT) { 66532176cfdSRui Paulo int flags = gethtadjustflags(ic); 66632176cfdSRui Paulo /* 66732176cfdSRui Paulo * Check for channel promotion required to support the 66832176cfdSRui Paulo * set of running vap's. This assumes we are called 66932176cfdSRui Paulo * after ni_chan is setup for each vap. 67032176cfdSRui Paulo */ 67132176cfdSRui Paulo /* NB: this assumes IEEE80211_FHT_USEHT40 > IEEE80211_FHT_HT */ 67232176cfdSRui Paulo if (flags > ieee80211_htchanflags(c)) 67332176cfdSRui Paulo c = ieee80211_ht_adjust_channel(ic, c, flags); 67432176cfdSRui Paulo } 67532176cfdSRui Paulo ic->ic_bsschan = ic->ic_curchan = c; 67632176cfdSRui Paulo ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 67732176cfdSRui Paulo ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); 67832176cfdSRui Paulo } 67932176cfdSRui Paulo 68032176cfdSRui Paulo /* 68132176cfdSRui Paulo * Change the current channel. The channel change is guaranteed to have 68232176cfdSRui Paulo * happened before the next state change. 68332176cfdSRui Paulo */ 68432176cfdSRui Paulo void 68532176cfdSRui Paulo ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 68632176cfdSRui Paulo { 68732176cfdSRui Paulo ieee80211_setupcurchan(ic, c); 68832176cfdSRui Paulo ieee80211_runtask(ic, &ic->ic_chan_task); 689841ab66cSSepherosa Ziehau } 690841ab66cSSepherosa Ziehau 691841ab66cSSepherosa Ziehau /* 692841ab66cSSepherosa Ziehau * Join the specified IBSS/BSS network. The node is assumed to 693841ab66cSSepherosa Ziehau * be passed in with a held reference. 694841ab66cSSepherosa Ziehau */ 69532176cfdSRui Paulo static int 69632176cfdSRui Paulo ieee80211_sta_join1(struct ieee80211_node *selbs) 697841ab66cSSepherosa Ziehau { 69832176cfdSRui Paulo struct ieee80211vap *vap = selbs->ni_vap; 69932176cfdSRui Paulo struct ieee80211com *ic = selbs->ni_ic; 700841ab66cSSepherosa Ziehau struct ieee80211_node *obss; 70132176cfdSRui Paulo int canreassoc; 702841ab66cSSepherosa Ziehau 703841ab66cSSepherosa Ziehau /* 704841ab66cSSepherosa Ziehau * Committed to selbs, setup state. 705841ab66cSSepherosa Ziehau */ 70632176cfdSRui Paulo obss = vap->iv_bss; 70732176cfdSRui Paulo /* 70832176cfdSRui Paulo * Check if old+new node have the same address in which 70932176cfdSRui Paulo * case we can reassociate when operating in sta mode. 71032176cfdSRui Paulo */ 71132176cfdSRui Paulo canreassoc = (obss != NULL && 71232176cfdSRui Paulo vap->iv_state == IEEE80211_S_RUN && 71332176cfdSRui Paulo IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr)); 71432176cfdSRui Paulo vap->iv_bss = selbs; /* NB: caller assumed to bump refcnt */ 715841ab66cSSepherosa Ziehau if (obss != NULL) { 716841ab66cSSepherosa Ziehau copy_bss(selbs, obss); 71732176cfdSRui Paulo ieee80211_node_decref(obss); /* iv_bss reference */ 71832176cfdSRui Paulo ieee80211_free_node(obss); /* station table reference */ 71932176cfdSRui Paulo obss = NULL; /* NB: guard against later use */ 720841ab66cSSepherosa Ziehau } 72132176cfdSRui Paulo 72232176cfdSRui Paulo /* 72332176cfdSRui Paulo * Delete unusable rates; we've already checked 72432176cfdSRui Paulo * that the negotiated rate set is acceptable. 72532176cfdSRui Paulo */ 72632176cfdSRui Paulo ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates, 72732176cfdSRui Paulo IEEE80211_F_DODEL | IEEE80211_F_JOIN); 72832176cfdSRui Paulo 72932176cfdSRui Paulo ieee80211_setcurchan(ic, selbs->ni_chan); 730841ab66cSSepherosa Ziehau /* 731841ab66cSSepherosa Ziehau * Set the erp state (mostly the slot time) to deal with 732841ab66cSSepherosa Ziehau * the auto-select case; this should be redundant if the 733841ab66cSSepherosa Ziehau * mode is locked. 734841ab66cSSepherosa Ziehau */ 735841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 73632176cfdSRui Paulo ieee80211_wme_initparams(vap); 737841ab66cSSepherosa Ziehau 73832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA) { 73932176cfdSRui Paulo if (canreassoc) { 74032176cfdSRui Paulo /* Reassociate */ 74132176cfdSRui Paulo ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1); 74232176cfdSRui Paulo } else { 743208a1285SSepherosa Ziehau /* 74432176cfdSRui Paulo * Act as if we received a DEAUTH frame in case we 74532176cfdSRui Paulo * are invoked from the RUN state. This will cause 74632176cfdSRui Paulo * us to try to re-authenticate if we are operating 74732176cfdSRui Paulo * as a station. 748208a1285SSepherosa Ziehau */ 74932176cfdSRui Paulo ieee80211_new_state(vap, IEEE80211_S_AUTH, 75032176cfdSRui Paulo IEEE80211_FC0_SUBTYPE_DEAUTH); 751208a1285SSepherosa Ziehau } 75232176cfdSRui Paulo } else 75332176cfdSRui Paulo ieee80211_new_state(vap, IEEE80211_S_RUN, -1); 754841ab66cSSepherosa Ziehau return 1; 755841ab66cSSepherosa Ziehau } 756841ab66cSSepherosa Ziehau 75732176cfdSRui Paulo int 75832176cfdSRui Paulo ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan, 75932176cfdSRui Paulo const struct ieee80211_scan_entry *se) 76032176cfdSRui Paulo { 76132176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 76232176cfdSRui Paulo struct ieee80211_node *ni; 76332176cfdSRui Paulo 76432176cfdSRui Paulo ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr); 76532176cfdSRui Paulo if (ni == NULL) { 76632176cfdSRui Paulo /* XXX msg */ 76732176cfdSRui Paulo return 0; 76832176cfdSRui Paulo } 76932176cfdSRui Paulo /* 77032176cfdSRui Paulo * Expand scan state into node's format. 77132176cfdSRui Paulo * XXX may not need all this stuff 77232176cfdSRui Paulo */ 77332176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid); 77432176cfdSRui Paulo ni->ni_esslen = se->se_ssid[1]; 77532176cfdSRui Paulo memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen); 77632176cfdSRui Paulo ni->ni_tstamp.tsf = se->se_tstamp.tsf; 77732176cfdSRui Paulo ni->ni_intval = se->se_intval; 77832176cfdSRui Paulo ni->ni_capinfo = se->se_capinfo; 77932176cfdSRui Paulo ni->ni_chan = chan; 78032176cfdSRui Paulo ni->ni_timoff = se->se_timoff; 78132176cfdSRui Paulo ni->ni_fhdwell = se->se_fhdwell; 78232176cfdSRui Paulo ni->ni_fhindex = se->se_fhindex; 78332176cfdSRui Paulo ni->ni_erp = se->se_erp; 78432176cfdSRui Paulo IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi); 78532176cfdSRui Paulo ni->ni_noise = se->se_noise; 78632176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA) { 78732176cfdSRui Paulo /* NB: only infrastructure mode requires an associd */ 78832176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_ASSOCID; 78932176cfdSRui Paulo } 79032176cfdSRui Paulo 79132176cfdSRui Paulo if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) { 79232176cfdSRui Paulo ieee80211_ies_expand(&ni->ni_ies); 79332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 79432176cfdSRui Paulo if (ni->ni_ies.ath_ie != NULL) 79532176cfdSRui Paulo ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 79632176cfdSRui Paulo #endif 79732176cfdSRui Paulo if (ni->ni_ies.htcap_ie != NULL) 79832176cfdSRui Paulo ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie); 79932176cfdSRui Paulo if (ni->ni_ies.htinfo_ie != NULL) 80032176cfdSRui Paulo ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie); 80132176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 80232176cfdSRui Paulo if (ni->ni_ies.meshid_ie != NULL) 80332176cfdSRui Paulo ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie); 80432176cfdSRui Paulo #endif 80532176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 80632176cfdSRui Paulo if (ni->ni_ies.tdma_ie != NULL) 80732176cfdSRui Paulo ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie); 80832176cfdSRui Paulo #endif 80932176cfdSRui Paulo } 81032176cfdSRui Paulo 81132176cfdSRui Paulo vap->iv_dtim_period = se->se_dtimperiod; 81232176cfdSRui Paulo vap->iv_dtim_count = 0; 81332176cfdSRui Paulo 81432176cfdSRui Paulo /* NB: must be after ni_chan is setup */ 81532176cfdSRui Paulo ieee80211_setup_rates(ni, se->se_rates, se->se_xrates, 81632176cfdSRui Paulo IEEE80211_F_DOSORT); 81732176cfdSRui Paulo if (ieee80211_iserp_rateset(&ni->ni_rates)) 81832176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_ERP; 81932176cfdSRui Paulo ieee80211_node_setuptxparms(ni); 82032176cfdSRui Paulo 82132176cfdSRui Paulo return ieee80211_sta_join1(ieee80211_ref_node(ni)); 82232176cfdSRui Paulo } 82332176cfdSRui Paulo 824841ab66cSSepherosa Ziehau /* 825841ab66cSSepherosa Ziehau * Leave the specified IBSS/BSS network. The node is assumed to 826841ab66cSSepherosa Ziehau * be passed in with a held reference. 827841ab66cSSepherosa Ziehau */ 828841ab66cSSepherosa Ziehau void 82932176cfdSRui Paulo ieee80211_sta_leave(struct ieee80211_node *ni) 830841ab66cSSepherosa Ziehau { 83132176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 83232176cfdSRui Paulo 833841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 83432176cfdSRui Paulo ieee80211_notify_node_leave(ni); 83532176cfdSRui Paulo } 83632176cfdSRui Paulo 83732176cfdSRui Paulo /* 83832176cfdSRui Paulo * Send a deauthenticate frame and drop the station. 83932176cfdSRui Paulo */ 84032176cfdSRui Paulo void 84132176cfdSRui Paulo ieee80211_node_deauth(struct ieee80211_node *ni, int reason) 84232176cfdSRui Paulo { 84332176cfdSRui Paulo /* NB: bump the refcnt to be sure temporay nodes are not reclaimed */ 84432176cfdSRui Paulo ieee80211_ref_node(ni); 84532176cfdSRui Paulo if (ni->ni_associd != 0) 84632176cfdSRui Paulo IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); 84732176cfdSRui Paulo ieee80211_node_leave(ni); 84832176cfdSRui Paulo ieee80211_free_node(ni); 849f186073cSJoerg Sonnenberger } 850f186073cSJoerg Sonnenberger 851f186073cSJoerg Sonnenberger static struct ieee80211_node * 85232176cfdSRui Paulo node_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 853f186073cSJoerg Sonnenberger { 854f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 855841ab66cSSepherosa Ziehau 85632176cfdSRui Paulo ni = (struct ieee80211_node *) kmalloc(sizeof(struct ieee80211_node), 857fcaa651dSRui Paulo M_80211_NODE, M_INTWAIT | M_ZERO); 858f186073cSJoerg Sonnenberger return ni; 859f186073cSJoerg Sonnenberger } 860f186073cSJoerg Sonnenberger 861841ab66cSSepherosa Ziehau /* 86232176cfdSRui Paulo * Initialize an ie blob with the specified data. If previous 86332176cfdSRui Paulo * data exists re-use the data block. As a side effect we clear 86432176cfdSRui Paulo * all references to specific ie's; the caller is required to 86532176cfdSRui Paulo * recalculate them. 86632176cfdSRui Paulo */ 86732176cfdSRui Paulo int 86832176cfdSRui Paulo ieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len) 86932176cfdSRui Paulo { 87032176cfdSRui Paulo /* NB: assumes data+len are the last fields */ 87132176cfdSRui Paulo memset(ies, 0, offsetof(struct ieee80211_ies, data)); 87232176cfdSRui Paulo if (ies->data != NULL && ies->len != len) { 87332176cfdSRui Paulo /* data size changed */ 87432176cfdSRui Paulo kfree(ies->data, M_80211_NODE_IE); 87532176cfdSRui Paulo ies->data = NULL; 87632176cfdSRui Paulo } 87732176cfdSRui Paulo if (ies->data == NULL) { 878fcaa651dSRui Paulo ies->data = (uint8_t *) kmalloc(len, M_80211_NODE_IE, M_INTWAIT); 87932176cfdSRui Paulo if (ies->data == NULL) { 88032176cfdSRui Paulo ies->len = 0; 88132176cfdSRui Paulo /* NB: pointers have already been zero'd above */ 88232176cfdSRui Paulo return 0; 88332176cfdSRui Paulo } 88432176cfdSRui Paulo } 88532176cfdSRui Paulo memcpy(ies->data, data, len); 88632176cfdSRui Paulo ies->len = len; 88732176cfdSRui Paulo return 1; 88832176cfdSRui Paulo } 88932176cfdSRui Paulo 89032176cfdSRui Paulo /* 89132176cfdSRui Paulo * Reclaim storage for an ie blob. 89232176cfdSRui Paulo */ 89332176cfdSRui Paulo void 89432176cfdSRui Paulo ieee80211_ies_cleanup(struct ieee80211_ies *ies) 89532176cfdSRui Paulo { 89632176cfdSRui Paulo if (ies->data != NULL) 89732176cfdSRui Paulo kfree(ies->data, M_80211_NODE_IE); 89832176cfdSRui Paulo } 89932176cfdSRui Paulo 90032176cfdSRui Paulo /* 90132176cfdSRui Paulo * Expand an ie blob data contents and to fillin individual 90232176cfdSRui Paulo * ie pointers. The data blob is assumed to be well-formed; 90332176cfdSRui Paulo * we don't do any validity checking of ie lengths. 90432176cfdSRui Paulo */ 90532176cfdSRui Paulo void 90632176cfdSRui Paulo ieee80211_ies_expand(struct ieee80211_ies *ies) 90732176cfdSRui Paulo { 90832176cfdSRui Paulo uint8_t *ie; 90932176cfdSRui Paulo int ielen; 91032176cfdSRui Paulo 91132176cfdSRui Paulo ie = ies->data; 91232176cfdSRui Paulo ielen = ies->len; 91332176cfdSRui Paulo while (ielen > 0) { 91432176cfdSRui Paulo switch (ie[0]) { 91532176cfdSRui Paulo case IEEE80211_ELEMID_VENDOR: 91632176cfdSRui Paulo if (iswpaoui(ie)) 91732176cfdSRui Paulo ies->wpa_ie = ie; 91832176cfdSRui Paulo else if (iswmeoui(ie)) 91932176cfdSRui Paulo ies->wme_ie = ie; 92032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 92132176cfdSRui Paulo else if (isatherosoui(ie)) 92232176cfdSRui Paulo ies->ath_ie = ie; 92332176cfdSRui Paulo #endif 92432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 92532176cfdSRui Paulo else if (istdmaoui(ie)) 92632176cfdSRui Paulo ies->tdma_ie = ie; 92732176cfdSRui Paulo #endif 92832176cfdSRui Paulo break; 92932176cfdSRui Paulo case IEEE80211_ELEMID_RSN: 93032176cfdSRui Paulo ies->rsn_ie = ie; 93132176cfdSRui Paulo break; 93232176cfdSRui Paulo case IEEE80211_ELEMID_HTCAP: 93332176cfdSRui Paulo ies->htcap_ie = ie; 93432176cfdSRui Paulo break; 93532176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 93632176cfdSRui Paulo case IEEE80211_ELEMID_MESHID: 93732176cfdSRui Paulo ies->meshid_ie = ie; 93832176cfdSRui Paulo break; 93932176cfdSRui Paulo #endif 94032176cfdSRui Paulo } 94132176cfdSRui Paulo ielen -= 2 + ie[1]; 94232176cfdSRui Paulo ie += 2 + ie[1]; 94332176cfdSRui Paulo } 94432176cfdSRui Paulo } 94532176cfdSRui Paulo 94632176cfdSRui Paulo /* 947841ab66cSSepherosa Ziehau * Reclaim any resources in a node and reset any critical 948841ab66cSSepherosa Ziehau * state. Typically nodes are free'd immediately after, 949841ab66cSSepherosa Ziehau * but in some cases the storage may be reused so we need 950841ab66cSSepherosa Ziehau * to insure consistent state (should probably fix that). 951841ab66cSSepherosa Ziehau */ 952f186073cSJoerg Sonnenberger static void 953841ab66cSSepherosa Ziehau node_cleanup(struct ieee80211_node *ni) 954f186073cSJoerg Sonnenberger { 95532176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 956841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 95732176cfdSRui Paulo int i; 958841ab66cSSepherosa Ziehau 959841ab66cSSepherosa Ziehau /* NB: preserve ni_table */ 960841ab66cSSepherosa Ziehau if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 96132176cfdSRui Paulo if (vap->iv_opmode != IEEE80211_M_STA) 96232176cfdSRui Paulo vap->iv_ps_sta--; 963841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 96432176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 96532176cfdSRui Paulo "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); 966841ab66cSSepherosa Ziehau } 967841ab66cSSepherosa Ziehau /* 96832176cfdSRui Paulo * Cleanup any HT-related state. 96932176cfdSRui Paulo */ 97032176cfdSRui Paulo if (ni->ni_flags & IEEE80211_NODE_HT) 97132176cfdSRui Paulo ieee80211_ht_node_cleanup(ni); 97232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 97332176cfdSRui Paulo else if (ni->ni_ath_flags & IEEE80211_NODE_ATH) 97432176cfdSRui Paulo ieee80211_ff_node_cleanup(ni); 97532176cfdSRui Paulo #endif 97632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 97732176cfdSRui Paulo /* 97832176cfdSRui Paulo * Cleanup any mesh-related state. 97932176cfdSRui Paulo */ 98032176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 98132176cfdSRui Paulo ieee80211_mesh_node_cleanup(ni); 98232176cfdSRui Paulo #endif 98332176cfdSRui Paulo /* 98432176cfdSRui Paulo * Clear any staging queue entries. 98532176cfdSRui Paulo */ 98632176cfdSRui Paulo ieee80211_ageq_drain_node(&ic->ic_stageq, ni); 98732176cfdSRui Paulo 98832176cfdSRui Paulo /* 989841ab66cSSepherosa Ziehau * Clear AREF flag that marks the authorization refcnt bump 990841ab66cSSepherosa Ziehau * has happened. This is probably not needed as the node 991841ab66cSSepherosa Ziehau * should always be removed from the table so not found but 992841ab66cSSepherosa Ziehau * do it just in case. 99332176cfdSRui Paulo * Likewise clear the ASSOCID flag as these flags are intended 99432176cfdSRui Paulo * to be managed in tandem. 995841ab66cSSepherosa Ziehau */ 99632176cfdSRui Paulo ni->ni_flags &= ~(IEEE80211_NODE_AREF | IEEE80211_NODE_ASSOCID); 997841ab66cSSepherosa Ziehau 998841ab66cSSepherosa Ziehau /* 999841ab66cSSepherosa Ziehau * Drain power save queue and, if needed, clear TIM. 1000841ab66cSSepherosa Ziehau */ 100132176cfdSRui Paulo if (ieee80211_node_psq_drain(ni) != 0 && vap->iv_set_tim != NULL) 100232176cfdSRui Paulo vap->iv_set_tim(ni, 0); 1003841ab66cSSepherosa Ziehau 1004841ab66cSSepherosa Ziehau ni->ni_associd = 0; 1005841ab66cSSepherosa Ziehau if (ni->ni_challenge != NULL) { 100632176cfdSRui Paulo kfree(ni->ni_challenge, M_80211_NODE); 1007841ab66cSSepherosa Ziehau ni->ni_challenge = NULL; 1008841ab66cSSepherosa Ziehau } 1009841ab66cSSepherosa Ziehau /* 1010841ab66cSSepherosa Ziehau * Preserve SSID, WPA, and WME ie's so the bss node is 1011841ab66cSSepherosa Ziehau * reusable during a re-auth/re-assoc state transition. 1012841ab66cSSepherosa Ziehau * If we remove these data they will not be recreated 1013841ab66cSSepherosa Ziehau * because they come from a probe-response or beacon frame 1014841ab66cSSepherosa Ziehau * which cannot be expected prior to the association-response. 1015841ab66cSSepherosa Ziehau * This should not be an issue when operating in other modes 1016841ab66cSSepherosa Ziehau * as stations leaving always go through a full state transition 1017841ab66cSSepherosa Ziehau * which will rebuild this state. 1018841ab66cSSepherosa Ziehau * 1019841ab66cSSepherosa Ziehau * XXX does this leave us open to inheriting old state? 1020841ab66cSSepherosa Ziehau */ 1021*c157ff7aSSascha Wildner for (i = 0; i < NELEM(ni->ni_rxfrag); i++) 1022841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[i] != NULL) { 1023841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[i]); 1024841ab66cSSepherosa Ziehau ni->ni_rxfrag[i] = NULL; 1025841ab66cSSepherosa Ziehau } 1026841ab66cSSepherosa Ziehau /* 1027841ab66cSSepherosa Ziehau * Must be careful here to remove any key map entry w/o a LOR. 1028841ab66cSSepherosa Ziehau */ 1029841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(ni); 1030f186073cSJoerg Sonnenberger } 1031f186073cSJoerg Sonnenberger 1032f186073cSJoerg Sonnenberger static void 1033841ab66cSSepherosa Ziehau node_free(struct ieee80211_node *ni) 1034f186073cSJoerg Sonnenberger { 1035841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1036841ab66cSSepherosa Ziehau 10374028af95SRui Paulo ieee80211_ratectl_node_deinit(ni); 1038841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 103932176cfdSRui Paulo ieee80211_ies_cleanup(&ni->ni_ies); 104032176cfdSRui Paulo ieee80211_psq_cleanup(&ni->ni_psq); 1041efda3bd0SMatthew Dillon kfree(ni, M_80211_NODE); 1042f186073cSJoerg Sonnenberger } 1043f186073cSJoerg Sonnenberger 104432176cfdSRui Paulo static void 104532176cfdSRui Paulo node_age(struct ieee80211_node *ni) 104632176cfdSRui Paulo { 104732176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 104832176cfdSRui Paulo 104932176cfdSRui Paulo /* 105032176cfdSRui Paulo * Age frames on the power save queue. 105132176cfdSRui Paulo */ 105232176cfdSRui Paulo if (ieee80211_node_psq_age(ni) != 0 && 105332176cfdSRui Paulo ni->ni_psq.psq_len == 0 && vap->iv_set_tim != NULL) 105432176cfdSRui Paulo vap->iv_set_tim(ni, 0); 105532176cfdSRui Paulo /* 105632176cfdSRui Paulo * Age out HT resources (e.g. frames on the 105732176cfdSRui Paulo * A-MPDU reorder queues). 105832176cfdSRui Paulo */ 105932176cfdSRui Paulo if (ni->ni_associd != 0 && (ni->ni_flags & IEEE80211_NODE_HT)) 106032176cfdSRui Paulo ieee80211_ht_node_age(ni); 106132176cfdSRui Paulo } 106232176cfdSRui Paulo 106332176cfdSRui Paulo static int8_t 1064841ab66cSSepherosa Ziehau node_getrssi(const struct ieee80211_node *ni) 1065f186073cSJoerg Sonnenberger { 106632176cfdSRui Paulo uint32_t avgrssi = ni->ni_avgrssi; 106732176cfdSRui Paulo int32_t rssi; 106832176cfdSRui Paulo 106932176cfdSRui Paulo if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) 107032176cfdSRui Paulo return 0; 107132176cfdSRui Paulo rssi = IEEE80211_RSSI_GET(avgrssi); 107232176cfdSRui Paulo return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 1073f186073cSJoerg Sonnenberger } 1074f186073cSJoerg Sonnenberger 1075f186073cSJoerg Sonnenberger static void 107632176cfdSRui Paulo node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise) 107732176cfdSRui Paulo { 107832176cfdSRui Paulo *rssi = node_getrssi(ni); 107932176cfdSRui Paulo *noise = ni->ni_noise; 108032176cfdSRui Paulo } 108132176cfdSRui Paulo 108232176cfdSRui Paulo static void 108332176cfdSRui Paulo node_getmimoinfo(const struct ieee80211_node *ni, 108432176cfdSRui Paulo struct ieee80211_mimo_info *info) 108532176cfdSRui Paulo { 108632176cfdSRui Paulo /* XXX zero data? */ 108732176cfdSRui Paulo } 108832176cfdSRui Paulo 108932176cfdSRui Paulo struct ieee80211_node * 109032176cfdSRui Paulo ieee80211_alloc_node(struct ieee80211_node_table *nt, 109132176cfdSRui Paulo struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1092f186073cSJoerg Sonnenberger { 1093841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 109432176cfdSRui Paulo struct ieee80211_node *ni; 1095f186073cSJoerg Sonnenberger int hash; 1096f186073cSJoerg Sonnenberger 109732176cfdSRui Paulo ni = ic->ic_node_alloc(vap, macaddr); 109832176cfdSRui Paulo if (ni == NULL) { 109932176cfdSRui Paulo vap->iv_stats.is_rx_nodealloc++; 110032176cfdSRui Paulo return NULL; 110132176cfdSRui Paulo } 1102841ab66cSSepherosa Ziehau 110332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 11046168f72eSRui Paulo "%s %p<%6D> in %s table\n", __func__, ni, 11056168f72eSRui Paulo macaddr, ":", nt->nt_name); 1106841ab66cSSepherosa Ziehau 1107f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 110832176cfdSRui Paulo hash = IEEE80211_NODE_HASH(ic, macaddr); 1109841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 1110841ab66cSSepherosa Ziehau ni->ni_chan = IEEE80211_CHAN_ANYC; 1111841ab66cSSepherosa Ziehau ni->ni_authmode = IEEE80211_AUTH_OPEN; 1112841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 111332176cfdSRui Paulo ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 111432176cfdSRui Paulo ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 111532176cfdSRui Paulo ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER; 1116841ab66cSSepherosa Ziehau ni->ni_inact_reload = nt->nt_inact_init; 1117841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 111832176cfdSRui Paulo ni->ni_ath_defkeyix = 0x7fff; 111932176cfdSRui Paulo ieee80211_psq_init(&ni->ni_psq, "unknown"); 112032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 112132176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 112232176cfdSRui Paulo ieee80211_mesh_node_init(vap, ni); 112332176cfdSRui Paulo #endif 1124841ab66cSSepherosa Ziehau TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 1125841ab66cSSepherosa Ziehau LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 1126841ab66cSSepherosa Ziehau ni->ni_table = nt; 112732176cfdSRui Paulo ni->ni_vap = vap; 1128841ab66cSSepherosa Ziehau ni->ni_ic = ic; 1129b9334f94SSepherosa Ziehau 113032176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 113132176cfdSRui Paulo "%s: inact_reload %u", __func__, ni->ni_inact_reload); 1132f186073cSJoerg Sonnenberger 1133f186073cSJoerg Sonnenberger return ni; 1134f186073cSJoerg Sonnenberger } 1135f186073cSJoerg Sonnenberger 1136841ab66cSSepherosa Ziehau /* 1137841ab66cSSepherosa Ziehau * Craft a temporary node suitable for sending a management frame 1138841ab66cSSepherosa Ziehau * to the specified station. We craft only as much state as we 1139841ab66cSSepherosa Ziehau * need to do the work since the node will be immediately reclaimed 1140841ab66cSSepherosa Ziehau * once the send completes. 1141841ab66cSSepherosa Ziehau */ 1142f186073cSJoerg Sonnenberger struct ieee80211_node * 114332176cfdSRui Paulo ieee80211_tmp_node(struct ieee80211vap *vap, 114432176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1145f186073cSJoerg Sonnenberger { 114632176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 1147841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1148841ab66cSSepherosa Ziehau 114932176cfdSRui Paulo ni = ic->ic_node_alloc(vap, macaddr); 1150f186073cSJoerg Sonnenberger if (ni != NULL) { 115132176cfdSRui Paulo struct ieee80211_node *bss = vap->iv_bss; 1152841ab66cSSepherosa Ziehau 115332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 11546168f72eSRui Paulo "%s %p<%6D>\n", __func__, ni, macaddr, ":"); 1155841ab66cSSepherosa Ziehau 1156841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* NB: pedantic */ 115732176cfdSRui Paulo ni->ni_ic = ic; /* NB: needed to set channel */ 115832176cfdSRui Paulo ni->ni_vap = vap; 115932176cfdSRui Paulo 116032176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 116132176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); 116232176cfdSRui Paulo ieee80211_node_initref(ni); /* mark referenced */ 116332176cfdSRui Paulo /* NB: required by ieee80211_fix_rate */ 116432176cfdSRui Paulo ieee80211_node_set_chan(ni, bss->ni_chan); 116532176cfdSRui Paulo ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, 116632176cfdSRui Paulo IEEE80211_KEYIX_NONE); 116732176cfdSRui Paulo ni->ni_txpower = bss->ni_txpower; 116832176cfdSRui Paulo /* XXX optimize away */ 116932176cfdSRui Paulo ieee80211_psq_init(&ni->ni_psq, "unknown"); 1170841ab66cSSepherosa Ziehau } else { 1171841ab66cSSepherosa Ziehau /* XXX msg */ 117232176cfdSRui Paulo vap->iv_stats.is_rx_nodealloc++; 1173841ab66cSSepherosa Ziehau } 1174841ab66cSSepherosa Ziehau return ni; 1175841ab66cSSepherosa Ziehau } 1176841ab66cSSepherosa Ziehau 1177841ab66cSSepherosa Ziehau struct ieee80211_node * 117832176cfdSRui Paulo ieee80211_dup_bss(struct ieee80211vap *vap, 117932176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1180841ab66cSSepherosa Ziehau { 118132176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 1182841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1183841ab66cSSepherosa Ziehau 118432176cfdSRui Paulo ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr); 1185841ab66cSSepherosa Ziehau if (ni != NULL) { 118632176cfdSRui Paulo struct ieee80211_node *bss = vap->iv_bss; 1187f186073cSJoerg Sonnenberger /* 118832176cfdSRui Paulo * Inherit from iv_bss. 1189f186073cSJoerg Sonnenberger */ 119032176cfdSRui Paulo copy_bss(ni, bss); 119132176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); 119232176cfdSRui Paulo ieee80211_node_set_chan(ni, bss->ni_chan); 119332176cfdSRui Paulo } 1194f186073cSJoerg Sonnenberger return ni; 1195f186073cSJoerg Sonnenberger } 1196f186073cSJoerg Sonnenberger 119732176cfdSRui Paulo /* 119832176cfdSRui Paulo * Create a bss node for a legacy WDS vap. The far end does 119932176cfdSRui Paulo * not associate so we just create create a new node and 120032176cfdSRui Paulo * simulate an association. The caller is responsible for 120132176cfdSRui Paulo * installing the node as the bss node and handling any further 120232176cfdSRui Paulo * setup work like authorizing the port. 120332176cfdSRui Paulo */ 120432176cfdSRui Paulo struct ieee80211_node * 120532176cfdSRui Paulo ieee80211_node_create_wds(struct ieee80211vap *vap, 120632176cfdSRui Paulo const uint8_t bssid[IEEE80211_ADDR_LEN], struct ieee80211_channel *chan) 120732176cfdSRui Paulo { 120832176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 120932176cfdSRui Paulo struct ieee80211_node *ni; 121032176cfdSRui Paulo 121132176cfdSRui Paulo /* XXX check if node already in sta table? */ 121232176cfdSRui Paulo ni = ieee80211_alloc_node(&ic->ic_sta, vap, bssid); 121332176cfdSRui Paulo if (ni != NULL) { 121432176cfdSRui Paulo ni->ni_wdsvap = vap; 121532176cfdSRui Paulo IEEE80211_ADDR_COPY(ni->ni_bssid, bssid); 121632176cfdSRui Paulo /* 121732176cfdSRui Paulo * Inherit any manually configured settings. 121832176cfdSRui Paulo */ 121932176cfdSRui Paulo copy_bss(ni, vap->iv_bss); 122032176cfdSRui Paulo ieee80211_node_set_chan(ni, chan); 122132176cfdSRui Paulo /* NB: propagate ssid so available to WPA supplicant */ 122232176cfdSRui Paulo ni->ni_esslen = vap->iv_des_ssid[0].len; 122332176cfdSRui Paulo memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 122432176cfdSRui Paulo /* NB: no associd for peer */ 122532176cfdSRui Paulo /* 122632176cfdSRui Paulo * There are no management frames to use to 122732176cfdSRui Paulo * discover neighbor capabilities, so blindly 122832176cfdSRui Paulo * propagate the local configuration. 122932176cfdSRui Paulo */ 123032176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) 123132176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_QOS; 123232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 123332176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_FF) 123432176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_FF; 123532176cfdSRui Paulo #endif 123632176cfdSRui Paulo if ((ic->ic_htcaps & IEEE80211_HTC_HT) && 123732176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_HT)) { 123832176cfdSRui Paulo /* 123932176cfdSRui Paulo * Device is HT-capable and HT is enabled for 124032176cfdSRui Paulo * the vap; setup HT operation. On return 124132176cfdSRui Paulo * ni_chan will be adjusted to an HT channel. 124232176cfdSRui Paulo */ 124332176cfdSRui Paulo ieee80211_ht_wds_init(ni); 124432176cfdSRui Paulo } else { 124532176cfdSRui Paulo struct ieee80211_channel *c = ni->ni_chan; 124632176cfdSRui Paulo /* 124732176cfdSRui Paulo * Force a legacy channel to be used. 124832176cfdSRui Paulo */ 124932176cfdSRui Paulo c = ieee80211_find_channel(ic, 125032176cfdSRui Paulo c->ic_freq, c->ic_flags &~ IEEE80211_CHAN_HT); 125132176cfdSRui Paulo KASSERT(c != NULL, ("no legacy channel, %u/%x", 125232176cfdSRui Paulo ni->ni_chan->ic_freq, ni->ni_chan->ic_flags)); 125332176cfdSRui Paulo ni->ni_chan = c; 125432176cfdSRui Paulo } 125532176cfdSRui Paulo } 125632176cfdSRui Paulo return ni; 125732176cfdSRui Paulo } 125832176cfdSRui Paulo 125932176cfdSRui Paulo struct ieee80211_node * 1260841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 126132176cfdSRui Paulo ieee80211_find_node_locked_debug(struct ieee80211_node_table *nt, 126232176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1263841ab66cSSepherosa Ziehau #else 126432176cfdSRui Paulo ieee80211_find_node_locked(struct ieee80211_node_table *nt, 126532176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1266841ab66cSSepherosa Ziehau #endif 1267f186073cSJoerg Sonnenberger { 1268f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1269f186073cSJoerg Sonnenberger int hash; 1270f186073cSJoerg Sonnenberger 127132176cfdSRui Paulo hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr); 1272841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1273f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1274841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1275841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 127632176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 12776168f72eSRui Paulo "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1278841ab66cSSepherosa Ziehau func, line, 12796168f72eSRui Paulo ni, ni->ni_macaddr, ":", 1280841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1281841ab66cSSepherosa Ziehau #endif 1282f186073cSJoerg Sonnenberger return ni; 1283f186073cSJoerg Sonnenberger } 1284f186073cSJoerg Sonnenberger } 1285f186073cSJoerg Sonnenberger return NULL; 1286f186073cSJoerg Sonnenberger } 1287f186073cSJoerg Sonnenberger 1288f186073cSJoerg Sonnenberger struct ieee80211_node * 1289841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1290841ab66cSSepherosa Ziehau ieee80211_find_node_debug(struct ieee80211_node_table *nt, 129132176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1292841ab66cSSepherosa Ziehau #else 129332176cfdSRui Paulo ieee80211_find_node(struct ieee80211_node_table *nt, 129432176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1295841ab66cSSepherosa Ziehau #endif 1296f186073cSJoerg Sonnenberger { 1297f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1298f186073cSJoerg Sonnenberger 129932176cfdSRui Paulo ni = ieee80211_find_node_locked(nt, macaddr); 130032176cfdSRui Paulo return ni; 130132176cfdSRui Paulo } 1302841ab66cSSepherosa Ziehau 130332176cfdSRui Paulo struct ieee80211_node * 130432176cfdSRui Paulo #ifdef IEEE80211_DEBUG_REFCNT 130532176cfdSRui Paulo ieee80211_find_vap_node_locked_debug(struct ieee80211_node_table *nt, 130632176cfdSRui Paulo const struct ieee80211vap *vap, 130732176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 130832176cfdSRui Paulo #else 130932176cfdSRui Paulo ieee80211_find_vap_node_locked(struct ieee80211_node_table *nt, 131032176cfdSRui Paulo const struct ieee80211vap *vap, 131132176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 131232176cfdSRui Paulo #endif 131332176cfdSRui Paulo { 131432176cfdSRui Paulo struct ieee80211_node *ni; 131532176cfdSRui Paulo int hash; 131632176cfdSRui Paulo 131732176cfdSRui Paulo hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr); 131832176cfdSRui Paulo LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 131932176cfdSRui Paulo if (ni->ni_vap == vap && 132032176cfdSRui Paulo IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 132132176cfdSRui Paulo ieee80211_ref_node(ni); /* mark referenced */ 132232176cfdSRui Paulo #ifdef IEEE80211_DEBUG_REFCNT 132332176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 13246168f72eSRui Paulo "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 132532176cfdSRui Paulo func, line, 13266168f72eSRui Paulo ni, ni->ni_macaddr, ":", 132732176cfdSRui Paulo ieee80211_node_refcnt(ni)); 132832176cfdSRui Paulo #endif 132932176cfdSRui Paulo return ni; 133032176cfdSRui Paulo } 133132176cfdSRui Paulo } 133232176cfdSRui Paulo return NULL; 133332176cfdSRui Paulo } 133432176cfdSRui Paulo 133532176cfdSRui Paulo struct ieee80211_node * 133632176cfdSRui Paulo #ifdef IEEE80211_DEBUG_REFCNT 133732176cfdSRui Paulo ieee80211_find_vap_node_debug(struct ieee80211_node_table *nt, 133832176cfdSRui Paulo const struct ieee80211vap *vap, 133932176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 134032176cfdSRui Paulo #else 134132176cfdSRui Paulo ieee80211_find_vap_node(struct ieee80211_node_table *nt, 134232176cfdSRui Paulo const struct ieee80211vap *vap, 134332176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 134432176cfdSRui Paulo #endif 134532176cfdSRui Paulo { 134632176cfdSRui Paulo struct ieee80211_node *ni; 134732176cfdSRui Paulo 134832176cfdSRui Paulo ni = ieee80211_find_vap_node_locked(nt, vap, macaddr); 1349f186073cSJoerg Sonnenberger return ni; 1350f186073cSJoerg Sonnenberger } 1351f186073cSJoerg Sonnenberger 1352f186073cSJoerg Sonnenberger /* 1353841ab66cSSepherosa Ziehau * Fake up a node; this handles node discovery in adhoc mode. 1354841ab66cSSepherosa Ziehau * Note that for the driver's benefit we we treat this like 1355841ab66cSSepherosa Ziehau * an association so the driver has an opportunity to setup 1356841ab66cSSepherosa Ziehau * it's private state. 1357841ab66cSSepherosa Ziehau */ 1358841ab66cSSepherosa Ziehau struct ieee80211_node * 135932176cfdSRui Paulo ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, 1360841ab66cSSepherosa Ziehau const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1361841ab66cSSepherosa Ziehau { 1362841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1363841ab66cSSepherosa Ziehau 136432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 13656168f72eSRui Paulo "%s: mac<%6D>\n", __func__, macaddr, ":"); 136632176cfdSRui Paulo ni = ieee80211_dup_bss(vap, macaddr); 1367841ab66cSSepherosa Ziehau if (ni != NULL) { 136832176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 136932176cfdSRui Paulo 1370841ab66cSSepherosa Ziehau /* XXX no rate negotiation; just dup */ 137132176cfdSRui Paulo ni->ni_rates = vap->iv_bss->ni_rates; 137232176cfdSRui Paulo if (ieee80211_iserp_rateset(&ni->ni_rates)) 137332176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_ERP; 137432176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 137532176cfdSRui Paulo /* 137632176cfdSRui Paulo * In adhoc demo mode there are no management 137732176cfdSRui Paulo * frames to use to discover neighbor capabilities, 137832176cfdSRui Paulo * so blindly propagate the local configuration 137932176cfdSRui Paulo * so we can do interesting things (e.g. use 138032176cfdSRui Paulo * WME to disable ACK's). 138132176cfdSRui Paulo */ 138232176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) 138332176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_QOS; 138432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 138532176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_FF) 138632176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_FF; 138732176cfdSRui Paulo #endif 138832176cfdSRui Paulo } 138932176cfdSRui Paulo ieee80211_node_setuptxparms(ni); 1390841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1391841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1392841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1393841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1394841ab66cSSepherosa Ziehau } 1395841ab66cSSepherosa Ziehau return ni; 1396841ab66cSSepherosa Ziehau } 1397841ab66cSSepherosa Ziehau 1398841ab66cSSepherosa Ziehau void 1399841ab66cSSepherosa Ziehau ieee80211_init_neighbor(struct ieee80211_node *ni, 1400841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1401841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1402841ab66cSSepherosa Ziehau { 1403841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1404841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1405841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1406841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1407841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1408841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1409841ab66cSSepherosa Ziehau ni->ni_chan = ni->ni_ic->ic_curchan; 1410841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1411841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1412841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1413841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 141432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 141532176cfdSRui Paulo if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS) 141632176cfdSRui Paulo ieee80211_mesh_init_neighbor(ni, wh, sp); 141732176cfdSRui Paulo #endif 141832176cfdSRui Paulo if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) { 141932176cfdSRui Paulo ieee80211_ies_expand(&ni->ni_ies); 142032176cfdSRui Paulo if (ni->ni_ies.wme_ie != NULL) 142132176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_QOS; 142232176cfdSRui Paulo else 142332176cfdSRui Paulo ni->ni_flags &= ~IEEE80211_NODE_QOS; 142432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 142532176cfdSRui Paulo if (ni->ni_ies.ath_ie != NULL) 142632176cfdSRui Paulo ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 142732176cfdSRui Paulo #endif 142832176cfdSRui Paulo } 1429841ab66cSSepherosa Ziehau 1430841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1431208a1285SSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, 1432208a1285SSepherosa Ziehau IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | 143332176cfdSRui Paulo IEEE80211_F_DONEGO | IEEE80211_F_DODEL); 1434841ab66cSSepherosa Ziehau } 1435841ab66cSSepherosa Ziehau 1436841ab66cSSepherosa Ziehau /* 1437841ab66cSSepherosa Ziehau * Do node discovery in adhoc mode on receipt of a beacon 1438841ab66cSSepherosa Ziehau * or probe response frame. Note that for the driver's 1439841ab66cSSepherosa Ziehau * benefit we we treat this like an association so the 1440841ab66cSSepherosa Ziehau * driver has an opportunity to setup it's private state. 1441841ab66cSSepherosa Ziehau */ 1442841ab66cSSepherosa Ziehau struct ieee80211_node * 144332176cfdSRui Paulo ieee80211_add_neighbor(struct ieee80211vap *vap, 1444841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1445841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1446841ab66cSSepherosa Ziehau { 1447841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1448841ab66cSSepherosa Ziehau 144932176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 14506168f72eSRui Paulo "%s: mac<%6D>\n", __func__, wh->i_addr2, ":"); 145132176cfdSRui Paulo ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */ 1452841ab66cSSepherosa Ziehau if (ni != NULL) { 145332176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 145432176cfdSRui Paulo 1455841ab66cSSepherosa Ziehau ieee80211_init_neighbor(ni, wh, sp); 145632176cfdSRui Paulo if (ieee80211_iserp_rateset(&ni->ni_rates)) 145732176cfdSRui Paulo ni->ni_flags |= IEEE80211_NODE_ERP; 145832176cfdSRui Paulo ieee80211_node_setuptxparms(ni); 1459841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1460841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1461841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1462841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1463841ab66cSSepherosa Ziehau } 1464841ab66cSSepherosa Ziehau return ni; 1465841ab66cSSepherosa Ziehau } 1466841ab66cSSepherosa Ziehau 146732176cfdSRui Paulo #define IS_PROBEREQ(wh) \ 146832176cfdSRui Paulo ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) \ 146932176cfdSRui Paulo == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ)) 147032176cfdSRui Paulo #define IS_BCAST_PROBEREQ(wh) \ 147132176cfdSRui Paulo (IS_PROBEREQ(wh) && IEEE80211_IS_MULTICAST( \ 147232176cfdSRui Paulo ((const struct ieee80211_frame *)(wh))->i_addr3)) 147332176cfdSRui Paulo 147432176cfdSRui Paulo static __inline struct ieee80211_node * 147532176cfdSRui Paulo _find_rxnode(struct ieee80211_node_table *nt, 147632176cfdSRui Paulo const struct ieee80211_frame_min *wh) 147732176cfdSRui Paulo { 147832176cfdSRui Paulo if (IS_BCAST_PROBEREQ(wh)) 147932176cfdSRui Paulo return NULL; /* spam bcast probe req to all vap's */ 148032176cfdSRui Paulo return ieee80211_find_node_locked(nt, wh->i_addr2); 148132176cfdSRui Paulo } 148232176cfdSRui Paulo 1483841ab66cSSepherosa Ziehau /* 1484841ab66cSSepherosa Ziehau * Locate the node for sender, track state, and then pass the 148532176cfdSRui Paulo * (referenced) node up to the 802.11 layer for its use. Note 148632176cfdSRui Paulo * we can return NULL if the sender is not in the table. 1487841ab66cSSepherosa Ziehau */ 1488841ab66cSSepherosa Ziehau struct ieee80211_node * 1489841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1490841ab66cSSepherosa Ziehau ieee80211_find_rxnode_debug(struct ieee80211com *ic, 1491841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, const char *func, int line) 1492841ab66cSSepherosa Ziehau #else 1493841ab66cSSepherosa Ziehau ieee80211_find_rxnode(struct ieee80211com *ic, 1494841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh) 1495841ab66cSSepherosa Ziehau #endif 1496841ab66cSSepherosa Ziehau { 1497841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1498841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1499841ab66cSSepherosa Ziehau 1500841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 150132176cfdSRui Paulo ni = _find_rxnode(nt, wh); 1502841ab66cSSepherosa Ziehau 1503841ab66cSSepherosa Ziehau return ni; 1504841ab66cSSepherosa Ziehau } 1505841ab66cSSepherosa Ziehau 1506841ab66cSSepherosa Ziehau /* 1507841ab66cSSepherosa Ziehau * Like ieee80211_find_rxnode but use the supplied h/w 1508841ab66cSSepherosa Ziehau * key index as a hint to locate the node in the key 1509841ab66cSSepherosa Ziehau * mapping table. If an entry is present at the key 1510841ab66cSSepherosa Ziehau * index we return it; otherwise do a normal lookup and 1511841ab66cSSepherosa Ziehau * update the mapping table if the station has a unicast 1512841ab66cSSepherosa Ziehau * key assigned to it. 1513841ab66cSSepherosa Ziehau */ 1514841ab66cSSepherosa Ziehau struct ieee80211_node * 1515841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1516841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1517841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1518841ab66cSSepherosa Ziehau const char *func, int line) 1519841ab66cSSepherosa Ziehau #else 1520841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1521841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1522841ab66cSSepherosa Ziehau #endif 1523841ab66cSSepherosa Ziehau { 1524841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1525841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1526841ab66cSSepherosa Ziehau 1527841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1528841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1529841ab66cSSepherosa Ziehau ni = nt->nt_keyixmap[keyix]; 1530841ab66cSSepherosa Ziehau else 1531841ab66cSSepherosa Ziehau ni = NULL; 1532841ab66cSSepherosa Ziehau if (ni == NULL) { 153332176cfdSRui Paulo ni = _find_rxnode(nt, wh); 153432176cfdSRui Paulo if (ni != NULL && nt->nt_keyixmap != NULL) { 1535841ab66cSSepherosa Ziehau /* 1536841ab66cSSepherosa Ziehau * If the station has a unicast key cache slot 1537841ab66cSSepherosa Ziehau * assigned update the key->node mapping table. 1538841ab66cSSepherosa Ziehau */ 1539841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1540841ab66cSSepherosa Ziehau /* XXX can keyixmap[keyix] != NULL? */ 1541841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1542841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == NULL) { 154332176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, 154432176cfdSRui Paulo IEEE80211_MSG_NODE, 15456168f72eSRui Paulo "%s: add key map entry %p<%6D> refcnt %d\n", 15466168f72eSRui Paulo __func__, ni, ni->ni_macaddr, ":", 1547841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 1548841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1549841ab66cSSepherosa Ziehau } 1550841ab66cSSepherosa Ziehau } 1551841ab66cSSepherosa Ziehau } else { 155232176cfdSRui Paulo if (IS_BCAST_PROBEREQ(wh)) 155332176cfdSRui Paulo ni = NULL; /* spam bcast probe req to all vap's */ 155432176cfdSRui Paulo else 1555841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1556841ab66cSSepherosa Ziehau } 1557841ab66cSSepherosa Ziehau return ni; 1558841ab66cSSepherosa Ziehau } 155932176cfdSRui Paulo #undef IS_BCAST_PROBEREQ 156032176cfdSRui Paulo #undef IS_PROBEREQ 1561841ab66cSSepherosa Ziehau 1562841ab66cSSepherosa Ziehau /* 1563f186073cSJoerg Sonnenberger * Return a reference to the appropriate node for sending 1564f186073cSJoerg Sonnenberger * a data frame. This handles node discovery in adhoc networks. 1565f186073cSJoerg Sonnenberger */ 1566f186073cSJoerg Sonnenberger struct ieee80211_node * 1567841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 156832176cfdSRui Paulo ieee80211_find_txnode_debug(struct ieee80211vap *vap, 156932176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN], 1570841ab66cSSepherosa Ziehau const char *func, int line) 1571841ab66cSSepherosa Ziehau #else 157232176cfdSRui Paulo ieee80211_find_txnode(struct ieee80211vap *vap, 157332176cfdSRui Paulo const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1574841ab66cSSepherosa Ziehau #endif 1575f186073cSJoerg Sonnenberger { 157632176cfdSRui Paulo struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta; 1577f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1578841ab66cSSepherosa Ziehau 1579f186073cSJoerg Sonnenberger /* 1580f186073cSJoerg Sonnenberger * The destination address should be in the node table 1581841ab66cSSepherosa Ziehau * unless this is a multicast/broadcast frame. We can 1582841ab66cSSepherosa Ziehau * also optimize station mode operation, all frames go 1583841ab66cSSepherosa Ziehau * to the bss node. 1584f186073cSJoerg Sonnenberger */ 158532176cfdSRui Paulo /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ 158632176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA || 158732176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_WDS || 158832176cfdSRui Paulo IEEE80211_IS_MULTICAST(macaddr)) 158932176cfdSRui Paulo ni = ieee80211_ref_node(vap->iv_bss); 159032176cfdSRui Paulo else 159132176cfdSRui Paulo ni = ieee80211_find_node_locked(nt, macaddr); 1592f186073cSJoerg Sonnenberger 1593841ab66cSSepherosa Ziehau if (ni == NULL) { 159432176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS || 159532176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_AHDEMO) { 1596f186073cSJoerg Sonnenberger /* 1597841ab66cSSepherosa Ziehau * In adhoc mode cons up a node for the destination. 1598841ab66cSSepherosa Ziehau * Note that we need an additional reference for the 159932176cfdSRui Paulo * caller to be consistent with 160032176cfdSRui Paulo * ieee80211_find_node_locked. 1601f186073cSJoerg Sonnenberger */ 160232176cfdSRui Paulo ni = ieee80211_fakeup_adhoc_node(vap, macaddr); 1603841ab66cSSepherosa Ziehau if (ni != NULL) 160432176cfdSRui Paulo (void) ieee80211_ref_node(ni); 1605841ab66cSSepherosa Ziehau } else { 160632176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, macaddr, 160732176cfdSRui Paulo "no node, discard frame (%s)", __func__); 160832176cfdSRui Paulo vap->iv_stats.is_tx_nonode++; 1609f186073cSJoerg Sonnenberger } 1610f186073cSJoerg Sonnenberger } 1611f186073cSJoerg Sonnenberger return ni; 1612f186073cSJoerg Sonnenberger } 1613f186073cSJoerg Sonnenberger 1614841ab66cSSepherosa Ziehau static void 1615841ab66cSSepherosa Ziehau _ieee80211_free_node(struct ieee80211_node *ni) 1616841ab66cSSepherosa Ziehau { 1617841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1618841ab66cSSepherosa Ziehau 161932176cfdSRui Paulo /* 162032176cfdSRui Paulo * NB: careful about referencing the vap as it may be 162132176cfdSRui Paulo * gone if the last reference was held by a driver. 162232176cfdSRui Paulo * We know the com will always be present so it's safe 162332176cfdSRui Paulo * to use ni_ic below to reclaim resources. 162432176cfdSRui Paulo */ 162532176cfdSRui Paulo #if 0 162632176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 16276168f72eSRui Paulo "%s %p<%6D> in %s table\n", __func__, ni, 16286168f72eSRui Paulo ni->ni_macaddr, ":", 1629841ab66cSSepherosa Ziehau nt != NULL ? nt->nt_name : "<gone>"); 163032176cfdSRui Paulo #endif 163132176cfdSRui Paulo if (ni->ni_associd != 0) { 163232176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 163332176cfdSRui Paulo if (vap->iv_aid_bitmap != NULL) 163432176cfdSRui Paulo IEEE80211_AID_CLR(vap, ni->ni_associd); 163532176cfdSRui Paulo } 1636841ab66cSSepherosa Ziehau if (nt != NULL) { 1637841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1638841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1639841ab66cSSepherosa Ziehau } 164032176cfdSRui Paulo ni->ni_ic->ic_node_free(ni); 1641841ab66cSSepherosa Ziehau } 1642841ab66cSSepherosa Ziehau 1643841ab66cSSepherosa Ziehau void 1644841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1645841ab66cSSepherosa Ziehau ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1646841ab66cSSepherosa Ziehau #else 1647841ab66cSSepherosa Ziehau ieee80211_free_node(struct ieee80211_node *ni) 1648841ab66cSSepherosa Ziehau #endif 1649841ab66cSSepherosa Ziehau { 1650841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1651841ab66cSSepherosa Ziehau 1652841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 165332176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 16546168f72eSRui Paulo "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, func, line, ni, 16556168f72eSRui Paulo ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)-1); 1656841ab66cSSepherosa Ziehau #endif 1657841ab66cSSepherosa Ziehau if (nt != NULL) { 1658841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) { 1659841ab66cSSepherosa Ziehau /* 1660841ab66cSSepherosa Ziehau * Last reference, reclaim state. 1661841ab66cSSepherosa Ziehau */ 1662841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1663841ab66cSSepherosa Ziehau } else if (ieee80211_node_refcnt(ni) == 1 && 1664841ab66cSSepherosa Ziehau nt->nt_keyixmap != NULL) { 1665841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1666841ab66cSSepherosa Ziehau /* 1667841ab66cSSepherosa Ziehau * Check for a last reference in the key mapping table. 1668841ab66cSSepherosa Ziehau */ 1669841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1670841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1671841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 167232176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, 167332176cfdSRui Paulo IEEE80211_MSG_NODE, 16746168f72eSRui Paulo "%s: %p<%6D> clear key map entry", __func__, 16756168f72eSRui Paulo ni, ni->ni_macaddr, ":"); 1676841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1677841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* XXX needed? */ 1678841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1679841ab66cSSepherosa Ziehau } 1680841ab66cSSepherosa Ziehau } 1681841ab66cSSepherosa Ziehau } else { 1682841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) 1683841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1684841ab66cSSepherosa Ziehau } 1685f186073cSJoerg Sonnenberger } 1686f186073cSJoerg Sonnenberger 1687f186073cSJoerg Sonnenberger /* 1688841ab66cSSepherosa Ziehau * Reclaim a unicast key and clear any key cache state. 1689841ab66cSSepherosa Ziehau */ 1690841ab66cSSepherosa Ziehau int 1691841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(struct ieee80211_node *ni) 1692841ab66cSSepherosa Ziehau { 1693841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1694841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1695841ab66cSSepherosa Ziehau struct ieee80211_node *nikey; 1696841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 169726c6f223SMatthew Dillon int status; 1698841ab66cSSepherosa Ziehau 169932176cfdSRui Paulo /* 170032176cfdSRui Paulo * NB: We must beware of LOR here; deleting the key 170132176cfdSRui Paulo * can cause the crypto layer to block traffic updates 170232176cfdSRui Paulo * which can generate a LOR against the node table lock; 170332176cfdSRui Paulo * grab it here and stash the key index for our use below. 170432176cfdSRui Paulo * 170532176cfdSRui Paulo * Must also beware of recursion on the node table lock. 170632176cfdSRui Paulo * When called from node_cleanup we may already have 170732176cfdSRui Paulo * the node table lock held. Unfortunately there's no 170832176cfdSRui Paulo * way to separate out this path so we must do this 170932176cfdSRui Paulo * conditionally. 171032176cfdSRui Paulo */ 171132176cfdSRui Paulo nikey = NULL; 171232176cfdSRui Paulo status = 1; /* NB: success */ 171332176cfdSRui Paulo if (ni->ni_ucastkey.wk_keyix != IEEE80211_KEYIX_NONE) { 1714841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 171532176cfdSRui Paulo status = ieee80211_crypto_delkey(ni->ni_vap, &ni->ni_ucastkey); 1716841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1717841ab66cSSepherosa Ziehau nikey = nt->nt_keyixmap[keyix]; 1718fc6d0222SSascha Wildner nt->nt_keyixmap[keyix] = NULL; 171932176cfdSRui Paulo } 172032176cfdSRui Paulo } 1721841ab66cSSepherosa Ziehau 1722841ab66cSSepherosa Ziehau if (nikey != NULL) { 1723841ab66cSSepherosa Ziehau KASSERT(nikey == ni, 1724841ab66cSSepherosa Ziehau ("key map out of sync, ni %p nikey %p", ni, nikey)); 172532176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 17266168f72eSRui Paulo "%s: delete key map entry %p<%6D> refcnt %d\n", 17276168f72eSRui Paulo __func__, ni, ni->ni_macaddr, ":", 1728841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)-1); 1729841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1730841ab66cSSepherosa Ziehau } 1731841ab66cSSepherosa Ziehau return status; 1732841ab66cSSepherosa Ziehau } 1733841ab66cSSepherosa Ziehau 1734841ab66cSSepherosa Ziehau /* 1735841ab66cSSepherosa Ziehau * Reclaim a node. If this is the last reference count then 1736841ab66cSSepherosa Ziehau * do the normal free work. Otherwise remove it from the node 1737841ab66cSSepherosa Ziehau * table and mark it gone by clearing the back-reference. 1738841ab66cSSepherosa Ziehau */ 1739841ab66cSSepherosa Ziehau static void 1740841ab66cSSepherosa Ziehau node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1741841ab66cSSepherosa Ziehau { 1742841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1743841ab66cSSepherosa Ziehau 174432176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 17456168f72eSRui Paulo "%s: remove %p<%6D> from %s table, refcnt %d\n", 17466168f72eSRui Paulo __func__, ni, ni->ni_macaddr, ":", 1747841ab66cSSepherosa Ziehau nt->nt_name, ieee80211_node_refcnt(ni)-1); 1748841ab66cSSepherosa Ziehau /* 1749841ab66cSSepherosa Ziehau * Clear any entry in the unicast key mapping table. 1750841ab66cSSepherosa Ziehau * We need to do it here so rx lookups don't find it 1751841ab66cSSepherosa Ziehau * in the mapping table even if it's not in the hash 1752841ab66cSSepherosa Ziehau * table. We cannot depend on the mapping table entry 1753841ab66cSSepherosa Ziehau * being cleared because the node may not be free'd. 1754841ab66cSSepherosa Ziehau */ 1755841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1756841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1757841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 175832176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 17596168f72eSRui Paulo "%s: %p<%6D> clear key map entry %u\n", 17606168f72eSRui Paulo __func__, ni, ni->ni_macaddr, ":", keyix); 1761841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1762841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* NB: don't need free */ 1763841ab66cSSepherosa Ziehau } 1764841ab66cSSepherosa Ziehau if (!ieee80211_node_dectestref(ni)) { 1765841ab66cSSepherosa Ziehau /* 1766841ab66cSSepherosa Ziehau * Other references are present, just remove the 1767841ab66cSSepherosa Ziehau * node from the table so it cannot be found. When 1768841ab66cSSepherosa Ziehau * the references are dropped storage will be 1769841ab66cSSepherosa Ziehau * reclaimed. 1770841ab66cSSepherosa Ziehau */ 1771841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1772841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1773841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* clear reference */ 1774841ab66cSSepherosa Ziehau } else 1775841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1776841ab66cSSepherosa Ziehau } 1777841ab66cSSepherosa Ziehau 1778841ab66cSSepherosa Ziehau /* 177932176cfdSRui Paulo * Node table support. 1780841ab66cSSepherosa Ziehau */ 178132176cfdSRui Paulo 1782841ab66cSSepherosa Ziehau static void 178332176cfdSRui Paulo ieee80211_node_table_init(struct ieee80211com *ic, 178432176cfdSRui Paulo struct ieee80211_node_table *nt, 178532176cfdSRui Paulo const char *name, int inact, int keyixmax) 1786841ab66cSSepherosa Ziehau { 178732176cfdSRui Paulo nt->nt_ic = ic; 178832176cfdSRui Paulo TAILQ_INIT(&nt->nt_node); 178932176cfdSRui Paulo nt->nt_name = name; 179032176cfdSRui Paulo nt->nt_scangen = 1; 179132176cfdSRui Paulo nt->nt_inact_init = inact; 179232176cfdSRui Paulo nt->nt_keyixmax = keyixmax; 179332176cfdSRui Paulo if (nt->nt_keyixmax > 0) { 179432176cfdSRui Paulo nt->nt_keyixmap = (struct ieee80211_node **) kmalloc( 179532176cfdSRui Paulo keyixmax * sizeof(struct ieee80211_node *), 1796fcaa651dSRui Paulo M_80211_NODE, M_INTWAIT | M_ZERO); 179732176cfdSRui Paulo if (nt->nt_keyixmap == NULL) 179832176cfdSRui Paulo if_printf(ic->ic_ifp, 179932176cfdSRui Paulo "Cannot allocate key index map with %u entries\n", 180032176cfdSRui Paulo keyixmax); 180132176cfdSRui Paulo } else 180232176cfdSRui Paulo nt->nt_keyixmap = NULL; 1803841ab66cSSepherosa Ziehau } 180432176cfdSRui Paulo 180532176cfdSRui Paulo static void 180632176cfdSRui Paulo ieee80211_node_table_reset(struct ieee80211_node_table *nt, 180732176cfdSRui Paulo struct ieee80211vap *match) 180832176cfdSRui Paulo { 180932176cfdSRui Paulo struct ieee80211_node *ni, *next; 181032176cfdSRui Paulo 181132176cfdSRui Paulo TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) { 181232176cfdSRui Paulo if (match != NULL && ni->ni_vap != match) 181332176cfdSRui Paulo continue; 181432176cfdSRui Paulo /* XXX can this happen? if so need's work */ 181532176cfdSRui Paulo if (ni->ni_associd != 0) { 181632176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 181732176cfdSRui Paulo 181832176cfdSRui Paulo if (vap->iv_auth->ia_node_leave != NULL) 181932176cfdSRui Paulo vap->iv_auth->ia_node_leave(ni); 182032176cfdSRui Paulo if (vap->iv_aid_bitmap != NULL) 182132176cfdSRui Paulo IEEE80211_AID_CLR(vap, ni->ni_associd); 182232176cfdSRui Paulo } 182332176cfdSRui Paulo ni->ni_wdsvap = NULL; /* clear reference */ 1824841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1825841ab66cSSepherosa Ziehau } 182632176cfdSRui Paulo if (match != NULL && match->iv_opmode == IEEE80211_M_WDS) { 182732176cfdSRui Paulo /* 182832176cfdSRui Paulo * Make a separate pass to clear references to this vap 182932176cfdSRui Paulo * held by DWDS entries. They will not be matched above 183032176cfdSRui Paulo * because ni_vap will point to the ap vap but we still 183132176cfdSRui Paulo * need to clear ni_wdsvap when the WDS vap is destroyed 183232176cfdSRui Paulo * and/or reset. 183332176cfdSRui Paulo */ 183432176cfdSRui Paulo TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) 183532176cfdSRui Paulo if (ni->ni_wdsvap == match) 183632176cfdSRui Paulo ni->ni_wdsvap = NULL; 183732176cfdSRui Paulo } 1838841ab66cSSepherosa Ziehau } 1839841ab66cSSepherosa Ziehau 184032176cfdSRui Paulo static void 184132176cfdSRui Paulo ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 184232176cfdSRui Paulo { 184332176cfdSRui Paulo ieee80211_node_table_reset(nt, NULL); 184432176cfdSRui Paulo if (nt->nt_keyixmap != NULL) { 184532176cfdSRui Paulo #ifdef DIAGNOSTIC 184632176cfdSRui Paulo /* XXX verify all entries are NULL */ 184732176cfdSRui Paulo int i; 184832176cfdSRui Paulo for (i = 0; i < nt->nt_keyixmax; i++) 184932176cfdSRui Paulo if (nt->nt_keyixmap[i] != NULL) 18502fafbbf5SRui Paulo kprintf("%s: %s[%u] still active\n", __func__, 185132176cfdSRui Paulo nt->nt_name, i); 185232176cfdSRui Paulo #endif 185332176cfdSRui Paulo kfree(nt->nt_keyixmap, M_80211_NODE); 185432176cfdSRui Paulo nt->nt_keyixmap = NULL; 185532176cfdSRui Paulo } 1856841ab66cSSepherosa Ziehau } 1857841ab66cSSepherosa Ziehau 1858841ab66cSSepherosa Ziehau /* 1859841ab66cSSepherosa Ziehau * Timeout inactive stations and do related housekeeping. 1860841ab66cSSepherosa Ziehau * Note that we cannot hold the node lock while sending a 1861841ab66cSSepherosa Ziehau * frame as this would lead to a LOR. Instead we use a 1862841ab66cSSepherosa Ziehau * generation number to mark nodes that we've scanned and 1863841ab66cSSepherosa Ziehau * drop the lock and restart a scan if we have to time out 1864841ab66cSSepherosa Ziehau * a node. Since we are single-threaded by virtue of 1865f186073cSJoerg Sonnenberger * controlling the inactivity timer we can be sure this will 1866f186073cSJoerg Sonnenberger * process each node only once. 1867f186073cSJoerg Sonnenberger */ 1868841ab66cSSepherosa Ziehau static void 186932176cfdSRui Paulo ieee80211_timeout_stations(struct ieee80211com *ic) 1870f186073cSJoerg Sonnenberger { 187132176cfdSRui Paulo struct ieee80211_node_table *nt = &ic->ic_sta; 187232176cfdSRui Paulo struct ieee80211vap *vap; 187332176cfdSRui Paulo struct ieee80211_node *ni; 187432176cfdSRui Paulo int gen = 0; 1875f186073cSJoerg Sonnenberger 187632176cfdSRui Paulo gen = ++nt->nt_scangen; 187732176cfdSRui Paulo restart: 187832176cfdSRui Paulo TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 187932176cfdSRui Paulo if (ni->ni_scangen == gen) /* previously handled */ 188032176cfdSRui Paulo continue; 188132176cfdSRui Paulo ni->ni_scangen = gen; 1882f186073cSJoerg Sonnenberger /* 1883841ab66cSSepherosa Ziehau * Ignore entries for which have yet to receive an 1884841ab66cSSepherosa Ziehau * authentication frame. These are transient and 1885841ab66cSSepherosa Ziehau * will be reclaimed when the last reference to them 1886841ab66cSSepherosa Ziehau * goes away (when frame xmits complete). 1887f186073cSJoerg Sonnenberger */ 188832176cfdSRui Paulo vap = ni->ni_vap; 188932176cfdSRui Paulo /* 189032176cfdSRui Paulo * Only process stations when in RUN state. This 189132176cfdSRui Paulo * insures, for example, that we don't timeout an 189232176cfdSRui Paulo * inactive station during CAC. Note that CSA state 189332176cfdSRui Paulo * is actually handled in ieee80211_node_timeout as 189432176cfdSRui Paulo * it applies to more than timeout processing. 189532176cfdSRui Paulo */ 189632176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_RUN) 189732176cfdSRui Paulo continue; 189832176cfdSRui Paulo /* XXX can vap be NULL? */ 189932176cfdSRui Paulo if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 190032176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_STA) && 1901841ab66cSSepherosa Ziehau (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1902841ab66cSSepherosa Ziehau continue; 1903841ab66cSSepherosa Ziehau /* 1904841ab66cSSepherosa Ziehau * Free fragment if not needed anymore 1905841ab66cSSepherosa Ziehau * (last fragment older than 1s). 190632176cfdSRui Paulo * XXX doesn't belong here, move to node_age 1907841ab66cSSepherosa Ziehau */ 1908841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && 1909841ab66cSSepherosa Ziehau ticks > ni->ni_rxfragstamp + hz) { 1910841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1911841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1912841ab66cSSepherosa Ziehau } 191332176cfdSRui Paulo if (ni->ni_inact > 0) { 191432176cfdSRui Paulo ni->ni_inact--; 191532176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 191632176cfdSRui Paulo "%s: inact %u inact_reload %u nrates %u", 191732176cfdSRui Paulo __func__, ni->ni_inact, ni->ni_inact_reload, 191832176cfdSRui Paulo ni->ni_rates.rs_nrates); 191932176cfdSRui Paulo } 1920841ab66cSSepherosa Ziehau /* 1921841ab66cSSepherosa Ziehau * Special case ourself; we may be idle for extended periods 1922841ab66cSSepherosa Ziehau * of time and regardless reclaiming our state is wrong. 192332176cfdSRui Paulo * XXX run ic_node_age 1924841ab66cSSepherosa Ziehau */ 192532176cfdSRui Paulo if (ni == vap->iv_bss) 1926841ab66cSSepherosa Ziehau continue; 192732176cfdSRui Paulo if (ni->ni_associd != 0 || 192832176cfdSRui Paulo (vap->iv_opmode == IEEE80211_M_IBSS || 192932176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_AHDEMO)) { 1930841ab66cSSepherosa Ziehau /* 193132176cfdSRui Paulo * Age/drain resources held by the station. 1932841ab66cSSepherosa Ziehau */ 193332176cfdSRui Paulo ic->ic_node_age(ni); 1934841ab66cSSepherosa Ziehau /* 1935841ab66cSSepherosa Ziehau * Probe the station before time it out. We 1936841ab66cSSepherosa Ziehau * send a null data frame which may not be 1937841ab66cSSepherosa Ziehau * universally supported by drivers (need it 1938841ab66cSSepherosa Ziehau * for ps-poll support so it should be...). 193932176cfdSRui Paulo * 194032176cfdSRui Paulo * XXX don't probe the station unless we've 194132176cfdSRui Paulo * received a frame from them (and have 194232176cfdSRui Paulo * some idea of the rates they are capable 194332176cfdSRui Paulo * of); this will get fixed more properly 194432176cfdSRui Paulo * soon with better handling of the rate set. 1945841ab66cSSepherosa Ziehau */ 194632176cfdSRui Paulo if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 194732176cfdSRui Paulo (0 < ni->ni_inact && 194832176cfdSRui Paulo ni->ni_inact <= vap->iv_inact_probe) && 194932176cfdSRui Paulo ni->ni_rates.rs_nrates != 0) { 195032176cfdSRui Paulo IEEE80211_NOTE(vap, 1951841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 1952841ab66cSSepherosa Ziehau ni, "%s", 1953841ab66cSSepherosa Ziehau "probe station due to inactivity"); 1954841ab66cSSepherosa Ziehau /* 1955841ab66cSSepherosa Ziehau * Grab a reference before unlocking the table 1956841ab66cSSepherosa Ziehau * so the node cannot be reclaimed before we 1957841ab66cSSepherosa Ziehau * send the frame. ieee80211_send_nulldata 1958841ab66cSSepherosa Ziehau * understands we've done this and reclaims the 1959841ab66cSSepherosa Ziehau * ref for us as needed. 1960841ab66cSSepherosa Ziehau */ 1961841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1962841ab66cSSepherosa Ziehau ieee80211_send_nulldata(ni); 1963841ab66cSSepherosa Ziehau /* XXX stat? */ 196432176cfdSRui Paulo goto restart; 1965841ab66cSSepherosa Ziehau } 1966841ab66cSSepherosa Ziehau } 196732176cfdSRui Paulo if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 196832176cfdSRui Paulo ni->ni_inact <= 0) { 196932176cfdSRui Paulo IEEE80211_NOTE(vap, 1970841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 1971841ab66cSSepherosa Ziehau "station timed out due to inactivity " 1972841ab66cSSepherosa Ziehau "(refcnt %u)", ieee80211_node_refcnt(ni)); 1973841ab66cSSepherosa Ziehau /* 1974841ab66cSSepherosa Ziehau * Send a deauthenticate frame and drop the station. 1975841ab66cSSepherosa Ziehau * This is somewhat complicated due to reference counts 1976841ab66cSSepherosa Ziehau * and locking. At this point a station will typically 1977841ab66cSSepherosa Ziehau * have a reference count of 1. ieee80211_node_leave 1978841ab66cSSepherosa Ziehau * will do a "free" of the node which will drop the 1979841ab66cSSepherosa Ziehau * reference count. But in the meantime a reference 1980841ab66cSSepherosa Ziehau * wil be held by the deauth frame. The actual reclaim 1981841ab66cSSepherosa Ziehau * of the node will happen either after the tx is 1982841ab66cSSepherosa Ziehau * completed or by ieee80211_node_leave. 198332176cfdSRui Paulo * 198432176cfdSRui Paulo * Separately we must drop the node lock before sending 198532176cfdSRui Paulo * in case the driver takes a lock, as this can result 198632176cfdSRui Paulo * in a LOR between the node lock and the driver lock. 1987841ab66cSSepherosa Ziehau */ 198832176cfdSRui Paulo ieee80211_ref_node(ni); 1989841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 199032176cfdSRui Paulo IEEE80211_SEND_MGMT(ni, 1991f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 1992f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_EXPIRE); 1993841ab66cSSepherosa Ziehau } 199432176cfdSRui Paulo ieee80211_node_leave(ni); 199532176cfdSRui Paulo ieee80211_free_node(ni); 199632176cfdSRui Paulo vap->iv_stats.is_node_timeout++; 199732176cfdSRui Paulo goto restart; 1998f186073cSJoerg Sonnenberger } 1999f186073cSJoerg Sonnenberger } 200032176cfdSRui Paulo } 2001841ab66cSSepherosa Ziehau 200232176cfdSRui Paulo /* 200332176cfdSRui Paulo * Aggressively reclaim resources. This should be used 200432176cfdSRui Paulo * only in a critical situation to reclaim mbuf resources. 200532176cfdSRui Paulo */ 200632176cfdSRui Paulo void 200732176cfdSRui Paulo ieee80211_drain(struct ieee80211com *ic) 200832176cfdSRui Paulo { 200932176cfdSRui Paulo struct ieee80211_node_table *nt = &ic->ic_sta; 201032176cfdSRui Paulo struct ieee80211vap *vap; 201132176cfdSRui Paulo struct ieee80211_node *ni; 201232176cfdSRui Paulo 201332176cfdSRui Paulo TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 201432176cfdSRui Paulo /* 201532176cfdSRui Paulo * Ignore entries for which have yet to receive an 201632176cfdSRui Paulo * authentication frame. These are transient and 201732176cfdSRui Paulo * will be reclaimed when the last reference to them 201832176cfdSRui Paulo * goes away (when frame xmits complete). 201932176cfdSRui Paulo */ 202032176cfdSRui Paulo vap = ni->ni_vap; 202132176cfdSRui Paulo /* 202232176cfdSRui Paulo * Only process stations when in RUN state. This 202332176cfdSRui Paulo * insures, for example, that we don't timeout an 202432176cfdSRui Paulo * inactive station during CAC. Note that CSA state 202532176cfdSRui Paulo * is actually handled in ieee80211_node_timeout as 202632176cfdSRui Paulo * it applies to more than timeout processing. 202732176cfdSRui Paulo */ 202832176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_RUN) 202932176cfdSRui Paulo continue; 203032176cfdSRui Paulo /* XXX can vap be NULL? */ 203132176cfdSRui Paulo if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 203232176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_STA) && 203332176cfdSRui Paulo (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 203432176cfdSRui Paulo continue; 203532176cfdSRui Paulo /* 203632176cfdSRui Paulo * Free fragments. 203732176cfdSRui Paulo * XXX doesn't belong here, move to node_drain 203832176cfdSRui Paulo */ 203932176cfdSRui Paulo if (ni->ni_rxfrag[0] != NULL) { 204032176cfdSRui Paulo m_freem(ni->ni_rxfrag[0]); 204132176cfdSRui Paulo ni->ni_rxfrag[0] = NULL; 204232176cfdSRui Paulo } 204332176cfdSRui Paulo /* 204432176cfdSRui Paulo * Drain resources held by the station. 204532176cfdSRui Paulo */ 204632176cfdSRui Paulo ic->ic_node_drain(ni); 204732176cfdSRui Paulo } 204832176cfdSRui Paulo } 204932176cfdSRui Paulo 205032176cfdSRui Paulo /* 205132176cfdSRui Paulo * Per-ieee80211com inactivity timer callback. 205232176cfdSRui Paulo */ 205347156d48SMatthew Dillon static void 205447156d48SMatthew Dillon ieee80211_node_timeout_callout(void *arg) 205532176cfdSRui Paulo { 205632176cfdSRui Paulo struct ieee80211com *ic = arg; 205732176cfdSRui Paulo 205832176cfdSRui Paulo /* 205932176cfdSRui Paulo * Defer timeout processing if a channel switch is pending. 206032176cfdSRui Paulo * We typically need to be mute so not doing things that 206132176cfdSRui Paulo * might generate frames is good to handle in one place. 206232176cfdSRui Paulo * Supressing the station timeout processing may extend the 206332176cfdSRui Paulo * lifetime of inactive stations (by not decrementing their 206432176cfdSRui Paulo * idle counters) but this should be ok unless the CSA is 206532176cfdSRui Paulo * active for an unusually long time. 206632176cfdSRui Paulo */ 206747156d48SMatthew Dillon wlan_serialize_enter(); 206832176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) { 206932176cfdSRui Paulo ieee80211_scan_timeout(ic); 207032176cfdSRui Paulo ieee80211_timeout_stations(ic); 207132176cfdSRui Paulo ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT); 207232176cfdSRui Paulo 207332176cfdSRui Paulo ieee80211_erp_timeout(ic); 207432176cfdSRui Paulo ieee80211_ht_timeout(ic); 207532176cfdSRui Paulo } 207632176cfdSRui Paulo callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 207747156d48SMatthew Dillon ieee80211_node_timeout_callout, ic); 207847156d48SMatthew Dillon wlan_serialize_exit(); 2079f186073cSJoerg Sonnenberger } 2080f186073cSJoerg Sonnenberger 2081f186073cSJoerg Sonnenberger void 208232176cfdSRui Paulo ieee80211_iterate_nodes(struct ieee80211_node_table *nt, 208332176cfdSRui Paulo ieee80211_iter_func *f, void *arg) 2084f186073cSJoerg Sonnenberger { 208532176cfdSRui Paulo struct ieee80211_node *ni; 208632176cfdSRui Paulo u_int gen; 2087f186073cSJoerg Sonnenberger 208832176cfdSRui Paulo gen = ++nt->nt_scangen; 208932176cfdSRui Paulo restart: 209032176cfdSRui Paulo TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 209132176cfdSRui Paulo if (ni->ni_scangen != gen) { 209232176cfdSRui Paulo ni->ni_scangen = gen; 209332176cfdSRui Paulo (void) ieee80211_ref_node(ni); 209432176cfdSRui Paulo (*f)(arg, ni); 209532176cfdSRui Paulo ieee80211_free_node(ni); 209632176cfdSRui Paulo goto restart; 209732176cfdSRui Paulo } 209832176cfdSRui Paulo } 2099841ab66cSSepherosa Ziehau } 2100841ab66cSSepherosa Ziehau 2101841ab66cSSepherosa Ziehau void 2102841ab66cSSepherosa Ziehau ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 2103841ab66cSSepherosa Ziehau { 210432176cfdSRui Paulo kprintf("0x%p: mac %6D refcnt %d\n", ni, ni->ni_macaddr, ":", 210532176cfdSRui Paulo ieee80211_node_refcnt(ni)); 210632176cfdSRui Paulo kprintf("\tscangen %u authmode %u flags 0x%x\n", 210732176cfdSRui Paulo ni->ni_scangen, ni->ni_authmode, ni->ni_flags); 2108a6ec04bcSSascha Wildner kprintf("\tassocid 0x%x txpower %u vlan %u\n", 2109841ab66cSSepherosa Ziehau ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 2110a6ec04bcSSascha Wildner kprintf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 211132176cfdSRui Paulo ni->ni_txseqs[IEEE80211_NONQOS_TID], 211232176cfdSRui Paulo ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT, 211332176cfdSRui Paulo ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK, 2114841ab66cSSepherosa Ziehau ni->ni_rxfragstamp); 211532176cfdSRui Paulo kprintf("\trssi %d noise %d intval %u capinfo 0x%x\n", 211632176cfdSRui Paulo node_getrssi(ni), ni->ni_noise, 211732176cfdSRui Paulo ni->ni_intval, ni->ni_capinfo); 2118a6ec04bcSSascha Wildner kprintf("\tbssid %6D essid \"%.*s\" channel %u:0x%x\n", 2119841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 2120841ab66cSSepherosa Ziehau ni->ni_esslen, ni->ni_essid, 2121841ab66cSSepherosa Ziehau ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 212232176cfdSRui Paulo kprintf("\tinact %u inact_reload %u txrate %u\n", 212332176cfdSRui Paulo ni->ni_inact, ni->ni_inact_reload, ni->ni_txrate); 212432176cfdSRui Paulo kprintf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n", 212532176cfdSRui Paulo ni->ni_htcap, ni->ni_htparam, 212632176cfdSRui Paulo ni->ni_htctlchan, ni->ni_ht2ndchan); 212732176cfdSRui Paulo kprintf("\thtopmode %x htstbc %x chw %u\n", 212832176cfdSRui Paulo ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw); 2129841ab66cSSepherosa Ziehau } 2130841ab66cSSepherosa Ziehau 2131841ab66cSSepherosa Ziehau void 2132841ab66cSSepherosa Ziehau ieee80211_dump_nodes(struct ieee80211_node_table *nt) 2133841ab66cSSepherosa Ziehau { 2134841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(nt, 2135841ab66cSSepherosa Ziehau (ieee80211_iter_func *) ieee80211_dump_node, nt); 2136841ab66cSSepherosa Ziehau } 2137841ab66cSSepherosa Ziehau 213832176cfdSRui Paulo static void 213932176cfdSRui Paulo ieee80211_notify_erp_locked(struct ieee80211com *ic) 214032176cfdSRui Paulo { 214132176cfdSRui Paulo struct ieee80211vap *vap; 214232176cfdSRui Paulo 214332176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 214432176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP) 214532176cfdSRui Paulo ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP); 214632176cfdSRui Paulo } 214732176cfdSRui Paulo 214832176cfdSRui Paulo void 214932176cfdSRui Paulo ieee80211_notify_erp(struct ieee80211com *ic) 215032176cfdSRui Paulo { 215132176cfdSRui Paulo ieee80211_notify_erp_locked(ic); 215232176cfdSRui Paulo } 215332176cfdSRui Paulo 2154841ab66cSSepherosa Ziehau /* 2155841ab66cSSepherosa Ziehau * Handle a station joining an 11g network. 2156841ab66cSSepherosa Ziehau */ 2157841ab66cSSepherosa Ziehau static void 215832176cfdSRui Paulo ieee80211_node_join_11g(struct ieee80211_node *ni) 2159841ab66cSSepherosa Ziehau { 216032176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 216132176cfdSRui Paulo 2162841ab66cSSepherosa Ziehau /* 2163841ab66cSSepherosa Ziehau * Station isn't capable of short slot time. Bump 2164841ab66cSSepherosa Ziehau * the count of long slot time stations and disable 2165841ab66cSSepherosa Ziehau * use of short slot time. Note that the actual switch 2166841ab66cSSepherosa Ziehau * over to long slot time use may not occur until the 2167841ab66cSSepherosa Ziehau * next beacon transmission (per sec. 7.3.1.4 of 11g). 2168841ab66cSSepherosa Ziehau */ 2169841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2170841ab66cSSepherosa Ziehau ic->ic_longslotsta++; 217132176cfdSRui Paulo IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 217232176cfdSRui Paulo "station needs long slot time, count %d", 217332176cfdSRui Paulo ic->ic_longslotsta); 2174841ab66cSSepherosa Ziehau /* XXX vap's w/ conflicting needs won't work */ 217532176cfdSRui Paulo if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) { 217632176cfdSRui Paulo /* 217732176cfdSRui Paulo * Don't force slot time when switched to turbo 217832176cfdSRui Paulo * mode as non-ERP stations won't be present; this 217932176cfdSRui Paulo * need only be done when on the normal G channel. 218032176cfdSRui Paulo */ 2181841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 0); 2182841ab66cSSepherosa Ziehau } 218332176cfdSRui Paulo } 2184841ab66cSSepherosa Ziehau /* 2185841ab66cSSepherosa Ziehau * If the new station is not an ERP station 2186841ab66cSSepherosa Ziehau * then bump the counter and enable protection 2187841ab66cSSepherosa Ziehau * if configured. 2188841ab66cSSepherosa Ziehau */ 218932176cfdSRui Paulo if (!ieee80211_iserp_rateset(&ni->ni_rates)) { 2190841ab66cSSepherosa Ziehau ic->ic_nonerpsta++; 219132176cfdSRui Paulo IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 219232176cfdSRui Paulo "station is !ERP, %d non-ERP stations associated", 219332176cfdSRui Paulo ic->ic_nonerpsta); 2194841ab66cSSepherosa Ziehau /* 2195841ab66cSSepherosa Ziehau * If station does not support short preamble 2196841ab66cSSepherosa Ziehau * then we must enable use of Barker preamble. 2197841ab66cSSepherosa Ziehau */ 2198841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 219932176cfdSRui Paulo IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 220032176cfdSRui Paulo "%s", "station needs long preamble"); 220132176cfdSRui Paulo ic->ic_flags |= IEEE80211_F_USEBARKER; 220232176cfdSRui Paulo ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 2203841ab66cSSepherosa Ziehau } 220432176cfdSRui Paulo /* 220532176cfdSRui Paulo * If protection is configured and this is the first 220632176cfdSRui Paulo * indication we should use protection, enable it. 220732176cfdSRui Paulo */ 220832176cfdSRui Paulo if (ic->ic_protmode != IEEE80211_PROT_NONE && 220932176cfdSRui Paulo ic->ic_nonerpsta == 1 && 221032176cfdSRui Paulo (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 221132176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 221232176cfdSRui Paulo "%s: enable use of protection\n", __func__); 221332176cfdSRui Paulo ic->ic_flags |= IEEE80211_F_USEPROT; 221432176cfdSRui Paulo ieee80211_notify_erp_locked(ic); 221532176cfdSRui Paulo } 2216841ab66cSSepherosa Ziehau } else 2217841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_ERP; 2218841ab66cSSepherosa Ziehau } 2219841ab66cSSepherosa Ziehau 2220841ab66cSSepherosa Ziehau void 222132176cfdSRui Paulo ieee80211_node_join(struct ieee80211_node *ni, int resp) 2222841ab66cSSepherosa Ziehau { 222332176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 222432176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 2225841ab66cSSepherosa Ziehau int newassoc; 2226841ab66cSSepherosa Ziehau 2227841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) { 2228841ab66cSSepherosa Ziehau uint16_t aid; 2229841ab66cSSepherosa Ziehau 223032176cfdSRui Paulo KASSERT(vap->iv_aid_bitmap != NULL, ("no aid bitmap")); 2231841ab66cSSepherosa Ziehau /* 2232841ab66cSSepherosa Ziehau * It would be good to search the bitmap 2233841ab66cSSepherosa Ziehau * more efficiently, but this will do for now. 2234841ab66cSSepherosa Ziehau */ 223532176cfdSRui Paulo for (aid = 1; aid < vap->iv_max_aid; aid++) { 223632176cfdSRui Paulo if (!IEEE80211_AID_ISSET(vap, aid)) 2237841ab66cSSepherosa Ziehau break; 2238841ab66cSSepherosa Ziehau } 223932176cfdSRui Paulo if (aid >= vap->iv_max_aid) { 224032176cfdSRui Paulo IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_TOOMANY); 224132176cfdSRui Paulo ieee80211_node_leave(ni); 2242841ab66cSSepherosa Ziehau return; 2243841ab66cSSepherosa Ziehau } 2244841ab66cSSepherosa Ziehau ni->ni_associd = aid | 0xc000; 224532176cfdSRui Paulo ni->ni_jointime = time_second; 224632176cfdSRui Paulo IEEE80211_AID_SET(vap, ni->ni_associd); 224732176cfdSRui Paulo vap->iv_sta_assoc++; 2248841ab66cSSepherosa Ziehau ic->ic_sta_assoc++; 224932176cfdSRui Paulo 225032176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 225132176cfdSRui Paulo ieee80211_ht_node_join(ni); 225232176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 225332176cfdSRui Paulo IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 225432176cfdSRui Paulo ieee80211_node_join_11g(ni); 225532176cfdSRui Paulo 2256841ab66cSSepherosa Ziehau newassoc = 1; 2257841ab66cSSepherosa Ziehau } else 2258841ab66cSSepherosa Ziehau newassoc = 0; 2259841ab66cSSepherosa Ziehau 226032176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 226132176cfdSRui Paulo "station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s", 2262841ab66cSSepherosa Ziehau IEEE80211_NODE_AID(ni), 2263841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2264841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2265841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 226632176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "", 226732176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_HT ? 226832176cfdSRui Paulo (ni->ni_chw == 40 ? ", HT40" : ", HT20") : "", 226932176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "", 227032176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" : 227132176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "", 227232176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "", 227332176cfdSRui Paulo IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ? 227432176cfdSRui Paulo ", fast-frames" : "", 227532176cfdSRui Paulo IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ? 227632176cfdSRui Paulo ", turbo" : "" 2277841ab66cSSepherosa Ziehau ); 2278841ab66cSSepherosa Ziehau 227932176cfdSRui Paulo ieee80211_node_setuptxparms(ni); 2280841ab66cSSepherosa Ziehau /* give driver a chance to setup state like ni_txrate */ 2281841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 2282841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, newassoc); 228332176cfdSRui Paulo IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_SUCCESS); 2284841ab66cSSepherosa Ziehau /* tell the authenticator about new station */ 228532176cfdSRui Paulo if (vap->iv_auth->ia_node_join != NULL) 228632176cfdSRui Paulo vap->iv_auth->ia_node_join(ni); 228732176cfdSRui Paulo ieee80211_notify_node_join(ni, 228832176cfdSRui Paulo resp == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 228932176cfdSRui Paulo } 229032176cfdSRui Paulo 229132176cfdSRui Paulo static void 229232176cfdSRui Paulo disable_protection(struct ieee80211com *ic) 229332176cfdSRui Paulo { 229432176cfdSRui Paulo KASSERT(ic->ic_nonerpsta == 0 && 229532176cfdSRui Paulo (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0, 229632176cfdSRui Paulo ("%d non ERP stations, flags 0x%x", ic->ic_nonerpsta, 229732176cfdSRui Paulo ic->ic_flags_ext)); 229832176cfdSRui Paulo 229932176cfdSRui Paulo ic->ic_flags &= ~IEEE80211_F_USEPROT; 230032176cfdSRui Paulo /* XXX verify mode? */ 230132176cfdSRui Paulo if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 230232176cfdSRui Paulo ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 230332176cfdSRui Paulo ic->ic_flags &= ~IEEE80211_F_USEBARKER; 230432176cfdSRui Paulo } 230532176cfdSRui Paulo ieee80211_notify_erp_locked(ic); 2306841ab66cSSepherosa Ziehau } 2307841ab66cSSepherosa Ziehau 2308841ab66cSSepherosa Ziehau /* 2309841ab66cSSepherosa Ziehau * Handle a station leaving an 11g network. 2310841ab66cSSepherosa Ziehau */ 2311841ab66cSSepherosa Ziehau static void 231232176cfdSRui Paulo ieee80211_node_leave_11g(struct ieee80211_node *ni) 2313841ab66cSSepherosa Ziehau { 231432176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 2315841ab66cSSepherosa Ziehau 231632176cfdSRui Paulo KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan), 231732176cfdSRui Paulo ("not in 11g, bss %u:0x%x", ic->ic_bsschan->ic_freq, 231832176cfdSRui Paulo ic->ic_bsschan->ic_flags)); 2319841ab66cSSepherosa Ziehau 2320841ab66cSSepherosa Ziehau /* 2321841ab66cSSepherosa Ziehau * If a long slot station do the slot time bookkeeping. 2322841ab66cSSepherosa Ziehau */ 2323841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2324841ab66cSSepherosa Ziehau KASSERT(ic->ic_longslotsta > 0, 2325841ab66cSSepherosa Ziehau ("bogus long slot station count %d", ic->ic_longslotsta)); 2326841ab66cSSepherosa Ziehau ic->ic_longslotsta--; 232732176cfdSRui Paulo IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 232832176cfdSRui Paulo "long slot time station leaves, count now %d", 232932176cfdSRui Paulo ic->ic_longslotsta); 2330841ab66cSSepherosa Ziehau if (ic->ic_longslotsta == 0) { 2331841ab66cSSepherosa Ziehau /* 2332841ab66cSSepherosa Ziehau * Re-enable use of short slot time if supported 2333841ab66cSSepherosa Ziehau * and not operating in IBSS mode (per spec). 2334841ab66cSSepherosa Ziehau */ 2335841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2336841ab66cSSepherosa Ziehau ic->ic_opmode != IEEE80211_M_IBSS) { 233732176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, 233832176cfdSRui Paulo IEEE80211_MSG_ASSOC, 2339841ab66cSSepherosa Ziehau "%s: re-enable use of short slot time\n", 2340841ab66cSSepherosa Ziehau __func__); 2341841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 1); 2342841ab66cSSepherosa Ziehau } 2343841ab66cSSepherosa Ziehau } 2344841ab66cSSepherosa Ziehau } 2345841ab66cSSepherosa Ziehau /* 2346841ab66cSSepherosa Ziehau * If a non-ERP station do the protection-related bookkeeping. 2347841ab66cSSepherosa Ziehau */ 2348841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2349841ab66cSSepherosa Ziehau KASSERT(ic->ic_nonerpsta > 0, 2350841ab66cSSepherosa Ziehau ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2351841ab66cSSepherosa Ziehau ic->ic_nonerpsta--; 235232176cfdSRui Paulo IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 235332176cfdSRui Paulo "non-ERP station leaves, count now %d%s", ic->ic_nonerpsta, 235432176cfdSRui Paulo (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) ? 235532176cfdSRui Paulo " (non-ERP sta present)" : ""); 235632176cfdSRui Paulo if (ic->ic_nonerpsta == 0 && 235732176cfdSRui Paulo (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 235832176cfdSRui Paulo IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2359841ab66cSSepherosa Ziehau "%s: disable use of protection\n", __func__); 236032176cfdSRui Paulo disable_protection(ic); 2361841ab66cSSepherosa Ziehau } 2362841ab66cSSepherosa Ziehau } 2363841ab66cSSepherosa Ziehau } 236432176cfdSRui Paulo 236532176cfdSRui Paulo /* 236632176cfdSRui Paulo * Time out presence of an overlapping bss with non-ERP 236732176cfdSRui Paulo * stations. When operating in hostap mode we listen for 236832176cfdSRui Paulo * beacons from other stations and if we identify a non-ERP 236932176cfdSRui Paulo * station is present we enable protection. To identify 237032176cfdSRui Paulo * when all non-ERP stations are gone we time out this 237132176cfdSRui Paulo * condition. 237232176cfdSRui Paulo */ 237332176cfdSRui Paulo static void 237432176cfdSRui Paulo ieee80211_erp_timeout(struct ieee80211com *ic) 237532176cfdSRui Paulo { 237632176cfdSRui Paulo if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) && 237732176cfdSRui Paulo time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) { 237832176cfdSRui Paulo #if 0 237932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 238032176cfdSRui Paulo "%s", "age out non-ERP sta present on channel"); 238132176cfdSRui Paulo #endif 238232176cfdSRui Paulo ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR; 238332176cfdSRui Paulo if (ic->ic_nonerpsta == 0) 238432176cfdSRui Paulo disable_protection(ic); 238532176cfdSRui Paulo } 2386841ab66cSSepherosa Ziehau } 2387841ab66cSSepherosa Ziehau 2388841ab66cSSepherosa Ziehau /* 2389841ab66cSSepherosa Ziehau * Handle bookkeeping for station deauthentication/disassociation 2390841ab66cSSepherosa Ziehau * when operating as an ap. 2391841ab66cSSepherosa Ziehau */ 2392841ab66cSSepherosa Ziehau void 239332176cfdSRui Paulo ieee80211_node_leave(struct ieee80211_node *ni) 2394841ab66cSSepherosa Ziehau { 239532176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 239632176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 2397841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 2398841ab66cSSepherosa Ziehau 239932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 240032176cfdSRui Paulo "station with aid %d leaves", IEEE80211_NODE_AID(ni)); 2401841ab66cSSepherosa Ziehau 240232176cfdSRui Paulo KASSERT(vap->iv_opmode != IEEE80211_M_STA, 240332176cfdSRui Paulo ("unexpected operating mode %u", vap->iv_opmode)); 2404841ab66cSSepherosa Ziehau /* 2405841ab66cSSepherosa Ziehau * If node wasn't previously associated all 2406841ab66cSSepherosa Ziehau * we need to do is reclaim the reference. 2407841ab66cSSepherosa Ziehau */ 2408841ab66cSSepherosa Ziehau /* XXX ibss mode bypasses 11g and notification */ 2409841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) 2410841ab66cSSepherosa Ziehau goto done; 2411841ab66cSSepherosa Ziehau /* 2412841ab66cSSepherosa Ziehau * Tell the authenticator the station is leaving. 2413841ab66cSSepherosa Ziehau * Note that we must do this before yanking the 2414841ab66cSSepherosa Ziehau * association id as the authenticator uses the 2415841ab66cSSepherosa Ziehau * associd to locate it's state block. 2416841ab66cSSepherosa Ziehau */ 241732176cfdSRui Paulo if (vap->iv_auth->ia_node_leave != NULL) 241832176cfdSRui Paulo vap->iv_auth->ia_node_leave(ni); 241932176cfdSRui Paulo 242032176cfdSRui Paulo IEEE80211_AID_CLR(vap, ni->ni_associd); 2421841ab66cSSepherosa Ziehau ni->ni_associd = 0; 242232176cfdSRui Paulo vap->iv_sta_assoc--; 2423841ab66cSSepherosa Ziehau ic->ic_sta_assoc--; 2424841ab66cSSepherosa Ziehau 242532176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 242632176cfdSRui Paulo ieee80211_ht_node_leave(ni); 242732176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 242832176cfdSRui Paulo IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 242932176cfdSRui Paulo ieee80211_node_leave_11g(ni); 2430841ab66cSSepherosa Ziehau /* 2431841ab66cSSepherosa Ziehau * Cleanup station state. In particular clear various 2432841ab66cSSepherosa Ziehau * state that might otherwise be reused if the node 2433841ab66cSSepherosa Ziehau * is reused before the reference count goes to zero 2434841ab66cSSepherosa Ziehau * (and memory is reclaimed). 2435841ab66cSSepherosa Ziehau */ 243632176cfdSRui Paulo ieee80211_sta_leave(ni); 2437841ab66cSSepherosa Ziehau done: 2438841ab66cSSepherosa Ziehau /* 2439841ab66cSSepherosa Ziehau * Remove the node from any table it's recorded in and 2440841ab66cSSepherosa Ziehau * drop the caller's reference. Removal from the table 2441841ab66cSSepherosa Ziehau * is important to insure the node is not reprocessed 2442841ab66cSSepherosa Ziehau * for inactivity. 2443841ab66cSSepherosa Ziehau */ 244432176cfdSRui Paulo if (nt != NULL) { 2445841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 244632176cfdSRui Paulo } else 2447841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2448841ab66cSSepherosa Ziehau } 2449841ab66cSSepherosa Ziehau 245032176cfdSRui Paulo struct rssiinfo { 245132176cfdSRui Paulo struct ieee80211vap *vap; 245232176cfdSRui Paulo int rssi_samples; 245332176cfdSRui Paulo uint32_t rssi_total; 245432176cfdSRui Paulo }; 245532176cfdSRui Paulo 245632176cfdSRui Paulo static void 245732176cfdSRui Paulo get_hostap_rssi(void *arg, struct ieee80211_node *ni) 245832176cfdSRui Paulo { 245932176cfdSRui Paulo struct rssiinfo *info = arg; 246032176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 246132176cfdSRui Paulo int8_t rssi; 246232176cfdSRui Paulo 246332176cfdSRui Paulo if (info->vap != vap) 246432176cfdSRui Paulo return; 246532176cfdSRui Paulo /* only associated stations */ 246632176cfdSRui Paulo if (ni->ni_associd == 0) 246732176cfdSRui Paulo return; 246832176cfdSRui Paulo rssi = vap->iv_ic->ic_node_getrssi(ni); 246932176cfdSRui Paulo if (rssi != 0) { 247032176cfdSRui Paulo info->rssi_samples++; 247132176cfdSRui Paulo info->rssi_total += rssi; 247232176cfdSRui Paulo } 247332176cfdSRui Paulo } 247432176cfdSRui Paulo 247532176cfdSRui Paulo static void 247632176cfdSRui Paulo get_adhoc_rssi(void *arg, struct ieee80211_node *ni) 247732176cfdSRui Paulo { 247832176cfdSRui Paulo struct rssiinfo *info = arg; 247932176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 248032176cfdSRui Paulo int8_t rssi; 248132176cfdSRui Paulo 248232176cfdSRui Paulo if (info->vap != vap) 248332176cfdSRui Paulo return; 248432176cfdSRui Paulo /* only neighbors */ 248532176cfdSRui Paulo /* XXX check bssid */ 248632176cfdSRui Paulo if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 248732176cfdSRui Paulo return; 248832176cfdSRui Paulo rssi = vap->iv_ic->ic_node_getrssi(ni); 248932176cfdSRui Paulo if (rssi != 0) { 249032176cfdSRui Paulo info->rssi_samples++; 249132176cfdSRui Paulo info->rssi_total += rssi; 249232176cfdSRui Paulo } 249332176cfdSRui Paulo } 249432176cfdSRui Paulo 249532176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 249632176cfdSRui Paulo static void 249732176cfdSRui Paulo get_mesh_rssi(void *arg, struct ieee80211_node *ni) 249832176cfdSRui Paulo { 249932176cfdSRui Paulo struct rssiinfo *info = arg; 250032176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 250132176cfdSRui Paulo int8_t rssi; 250232176cfdSRui Paulo 250332176cfdSRui Paulo if (info->vap != vap) 250432176cfdSRui Paulo return; 250532176cfdSRui Paulo /* only neighbors that peered successfully */ 250632176cfdSRui Paulo if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 250732176cfdSRui Paulo return; 250832176cfdSRui Paulo rssi = vap->iv_ic->ic_node_getrssi(ni); 250932176cfdSRui Paulo if (rssi != 0) { 251032176cfdSRui Paulo info->rssi_samples++; 251132176cfdSRui Paulo info->rssi_total += rssi; 251232176cfdSRui Paulo } 251332176cfdSRui Paulo } 251432176cfdSRui Paulo #endif /* IEEE80211_SUPPORT_MESH */ 251532176cfdSRui Paulo 251632176cfdSRui Paulo int8_t 251732176cfdSRui Paulo ieee80211_getrssi(struct ieee80211vap *vap) 2518841ab66cSSepherosa Ziehau { 2519841ab66cSSepherosa Ziehau #define NZ(x) ((x) == 0 ? 1 : (x)) 252032176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 252132176cfdSRui Paulo struct rssiinfo info; 2522841ab66cSSepherosa Ziehau 252332176cfdSRui Paulo info.rssi_total = 0; 252432176cfdSRui Paulo info.rssi_samples = 0; 252532176cfdSRui Paulo info.vap = vap; 252632176cfdSRui Paulo switch (vap->iv_opmode) { 2527841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2528841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: /* average of all neighbors */ 252932176cfdSRui Paulo ieee80211_iterate_nodes(&ic->ic_sta, get_adhoc_rssi, &info); 2530841ab66cSSepherosa Ziehau break; 2531841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: /* average of all associated stations */ 253232176cfdSRui Paulo ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info); 2533841ab66cSSepherosa Ziehau break; 253432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 253532176cfdSRui Paulo case IEEE80211_M_MBSS: /* average of all mesh neighbors */ 253632176cfdSRui Paulo ieee80211_iterate_nodes(&ic->ic_sta, get_mesh_rssi, &info); 253732176cfdSRui Paulo break; 253832176cfdSRui Paulo #endif 2539841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* XXX */ 2540841ab66cSSepherosa Ziehau case IEEE80211_M_STA: /* use stats from associated ap */ 2541841ab66cSSepherosa Ziehau default: 254232176cfdSRui Paulo if (vap->iv_bss != NULL) 254332176cfdSRui Paulo info.rssi_total = ic->ic_node_getrssi(vap->iv_bss); 254432176cfdSRui Paulo info.rssi_samples = 1; 2545841ab66cSSepherosa Ziehau break; 2546841ab66cSSepherosa Ziehau } 254732176cfdSRui Paulo return info.rssi_total / NZ(info.rssi_samples); 2548841ab66cSSepherosa Ziehau #undef NZ 2549841ab66cSSepherosa Ziehau } 2550841ab66cSSepherosa Ziehau 2551841ab66cSSepherosa Ziehau void 255232176cfdSRui Paulo ieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise) 2553841ab66cSSepherosa Ziehau { 2554841ab66cSSepherosa Ziehau 255532176cfdSRui Paulo if (vap->iv_bss == NULL) /* NB: shouldn't happen */ 255632176cfdSRui Paulo return; 255732176cfdSRui Paulo vap->iv_ic->ic_node_getsignal(vap->iv_bss, rssi, noise); 255832176cfdSRui Paulo /* for non-station mode return avg'd rssi accounting */ 255932176cfdSRui Paulo if (vap->iv_opmode != IEEE80211_M_STA) 256032176cfdSRui Paulo *rssi = ieee80211_getrssi(vap); 2561f39a365aSSepherosa Ziehau } 2562