1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3186904Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 4116742Ssam * All rights reserved. 5116742Ssam * 6116742Ssam * Redistribution and use in source and binary forms, with or without 7116742Ssam * modification, are permitted provided that the following conditions 8116742Ssam * are met: 9116742Ssam * 1. Redistributions of source code must retain the above copyright 10116904Ssam * notice, this list of conditions and the following disclaimer. 11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright 12116904Ssam * notice, this list of conditions and the following disclaimer in the 13116904Ssam * documentation and/or other materials provided with the distribution. 14116742Ssam * 15116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116742Ssam */ 26116742Ssam 27116742Ssam#include <sys/cdefs.h> 28116742Ssam__FBSDID("$FreeBSD: stable/11/sys/net80211/ieee80211_node.c 342464 2018-12-25 13:54:10Z avos $"); 29116742Ssam 30178354Ssam#include "opt_wlan.h" 31178354Ssam 32116742Ssam#include <sys/param.h> 33337951Skevans#include <sys/systm.h> 34337951Skevans#include <sys/mbuf.h> 35116742Ssam#include <sys/malloc.h> 36116742Ssam#include <sys/kernel.h> 37138568Ssam 38116742Ssam#include <sys/socket.h> 39337951Skevans 40116742Ssam#include <net/if.h> 41257176Sglebius#include <net/if_var.h> 42116742Ssam#include <net/if_media.h> 43116742Ssam#include <net/ethernet.h> 44116742Ssam 45116742Ssam#include <net80211/ieee80211_var.h> 46178354Ssam#include <net80211/ieee80211_input.h> 47190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 48190391Ssam#include <net80211/ieee80211_superg.h> 49190391Ssam#endif 50186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 51186904Ssam#include <net80211/ieee80211_tdma.h> 52186904Ssam#endif 53178354Ssam#include <net80211/ieee80211_wds.h> 54195618Srpaulo#include <net80211/ieee80211_mesh.h> 55206358Srpaulo#include <net80211/ieee80211_ratectl.h> 56116742Ssam 57116742Ssam#include <net/bpf.h> 58116742Ssam 59147221Ssam/* 60195618Srpaulo * IEEE80211_NODE_HASHSIZE must be a power of 2. 61195618Srpaulo */ 62195618SrpauloCTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0); 63195618Srpaulo 64195618Srpaulo/* 65147221Ssam * Association id's are managed with a bit vector. 66147221Ssam */ 67178354Ssam#define IEEE80211_AID_SET(_vap, b) \ 68178354Ssam ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] |= \ 69178354Ssam (1 << (IEEE80211_AID(b) % 32))) 70178354Ssam#define IEEE80211_AID_CLR(_vap, b) \ 71178354Ssam ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] &= \ 72178354Ssam ~(1 << (IEEE80211_AID(b) % 32))) 73178354Ssam#define IEEE80211_AID_ISSET(_vap, b) \ 74178354Ssam ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32))) 75147221Ssam 76170530Ssamstatic int ieee80211_sta_join1(struct ieee80211_node *); 77170530Ssam 78179643Ssamstatic struct ieee80211_node *node_alloc(struct ieee80211vap *, 79179643Ssam const uint8_t [IEEE80211_ADDR_LEN]); 80138568Ssamstatic void node_cleanup(struct ieee80211_node *); 81138568Ssamstatic void node_free(struct ieee80211_node *); 82178354Ssamstatic void node_age(struct ieee80211_node *); 83170530Ssamstatic int8_t node_getrssi(const struct ieee80211_node *); 84170530Ssamstatic void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *); 85178354Ssamstatic void node_getmimoinfo(const struct ieee80211_node *, 86178354Ssam struct ieee80211_mimo_info *); 87116742Ssam 88138568Ssamstatic void _ieee80211_free_node(struct ieee80211_node *); 89120104Ssam 90282372Sadrianstatic void node_reclaim(struct ieee80211_node_table *nt, 91282372Sadrian struct ieee80211_node *ni); 92138568Ssamstatic void ieee80211_node_table_init(struct ieee80211com *ic, 93148863Ssam struct ieee80211_node_table *nt, const char *name, 94170530Ssam int inact, int keymaxix); 95178354Ssamstatic void ieee80211_node_table_reset(struct ieee80211_node_table *, 96178354Ssam struct ieee80211vap *); 97138568Ssamstatic void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 98172211Ssamstatic void ieee80211_erp_timeout(struct ieee80211com *); 99138568Ssam 100127876SsamMALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 101178354SsamMALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie"); 102120481Ssam 103116742Ssamvoid 104138568Ssamieee80211_node_attach(struct ieee80211com *ic) 105116742Ssam{ 106195379Ssam /* XXX really want maxlen enforced per-sta */ 107195379Ssam ieee80211_ageq_init(&ic->ic_stageq, ic->ic_max_keyix * 8, 108195379Ssam "802.11 staging q"); 109178354Ssam ieee80211_node_table_init(ic, &ic->ic_sta, "station", 110178354Ssam IEEE80211_INACT_INIT, ic->ic_max_keyix); 111283291Sjkim callout_init(&ic->ic_inact, 1); 112178354Ssam callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 113178354Ssam ieee80211_node_timeout, ic); 114116742Ssam 115138568Ssam ic->ic_node_alloc = node_alloc; 116138568Ssam ic->ic_node_free = node_free; 117138568Ssam ic->ic_node_cleanup = node_cleanup; 118178354Ssam ic->ic_node_age = node_age; 119178354Ssam ic->ic_node_drain = node_age; /* NB: same as age */ 120138568Ssam ic->ic_node_getrssi = node_getrssi; 121170530Ssam ic->ic_node_getsignal = node_getsignal; 122178354Ssam ic->ic_node_getmimoinfo = node_getmimoinfo; 123138568Ssam 124178354Ssam /* 125178354Ssam * Set flags to be propagated to all vap's; 126178354Ssam * these define default behaviour/configuration. 127178354Ssam */ 128178354Ssam ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */ 129178354Ssam} 130138568Ssam 131178354Ssamvoid 132178354Ssamieee80211_node_detach(struct ieee80211com *ic) 133178354Ssam{ 134170530Ssam 135178354Ssam callout_drain(&ic->ic_inact); 136178354Ssam ieee80211_node_table_cleanup(&ic->ic_sta); 137337951Skevans ieee80211_ageq_drain(&ic->ic_stageq); 138195379Ssam ieee80211_ageq_cleanup(&ic->ic_stageq); 139178354Ssam} 140172062Ssam 141178354Ssamvoid 142178354Ssamieee80211_node_vattach(struct ieee80211vap *vap) 143178354Ssam{ 144178354Ssam /* NB: driver can override */ 145178354Ssam vap->iv_max_aid = IEEE80211_AID_DEF; 146178354Ssam 147178354Ssam /* default station inactivity timer setings */ 148178354Ssam vap->iv_inact_init = IEEE80211_INACT_INIT; 149178354Ssam vap->iv_inact_auth = IEEE80211_INACT_AUTH; 150178354Ssam vap->iv_inact_run = IEEE80211_INACT_RUN; 151178354Ssam vap->iv_inact_probe = IEEE80211_INACT_PROBE; 152184277Ssam 153184277Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_INACT, 154184277Ssam "%s: init %u auth %u run %u probe %u\n", __func__, 155184277Ssam vap->iv_inact_init, vap->iv_inact_auth, 156184277Ssam vap->iv_inact_run, vap->iv_inact_probe); 157148863Ssam} 158148863Ssam 159148863Ssamvoid 160178354Ssamieee80211_node_latevattach(struct ieee80211vap *vap) 161148863Ssam{ 162178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 163178354Ssam /* XXX should we allow max aid to be zero? */ 164178354Ssam if (vap->iv_max_aid < IEEE80211_AID_MIN) { 165178354Ssam vap->iv_max_aid = IEEE80211_AID_MIN; 166178354Ssam if_printf(vap->iv_ifp, 167178354Ssam "WARNING: max aid too small, changed to %d\n", 168178354Ssam vap->iv_max_aid); 169178354Ssam } 170283538Sadrian vap->iv_aid_bitmap = (uint32_t *) IEEE80211_MALLOC( 171184210Sdes howmany(vap->iv_max_aid, 32) * sizeof(uint32_t), 172283538Sadrian M_80211_NODE, 173283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 174178354Ssam if (vap->iv_aid_bitmap == NULL) { 175178354Ssam /* XXX no way to recover */ 176178354Ssam printf("%s: no memory for AID bitmap, max aid %d!\n", 177178354Ssam __func__, vap->iv_max_aid); 178178354Ssam vap->iv_max_aid = 0; 179178354Ssam } 180138568Ssam } 181138568Ssam 182178354Ssam ieee80211_reset_bss(vap); 183118887Ssam 184178354Ssam vap->iv_auth = ieee80211_authenticator_get(vap->iv_bss->ni_authmode); 185116742Ssam} 186116742Ssam 187116742Ssamvoid 188178354Ssamieee80211_node_vdetach(struct ieee80211vap *vap) 189116742Ssam{ 190178354Ssam struct ieee80211com *ic = vap->iv_ic; 191116742Ssam 192178354Ssam ieee80211_node_table_reset(&ic->ic_sta, vap); 193178354Ssam if (vap->iv_bss != NULL) { 194178354Ssam ieee80211_free_node(vap->iv_bss); 195178354Ssam vap->iv_bss = NULL; 196138568Ssam } 197178354Ssam if (vap->iv_aid_bitmap != NULL) { 198283538Sadrian IEEE80211_FREE(vap->iv_aid_bitmap, M_80211_NODE); 199178354Ssam vap->iv_aid_bitmap = NULL; 200138568Ssam } 201116742Ssam} 202116742Ssam 203337951Skevans/* 204138568Ssam * Port authorize/unauthorize interfaces for use by an authenticator. 205138568Ssam */ 206138568Ssam 207138568Ssamvoid 208148302Ssamieee80211_node_authorize(struct ieee80211_node *ni) 209138568Ssam{ 210184277Ssam struct ieee80211vap *vap = ni->ni_vap; 211184277Ssam 212138568Ssam ni->ni_flags |= IEEE80211_NODE_AUTH; 213184277Ssam ni->ni_inact_reload = vap->iv_inact_run; 214172062Ssam ni->ni_inact = ni->ni_inact_reload; 215184277Ssam 216184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 217184277Ssam "%s: inact_reload %u", __func__, ni->ni_inact_reload); 218138568Ssam} 219138568Ssam 220138568Ssamvoid 221148302Ssamieee80211_node_unauthorize(struct ieee80211_node *ni) 222138568Ssam{ 223184277Ssam struct ieee80211vap *vap = ni->ni_vap; 224184277Ssam 225138568Ssam ni->ni_flags &= ~IEEE80211_NODE_AUTH; 226184277Ssam ni->ni_inact_reload = vap->iv_inact_auth; 227172062Ssam if (ni->ni_inact > ni->ni_inact_reload) 228172062Ssam ni->ni_inact = ni->ni_inact_reload; 229184277Ssam 230184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 231184277Ssam "%s: inact_reload %u inact %u", __func__, 232184277Ssam ni->ni_inact_reload, ni->ni_inact); 233138568Ssam} 234138568Ssam 235116742Ssam/* 236183251Ssam * Fix tx parameters for a node according to ``association state''. 237183251Ssam */ 238193966Ssamvoid 239193966Ssamieee80211_node_setuptxparms(struct ieee80211_node *ni) 240183251Ssam{ 241183251Ssam struct ieee80211vap *vap = ni->ni_vap; 242187898Ssam enum ieee80211_phymode mode; 243183251Ssam 244183251Ssam if (ni->ni_flags & IEEE80211_NODE_HT) { 245183251Ssam if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 246187898Ssam mode = IEEE80211_MODE_11NA; 247183251Ssam else 248187898Ssam mode = IEEE80211_MODE_11NG; 249183251Ssam } else { /* legacy rate handling */ 250187898Ssam if (IEEE80211_IS_CHAN_ST(ni->ni_chan)) 251187898Ssam mode = IEEE80211_MODE_STURBO_A; 252188782Ssam else if (IEEE80211_IS_CHAN_HALF(ni->ni_chan)) 253188782Ssam mode = IEEE80211_MODE_HALF; 254188782Ssam else if (IEEE80211_IS_CHAN_QUARTER(ni->ni_chan)) 255188782Ssam mode = IEEE80211_MODE_QUARTER; 256191015Ssam /* NB: 108A should be handled as 11a */ 257187898Ssam else if (IEEE80211_IS_CHAN_A(ni->ni_chan)) 258187898Ssam mode = IEEE80211_MODE_11A; 259191015Ssam else if (IEEE80211_IS_CHAN_108G(ni->ni_chan) || 260191015Ssam (ni->ni_flags & IEEE80211_NODE_ERP)) 261187898Ssam mode = IEEE80211_MODE_11G; 262183251Ssam else 263187898Ssam mode = IEEE80211_MODE_11B; 264183251Ssam } 265187898Ssam ni->ni_txparms = &vap->iv_txparms[mode]; 266183251Ssam} 267183251Ssam 268183251Ssam/* 269138568Ssam * Set/change the channel. The rate set is also updated as 270138568Ssam * to insure a consistent view by drivers. 271178354Ssam * XXX should be private but hostap needs it to deal with CSA 272138568Ssam */ 273178354Ssamvoid 274178354Ssamieee80211_node_set_chan(struct ieee80211_node *ni, 275178354Ssam struct ieee80211_channel *chan) 276138568Ssam{ 277178354Ssam struct ieee80211com *ic = ni->ni_ic; 278183251Ssam struct ieee80211vap *vap = ni->ni_vap; 279183251Ssam enum ieee80211_phymode mode; 280170530Ssam 281178354Ssam KASSERT(chan != IEEE80211_CHAN_ANYC, ("no channel")); 282178354Ssam 283138568Ssam ni->ni_chan = chan; 284183251Ssam mode = ieee80211_chan2mode(chan); 285170530Ssam if (IEEE80211_IS_CHAN_HT(chan)) { 286170530Ssam /* 287219602Sbschmidt * We must install the legacy rate est in ni_rates and the 288170530Ssam * HT rate set in ni_htrates. 289170530Ssam */ 290170530Ssam ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); 291183251Ssam /* 292183251Ssam * Setup bss tx parameters based on operating mode. We 293183251Ssam * use legacy rates when operating in a mixed HT+non-HT bss 294183251Ssam * and non-ERP rates in 11g for mixed ERP+non-ERP bss. 295183251Ssam */ 296183251Ssam if (mode == IEEE80211_MODE_11NA && 297193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) 298183251Ssam mode = IEEE80211_MODE_11A; 299183251Ssam else if (mode == IEEE80211_MODE_11NG && 300193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) 301183251Ssam mode = IEEE80211_MODE_11G; 302183251Ssam if (mode == IEEE80211_MODE_11G && 303183251Ssam (vap->iv_flags & IEEE80211_F_PUREG) == 0) 304183251Ssam mode = IEEE80211_MODE_11B; 305170530Ssam } 306183251Ssam ni->ni_txparms = &vap->iv_txparms[mode]; 307165569Ssam ni->ni_rates = *ieee80211_get_suprates(ic, chan); 308138568Ssam} 309138568Ssam 310141658Ssamstatic __inline void 311141658Ssamcopy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 312141658Ssam{ 313141658Ssam /* propagate useful state */ 314141658Ssam nbss->ni_authmode = obss->ni_authmode; 315141658Ssam nbss->ni_txpower = obss->ni_txpower; 316141658Ssam nbss->ni_vlan = obss->ni_vlan; 317141658Ssam /* XXX statistics? */ 318178354Ssam /* XXX legacy WDS bssid? */ 319141658Ssam} 320141658Ssam 321116742Ssamvoid 322178354Ssamieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan) 323116742Ssam{ 324178354Ssam struct ieee80211com *ic = vap->iv_ic; 325116742Ssam struct ieee80211_node *ni; 326116742Ssam 327178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, 328297731Sadrian "%s: creating %s on channel %u%c\n", __func__, 329195618Srpaulo ieee80211_opmode_name[vap->iv_opmode], 330297731Sadrian ieee80211_chan2ieee(ic, chan), 331297731Sadrian ieee80211_channel_type_char(chan)); 332138568Ssam 333178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 334140753Ssam if (ni == NULL) { 335140753Ssam /* XXX recovery? */ 336138568Ssam return; 337138568Ssam } 338178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 339178354Ssam ni->ni_esslen = vap->iv_des_ssid[0].len; 340178354Ssam memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 341178354Ssam if (vap->iv_bss != NULL) 342178354Ssam copy_bss(ni, vap->iv_bss); 343148843Ssam ni->ni_intval = ic->ic_bintval; 344178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) 345116742Ssam ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 346116742Ssam if (ic->ic_phytype == IEEE80211_T_FH) { 347116742Ssam ni->ni_fhdwell = 200; /* XXX */ 348116742Ssam ni->ni_fhindex = 1; 349116742Ssam } 350178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 351178354Ssam vap->iv_flags |= IEEE80211_F_SIBSS; 352138568Ssam ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 353178354Ssam if (vap->iv_flags & IEEE80211_F_DESBSSID) 354178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 355167282Ssam else { 356167282Ssam get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN); 357167282Ssam /* clear group bit, add local bit */ 358167282Ssam ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02; 359167282Ssam } 360178354Ssam } else if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 361178354Ssam if (vap->iv_flags & IEEE80211_F_DESBSSID) 362178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 363153403Ssam else 364186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 365186904Ssam if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 366186904Ssam#endif 367153403Ssam memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 368195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 369195618Srpaulo } else if (vap->iv_opmode == IEEE80211_M_MBSS) { 370195618Srpaulo ni->ni_meshidlen = vap->iv_mesh->ms_idlen; 371195618Srpaulo memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen); 372195618Srpaulo#endif 373138568Ssam } 374337951Skevans /* 375138568Ssam * Fix the channel and related attributes. 376138568Ssam */ 377178354Ssam /* clear DFS CAC state on previous channel */ 378178354Ssam if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && 379178354Ssam ic->ic_bsschan->ic_freq != chan->ic_freq && 380178354Ssam IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) 381178354Ssam ieee80211_dfs_cac_clear(ic, ic->ic_bsschan); 382170530Ssam ic->ic_bsschan = chan; 383178354Ssam ieee80211_node_set_chan(ni, chan); 384170530Ssam ic->ic_curmode = ieee80211_chan2mode(chan); 385138568Ssam /* 386178354Ssam * Do mode-specific setup. 387138568Ssam */ 388170530Ssam if (IEEE80211_IS_CHAN_FULL(chan)) { 389170530Ssam if (IEEE80211_IS_CHAN_ANYG(chan)) { 390170530Ssam /* 391178354Ssam * Use a mixed 11b/11g basic rate set. 392170530Ssam */ 393178354Ssam ieee80211_setbasicrates(&ni->ni_rates, 394178354Ssam IEEE80211_MODE_11G); 395178354Ssam if (vap->iv_flags & IEEE80211_F_PUREG) { 396178354Ssam /* 397178354Ssam * Also mark OFDM rates basic so 11b 398178354Ssam * stations do not join (WiFi compliance). 399178354Ssam */ 400178354Ssam ieee80211_addbasicrates(&ni->ni_rates, 401178354Ssam IEEE80211_MODE_11A); 402178354Ssam } 403170530Ssam } else if (IEEE80211_IS_CHAN_B(chan)) { 404170530Ssam /* 405170530Ssam * Force pure 11b rate set. 406170530Ssam */ 407178354Ssam ieee80211_setbasicrates(&ni->ni_rates, 408170530Ssam IEEE80211_MODE_11B); 409170530Ssam } 410170530Ssam } 411138568Ssam 412170530Ssam (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); 413116742Ssam} 414116742Ssam 415170530Ssam/* 416170530Ssam * Reset bss state on transition to the INIT state. 417170530Ssam * Clear any stations from the table (they have been 418170530Ssam * deauth'd) and reset the bss node (clears key, rate 419170530Ssam * etc. state). 420170530Ssam */ 421138568Ssamvoid 422178354Ssamieee80211_reset_bss(struct ieee80211vap *vap) 423138568Ssam{ 424178354Ssam struct ieee80211com *ic = vap->iv_ic; 425138568Ssam struct ieee80211_node *ni, *obss; 426138568Ssam 427178354Ssam ieee80211_node_table_reset(&ic->ic_sta, vap); 428178354Ssam /* XXX multi-bss: wrong */ 429170530Ssam ieee80211_reset_erp(ic); 430140753Ssam 431178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 432207322Srpaulo KASSERT(ni != NULL, ("unable to setup initial BSS node")); 433178354Ssam obss = vap->iv_bss; 434178354Ssam vap->iv_bss = ieee80211_ref_node(ni); 435141658Ssam if (obss != NULL) { 436141658Ssam copy_bss(ni, obss); 437148843Ssam ni->ni_intval = ic->ic_bintval; 438138568Ssam ieee80211_free_node(obss); 439178354Ssam } else 440178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 441138568Ssam} 442138568Ssam 443170530Ssamstatic int 444170530Ssammatch_ssid(const struct ieee80211_node *ni, 445170530Ssam int nssid, const struct ieee80211_scan_ssid ssids[]) 446170530Ssam{ 447170530Ssam int i; 448148432Ssam 449170530Ssam for (i = 0; i < nssid; i++) { 450170530Ssam if (ni->ni_esslen == ssids[i].len && 451170530Ssam memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0) 452170530Ssam return 1; 453170530Ssam } 454170530Ssam return 0; 455170530Ssam} 456170530Ssam 457170530Ssam/* 458170530Ssam * Test a node for suitability/compatibility. 459170530Ssam */ 460127767Ssamstatic int 461178354Ssamcheck_bss(struct ieee80211vap *vap, struct ieee80211_node *ni) 462127767Ssam{ 463178354Ssam struct ieee80211com *ic = ni->ni_ic; 464170530Ssam uint8_t rate; 465170530Ssam 466170530Ssam if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 467170530Ssam return 0; 468178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 469170530Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 470170530Ssam return 0; 471170530Ssam } else { 472170530Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 473170530Ssam return 0; 474170530Ssam } 475178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) { 476170530Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 477170530Ssam return 0; 478170530Ssam } else { 479170530Ssam /* XXX does this mean privacy is supported or required? */ 480170530Ssam if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 481170530Ssam return 0; 482170530Ssam } 483170530Ssam rate = ieee80211_fix_rate(ni, &ni->ni_rates, 484170530Ssam IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 485170530Ssam if (rate & IEEE80211_RATE_BASIC) 486170530Ssam return 0; 487178354Ssam if (vap->iv_des_nssid != 0 && 488178354Ssam !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 489170530Ssam return 0; 490178354Ssam if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 491178354Ssam !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 492170530Ssam return 0; 493170530Ssam return 1; 494170530Ssam} 495170530Ssam 496170530Ssam#ifdef IEEE80211_DEBUG 497170530Ssam/* 498170530Ssam * Display node suitability/compatibility. 499170530Ssam */ 500170530Ssamstatic void 501178354Ssamcheck_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni) 502170530Ssam{ 503178354Ssam struct ieee80211com *ic = ni->ni_ic; 504170530Ssam uint8_t rate; 505127767Ssam int fail; 506127767Ssam 507127767Ssam fail = 0; 508127767Ssam if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 509127767Ssam fail |= 0x01; 510178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 511127767Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 512127767Ssam fail |= 0x02; 513127767Ssam } else { 514127767Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 515127767Ssam fail |= 0x02; 516127767Ssam } 517178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) { 518127767Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 519127767Ssam fail |= 0x04; 520127767Ssam } else { 521127767Ssam /* XXX does this mean privacy is supported or required? */ 522127767Ssam if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 523127767Ssam fail |= 0x04; 524127767Ssam } 525167442Ssam rate = ieee80211_fix_rate(ni, &ni->ni_rates, 526165887Ssam IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 527127767Ssam if (rate & IEEE80211_RATE_BASIC) 528127767Ssam fail |= 0x08; 529178354Ssam if (vap->iv_des_nssid != 0 && 530178354Ssam !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 531127767Ssam fail |= 0x10; 532178354Ssam if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 533178354Ssam !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 534127767Ssam fail |= 0x20; 535127767Ssam 536170530Ssam printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); 537170530Ssam printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); 538170530Ssam printf(" %3d%c", 539170530Ssam ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); 540170530Ssam printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 541170530Ssam fail & 0x08 ? '!' : ' '); 542170530Ssam printf(" %4s%c", 543170530Ssam (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 544170530Ssam (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 545170530Ssam "????", 546170530Ssam fail & 0x02 ? '!' : ' '); 547170530Ssam printf(" %3s%c ", 548170530Ssam (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no", 549170530Ssam fail & 0x04 ? '!' : ' '); 550170530Ssam ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 551170530Ssam printf("%s\n", fail & 0x10 ? "!" : ""); 552138568Ssam} 553170530Ssam#endif /* IEEE80211_DEBUG */ 554297728Sadrian 555337951Skevans 556297728Sadrianint 557297728Sadrianieee80211_ibss_merge_check(struct ieee80211_node *ni) 558297728Sadrian{ 559297728Sadrian struct ieee80211vap *vap = ni->ni_vap; 560297728Sadrian 561297728Sadrian if (ni == vap->iv_bss || 562297728Sadrian IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { 563297728Sadrian /* unchanged, nothing to do */ 564297728Sadrian return 0; 565297728Sadrian } 566297728Sadrian 567297728Sadrian if (!check_bss(vap, ni)) { 568297728Sadrian /* capabilities mismatch */ 569297728Sadrian IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 570297728Sadrian "%s: merge failed, capabilities mismatch\n", __func__); 571297728Sadrian#ifdef IEEE80211_DEBUG 572297728Sadrian if (ieee80211_msg_assoc(vap)) 573297728Sadrian check_bss_debug(vap, ni); 574297728Sadrian#endif 575297728Sadrian vap->iv_stats.is_ibss_capmismatch++; 576297728Sadrian return 0; 577297728Sadrian } 578297728Sadrian 579297728Sadrian return 1; 580297728Sadrian} 581297728Sadrian 582138568Ssam/* 583330458Seadler * Check if the given node should populate the node table. 584330458Seadler * 585330458Seadler * We need to be in "see all beacons for all ssids" mode in order 586330458Seadler * to do IBSS merges, however this means we will populate nodes for 587330458Seadler * /all/ IBSS SSIDs, versus just the one we care about. 588330458Seadler * 589330458Seadler * So this check ensures the node can actually belong to our IBSS 590330458Seadler * configuration. For now it simply checks the SSID. 591330458Seadler */ 592330458Seadlerint 593330458Seadlerieee80211_ibss_node_check_new(struct ieee80211_node *ni, 594330458Seadler const struct ieee80211_scanparams *scan) 595330458Seadler{ 596330458Seadler struct ieee80211vap *vap = ni->ni_vap; 597330458Seadler int i; 598330458Seadler 599330458Seadler /* 600330458Seadler * If we have no SSID and no scan SSID, return OK. 601330458Seadler */ 602330458Seadler if (vap->iv_des_nssid == 0 && scan->ssid == NULL) 603330458Seadler goto ok; 604330458Seadler 605330458Seadler /* 606330458Seadler * If we have one of (SSID, scan SSID) then return error. 607330458Seadler */ 608330458Seadler if (!! (vap->iv_des_nssid == 0) != !! (scan->ssid == NULL)) 609330458Seadler goto mismatch; 610330458Seadler 611330458Seadler /* 612330458Seadler * Double-check - we need scan SSID. 613330458Seadler */ 614330458Seadler if (scan->ssid == NULL) 615330458Seadler goto mismatch; 616330458Seadler 617330458Seadler /* 618330458Seadler * Check if the scan SSID matches the SSID list for the VAP. 619330458Seadler */ 620330458Seadler for (i = 0; i < vap->iv_des_nssid; i++) { 621330458Seadler 622330458Seadler /* Sanity length check */ 623330458Seadler if (vap->iv_des_ssid[i].len != scan->ssid[1]) 624330458Seadler continue; 625330458Seadler 626330458Seadler /* Note: SSID in the scan entry is the IE format */ 627330458Seadler if (memcmp(vap->iv_des_ssid[i].ssid, scan->ssid + 2, 628330458Seadler vap->iv_des_ssid[i].len) == 0) 629330458Seadler goto ok; 630330458Seadler } 631330458Seadler 632330458Seadlermismatch: 633330458Seadler return (0); 634330458Seadlerok: 635330458Seadler return (1); 636330458Seadler} 637330458Seadler 638330458Seadler/* 639138568Ssam * Handle 802.11 ad hoc network merge. The 640138568Ssam * convention, set by the Wireless Ethernet Compatibility Alliance 641138568Ssam * (WECA), is that an 802.11 station will change its BSSID to match 642138568Ssam * the "oldest" 802.11 ad hoc network, on the same channel, that 643138568Ssam * has the station's desired SSID. The "oldest" 802.11 network 644138568Ssam * sends beacons with the greatest TSF timestamp. 645138568Ssam * 646138568Ssam * The caller is assumed to validate TSF's before attempting a merge. 647138568Ssam * 648138568Ssam * Return !0 if the BSSID changed, 0 otherwise. 649138568Ssam */ 650138568Ssamint 651148306Ssamieee80211_ibss_merge(struct ieee80211_node *ni) 652138568Ssam{ 653297733Sbz#ifdef IEEE80211_DEBUG 654178354Ssam struct ieee80211vap *vap = ni->ni_vap; 655148306Ssam struct ieee80211com *ic = ni->ni_ic; 656178354Ssam#endif 657138568Ssam 658297728Sadrian if (! ieee80211_ibss_merge_check(ni)) 659138568Ssam return 0; 660297728Sadrian 661178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 662138568Ssam "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__, 663138568Ssam ether_sprintf(ni->ni_bssid), 664138568Ssam ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 665138568Ssam ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 666138568Ssam ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 667138568Ssam ); 668170530Ssam return ieee80211_sta_join1(ieee80211_ref_node(ni)); 669138568Ssam} 670138568Ssam 671138568Ssam/* 672178354Ssam * Calculate HT channel promotion flags for all vaps. 673178354Ssam * This assumes ni_chan have been setup for each vap. 674173273Ssam */ 675178354Ssamstatic int 676178354Ssamgethtadjustflags(struct ieee80211com *ic) 677178354Ssam{ 678178354Ssam struct ieee80211vap *vap; 679178354Ssam int flags; 680178354Ssam 681178354Ssam flags = 0; 682178354Ssam /* XXX locking */ 683178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 684178354Ssam if (vap->iv_state < IEEE80211_S_RUN) 685178354Ssam continue; 686178354Ssam switch (vap->iv_opmode) { 687178354Ssam case IEEE80211_M_WDS: 688178354Ssam case IEEE80211_M_STA: 689178354Ssam case IEEE80211_M_AHDEMO: 690178354Ssam case IEEE80211_M_HOSTAP: 691178354Ssam case IEEE80211_M_IBSS: 692195618Srpaulo case IEEE80211_M_MBSS: 693178354Ssam flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan); 694178354Ssam break; 695178354Ssam default: 696178354Ssam break; 697178354Ssam } 698178354Ssam } 699178354Ssam return flags; 700178354Ssam} 701178354Ssam 702178354Ssam/* 703178354Ssam * Check if the current channel needs to change based on whether 704184303Ssam * any vap's are using HT20/HT40. This is used to sync the state 705184303Ssam * of ic_curchan after a channel width change on a running vap. 706178354Ssam */ 707173273Ssamvoid 708178354Ssamieee80211_sync_curchan(struct ieee80211com *ic) 709173273Ssam{ 710178354Ssam struct ieee80211_channel *c; 711178354Ssam 712178354Ssam c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic)); 713178354Ssam if (c != ic->ic_curchan) { 714178354Ssam ic->ic_curchan = c; 715178354Ssam ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 716190532Ssam ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); 717191746Sthompsa IEEE80211_UNLOCK(ic); 718178354Ssam ic->ic_set_channel(ic); 719192468Ssam ieee80211_radiotap_chan_change(ic); 720191746Sthompsa IEEE80211_LOCK(ic); 721178354Ssam } 722178354Ssam} 723178354Ssam 724178354Ssam/* 725191746Sthompsa * Setup the current channel. The request channel may be 726178354Ssam * promoted if other vap's are operating with HT20/HT40. 727178354Ssam */ 728178354Ssamvoid 729191746Sthompsaieee80211_setupcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 730178354Ssam{ 731178354Ssam if (ic->ic_htcaps & IEEE80211_HTC_HT) { 732178354Ssam int flags = gethtadjustflags(ic); 733178354Ssam /* 734178354Ssam * Check for channel promotion required to support the 735178354Ssam * set of running vap's. This assumes we are called 736178354Ssam * after ni_chan is setup for each vap. 737178354Ssam */ 738193655Ssam /* NB: this assumes IEEE80211_FHT_USEHT40 > IEEE80211_FHT_HT */ 739178354Ssam if (flags > ieee80211_htchanflags(c)) 740178354Ssam c = ieee80211_ht_adjust_channel(ic, c, flags); 741178354Ssam } 742178354Ssam ic->ic_bsschan = ic->ic_curchan = c; 743173273Ssam ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 744190532Ssam ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); 745173273Ssam} 746173273Ssam 747173273Ssam/* 748191746Sthompsa * Change the current channel. The channel change is guaranteed to have 749191746Sthompsa * happened before the next state change. 750191746Sthompsa */ 751191746Sthompsavoid 752191746Sthompsaieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 753191746Sthompsa{ 754191746Sthompsa ieee80211_setupcurchan(ic, c); 755191746Sthompsa ieee80211_runtask(ic, &ic->ic_chan_task); 756191746Sthompsa} 757191746Sthompsa 758233452Sadrianvoid 759233452Sadrianieee80211_update_chw(struct ieee80211com *ic) 760233452Sadrian{ 761233452Sadrian 762233452Sadrian ieee80211_setupcurchan(ic, ic->ic_curchan); 763233452Sadrian ieee80211_runtask(ic, &ic->ic_chw_task); 764233452Sadrian} 765233452Sadrian 766191746Sthompsa/* 767138568Ssam * Join the specified IBSS/BSS network. The node is assumed to 768138568Ssam * be passed in with a held reference. 769138568Ssam */ 770170530Ssamstatic int 771170530Ssamieee80211_sta_join1(struct ieee80211_node *selbs) 772138568Ssam{ 773178354Ssam struct ieee80211vap *vap = selbs->ni_vap; 774170530Ssam struct ieee80211com *ic = selbs->ni_ic; 775138568Ssam struct ieee80211_node *obss; 776170530Ssam int canreassoc; 777138568Ssam 778138568Ssam /* 779138568Ssam * Committed to selbs, setup state. 780138568Ssam */ 781178354Ssam obss = vap->iv_bss; 782170530Ssam /* 783170530Ssam * Check if old+new node have the same address in which 784170530Ssam * case we can reassociate when operating in sta mode. 785170530Ssam */ 786170530Ssam canreassoc = (obss != NULL && 787178354Ssam vap->iv_state == IEEE80211_S_RUN && 788170530Ssam IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr)); 789178354Ssam vap->iv_bss = selbs; /* NB: caller assumed to bump refcnt */ 790153352Ssam if (obss != NULL) { 791282372Sadrian struct ieee80211_node_table *nt = obss->ni_table; 792282372Sadrian 793153352Ssam copy_bss(selbs, obss); 794188541Ssam ieee80211_node_decref(obss); /* iv_bss reference */ 795282372Sadrian 796282372Sadrian IEEE80211_NODE_LOCK(nt); 797282372Sadrian node_reclaim(nt, obss); /* station table reference */ 798282372Sadrian IEEE80211_NODE_UNLOCK(nt); 799282372Sadrian 800178354Ssam obss = NULL; /* NB: guard against later use */ 801153352Ssam } 802165887Ssam 803138568Ssam /* 804165887Ssam * Delete unusable rates; we've already checked 805165887Ssam * that the negotiated rate set is acceptable. 806165887Ssam */ 807178354Ssam ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates, 808167442Ssam IEEE80211_F_DODEL | IEEE80211_F_JOIN); 809165887Ssam 810178354Ssam ieee80211_setcurchan(ic, selbs->ni_chan); 811165887Ssam /* 812138568Ssam * Set the erp state (mostly the slot time) to deal with 813138568Ssam * the auto-select case; this should be redundant if the 814138568Ssam * mode is locked. 815337951Skevans */ 816138568Ssam ieee80211_reset_erp(ic); 817178354Ssam ieee80211_wme_initparams(vap); 818140753Ssam 819178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 820170530Ssam if (canreassoc) { 821170530Ssam /* Reassociate */ 822178354Ssam ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1); 823170530Ssam } else { 824170530Ssam /* 825170530Ssam * Act as if we received a DEAUTH frame in case we 826170530Ssam * are invoked from the RUN state. This will cause 827170530Ssam * us to try to re-authenticate if we are operating 828170530Ssam * as a station. 829170530Ssam */ 830178354Ssam ieee80211_new_state(vap, IEEE80211_S_AUTH, 831170530Ssam IEEE80211_FC0_SUBTYPE_DEAUTH); 832170530Ssam } 833170530Ssam } else 834178354Ssam ieee80211_new_state(vap, IEEE80211_S_RUN, -1); 835138568Ssam return 1; 836116742Ssam} 837116742Ssam 838170530Ssamint 839184274Ssamieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan, 840170530Ssam const struct ieee80211_scan_entry *se) 841170530Ssam{ 842178354Ssam struct ieee80211com *ic = vap->iv_ic; 843170530Ssam struct ieee80211_node *ni; 844170530Ssam 845178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr); 846170530Ssam if (ni == NULL) { 847170530Ssam /* XXX msg */ 848170530Ssam return 0; 849170530Ssam } 850245928Sadrian 851170530Ssam /* 852170530Ssam * Expand scan state into node's format. 853170530Ssam * XXX may not need all this stuff 854170530Ssam */ 855170530Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid); 856170530Ssam ni->ni_esslen = se->se_ssid[1]; 857170530Ssam memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen); 858170530Ssam ni->ni_tstamp.tsf = se->se_tstamp.tsf; 859170530Ssam ni->ni_intval = se->se_intval; 860170530Ssam ni->ni_capinfo = se->se_capinfo; 861184274Ssam ni->ni_chan = chan; 862170530Ssam ni->ni_timoff = se->se_timoff; 863170530Ssam ni->ni_fhdwell = se->se_fhdwell; 864170530Ssam ni->ni_fhindex = se->se_fhindex; 865170530Ssam ni->ni_erp = se->se_erp; 866178354Ssam IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi); 867170530Ssam ni->ni_noise = se->se_noise; 868186870Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 869186870Ssam /* NB: only infrastructure mode requires an associd */ 870186870Ssam ni->ni_flags |= IEEE80211_NODE_ASSOCID; 871186870Ssam } 872178354Ssam 873178354Ssam if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) { 874178354Ssam ieee80211_ies_expand(&ni->ni_ies); 875190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 876178354Ssam if (ni->ni_ies.ath_ie != NULL) 877178354Ssam ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 878190391Ssam#endif 879178354Ssam if (ni->ni_ies.htcap_ie != NULL) 880178354Ssam ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie); 881178354Ssam if (ni->ni_ies.htinfo_ie != NULL) 882178354Ssam ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie); 883195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 884195618Srpaulo if (ni->ni_ies.meshid_ie != NULL) 885195618Srpaulo ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie); 886195618Srpaulo#endif 887186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 888186904Ssam if (ni->ni_ies.tdma_ie != NULL) 889186904Ssam ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie); 890186904Ssam#endif 891173864Ssam } 892170530Ssam 893178354Ssam vap->iv_dtim_period = se->se_dtimperiod; 894178354Ssam vap->iv_dtim_count = 0; 895170530Ssam 896170530Ssam /* NB: must be after ni_chan is setup */ 897170530Ssam ieee80211_setup_rates(ni, se->se_rates, se->se_xrates, 898170530Ssam IEEE80211_F_DOSORT); 899184279Ssam if (ieee80211_iserp_rateset(&ni->ni_rates)) 900184279Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 901245928Sadrian 902245928Sadrian /* 903245928Sadrian * Setup HT state for this node if it's available, otherwise 904245928Sadrian * non-STA modes won't pick this state up. 905245928Sadrian * 906245928Sadrian * For IBSS and related modes that don't go through an 907245928Sadrian * association request/response, the only appropriate place 908245928Sadrian * to setup the HT state is here. 909245928Sadrian */ 910245928Sadrian if (ni->ni_ies.htinfo_ie != NULL && 911245928Sadrian ni->ni_ies.htcap_ie != NULL && 912245928Sadrian vap->iv_flags_ht & IEEE80211_FHT_HT) { 913245928Sadrian ieee80211_ht_node_init(ni); 914245928Sadrian ieee80211_ht_updateparams(ni, 915245928Sadrian ni->ni_ies.htcap_ie, 916245928Sadrian ni->ni_ies.htinfo_ie); 917245928Sadrian ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie, 918245928Sadrian IEEE80211_F_JOIN | IEEE80211_F_DOBRS); 919245928Sadrian ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie); 920245928Sadrian } 921245928Sadrian /* XXX else check for ath FF? */ 922245928Sadrian /* XXX QoS? Difficult given that WME config is specific to a master */ 923245928Sadrian 924193966Ssam ieee80211_node_setuptxparms(ni); 925214894Sbschmidt ieee80211_ratectl_node_init(ni); 926170530Ssam 927170530Ssam return ieee80211_sta_join1(ieee80211_ref_node(ni)); 928170530Ssam} 929170530Ssam 930138568Ssam/* 931138568Ssam * Leave the specified IBSS/BSS network. The node is assumed to 932138568Ssam * be passed in with a held reference. 933138568Ssam */ 934138568Ssamvoid 935178354Ssamieee80211_sta_leave(struct ieee80211_node *ni) 936138568Ssam{ 937178354Ssam struct ieee80211com *ic = ni->ni_ic; 938178354Ssam 939138568Ssam ic->ic_node_cleanup(ni); 940178354Ssam ieee80211_notify_node_leave(ni); 941138568Ssam} 942138568Ssam 943178354Ssam/* 944178354Ssam * Send a deauthenticate frame and drop the station. 945178354Ssam */ 946178354Ssamvoid 947178354Ssamieee80211_node_deauth(struct ieee80211_node *ni, int reason) 948178354Ssam{ 949282404Sadrian /* NB: bump the refcnt to be sure temporary nodes are not reclaimed */ 950178354Ssam ieee80211_ref_node(ni); 951178354Ssam if (ni->ni_associd != 0) 952178354Ssam IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); 953178354Ssam ieee80211_node_leave(ni); 954178354Ssam ieee80211_free_node(ni); 955178354Ssam} 956178354Ssam 957116742Ssamstatic struct ieee80211_node * 958179643Ssamnode_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 959116742Ssam{ 960127768Ssam struct ieee80211_node *ni; 961138568Ssam 962283538Sadrian ni = (struct ieee80211_node *) IEEE80211_MALLOC(sizeof(struct ieee80211_node), 963283538Sadrian M_80211_NODE, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 964127768Ssam return ni; 965116742Ssam} 966116742Ssam 967138568Ssam/* 968178354Ssam * Initialize an ie blob with the specified data. If previous 969178354Ssam * data exists re-use the data block. As a side effect we clear 970178354Ssam * all references to specific ie's; the caller is required to 971178354Ssam * recalculate them. 972178354Ssam */ 973178354Ssamint 974178354Ssamieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len) 975178354Ssam{ 976178354Ssam /* NB: assumes data+len are the last fields */ 977178354Ssam memset(ies, 0, offsetof(struct ieee80211_ies, data)); 978178354Ssam if (ies->data != NULL && ies->len != len) { 979178354Ssam /* data size changed */ 980283538Sadrian IEEE80211_FREE(ies->data, M_80211_NODE_IE); 981178354Ssam ies->data = NULL; 982178354Ssam } 983178354Ssam if (ies->data == NULL) { 984283538Sadrian ies->data = (uint8_t *) IEEE80211_MALLOC(len, M_80211_NODE_IE, 985283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 986178354Ssam if (ies->data == NULL) { 987178354Ssam ies->len = 0; 988178354Ssam /* NB: pointers have already been zero'd above */ 989178354Ssam return 0; 990178354Ssam } 991178354Ssam } 992178354Ssam memcpy(ies->data, data, len); 993178354Ssam ies->len = len; 994178354Ssam return 1; 995178354Ssam} 996178354Ssam 997178354Ssam/* 998178354Ssam * Reclaim storage for an ie blob. 999178354Ssam */ 1000178354Ssamvoid 1001178354Ssamieee80211_ies_cleanup(struct ieee80211_ies *ies) 1002178354Ssam{ 1003178354Ssam if (ies->data != NULL) 1004283538Sadrian IEEE80211_FREE(ies->data, M_80211_NODE_IE); 1005178354Ssam} 1006178354Ssam 1007178354Ssam/* 1008178354Ssam * Expand an ie blob data contents and to fillin individual 1009178354Ssam * ie pointers. The data blob is assumed to be well-formed; 1010178354Ssam * we don't do any validity checking of ie lengths. 1011178354Ssam */ 1012178354Ssamvoid 1013178354Ssamieee80211_ies_expand(struct ieee80211_ies *ies) 1014178354Ssam{ 1015178354Ssam uint8_t *ie; 1016178354Ssam int ielen; 1017178354Ssam 1018178354Ssam ie = ies->data; 1019178354Ssam ielen = ies->len; 1020178354Ssam while (ielen > 0) { 1021178354Ssam switch (ie[0]) { 1022178354Ssam case IEEE80211_ELEMID_VENDOR: 1023178354Ssam if (iswpaoui(ie)) 1024178354Ssam ies->wpa_ie = ie; 1025178354Ssam else if (iswmeoui(ie)) 1026178354Ssam ies->wme_ie = ie; 1027190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1028178354Ssam else if (isatherosoui(ie)) 1029178354Ssam ies->ath_ie = ie; 1030190391Ssam#endif 1031186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 1032186904Ssam else if (istdmaoui(ie)) 1033186904Ssam ies->tdma_ie = ie; 1034186904Ssam#endif 1035178354Ssam break; 1036178354Ssam case IEEE80211_ELEMID_RSN: 1037178354Ssam ies->rsn_ie = ie; 1038178354Ssam break; 1039178354Ssam case IEEE80211_ELEMID_HTCAP: 1040178354Ssam ies->htcap_ie = ie; 1041178354Ssam break; 1042245928Sadrian case IEEE80211_ELEMID_HTINFO: 1043245928Sadrian ies->htinfo_ie = ie; 1044245928Sadrian break; 1045195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1046195618Srpaulo case IEEE80211_ELEMID_MESHID: 1047195618Srpaulo ies->meshid_ie = ie; 1048195618Srpaulo break; 1049195618Srpaulo#endif 1050178354Ssam } 1051178354Ssam ielen -= 2 + ie[1]; 1052178354Ssam ie += 2 + ie[1]; 1053178354Ssam } 1054178354Ssam} 1055178354Ssam 1056178354Ssam/* 1057138568Ssam * Reclaim any resources in a node and reset any critical 1058138568Ssam * state. Typically nodes are free'd immediately after, 1059138568Ssam * but in some cases the storage may be reused so we need 1060138568Ssam * to insure consistent state (should probably fix that). 1061138568Ssam */ 1062116742Ssamstatic void 1063138568Ssamnode_cleanup(struct ieee80211_node *ni) 1064116742Ssam{ 1065178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1066195379Ssam struct ieee80211com *ic = ni->ni_ic; 1067170530Ssam int i; 1068138568Ssam 1069138568Ssam /* NB: preserve ni_table */ 1070138568Ssam if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 1071178354Ssam if (vap->iv_opmode != IEEE80211_M_STA) 1072178354Ssam vap->iv_ps_sta--; 1073138568Ssam ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 1074178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 1075178354Ssam "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); 1076138568Ssam } 1077147788Ssam /* 1078173273Ssam * Cleanup any HT-related state. 1079173273Ssam */ 1080173273Ssam if (ni->ni_flags & IEEE80211_NODE_HT) 1081173273Ssam ieee80211_ht_node_cleanup(ni); 1082190579Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1083297603Sadrian /* Always do FF node cleanup; for A-MSDU */ 1084297603Sadrian ieee80211_ff_node_cleanup(ni); 1085190579Ssam#endif 1086195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1087173273Ssam /* 1088195618Srpaulo * Cleanup any mesh-related state. 1089195618Srpaulo */ 1090195618Srpaulo if (vap->iv_opmode == IEEE80211_M_MBSS) 1091195618Srpaulo ieee80211_mesh_node_cleanup(ni); 1092195618Srpaulo#endif 1093195618Srpaulo /* 1094195379Ssam * Clear any staging queue entries. 1095195379Ssam */ 1096195379Ssam ieee80211_ageq_drain_node(&ic->ic_stageq, ni); 1097195379Ssam 1098195379Ssam /* 1099147788Ssam * Clear AREF flag that marks the authorization refcnt bump 1100147788Ssam * has happened. This is probably not needed as the node 1101147788Ssam * should always be removed from the table so not found but 1102147788Ssam * do it just in case. 1103186099Ssam * Likewise clear the ASSOCID flag as these flags are intended 1104186099Ssam * to be managed in tandem. 1105147788Ssam */ 1106186099Ssam ni->ni_flags &= ~(IEEE80211_NODE_AREF | IEEE80211_NODE_ASSOCID); 1107138568Ssam 1108138568Ssam /* 1109138568Ssam * Drain power save queue and, if needed, clear TIM. 1110138568Ssam */ 1111184288Ssam if (ieee80211_node_psq_drain(ni) != 0 && vap->iv_set_tim != NULL) 1112178354Ssam vap->iv_set_tim(ni, 0); 1113138568Ssam 1114138568Ssam ni->ni_associd = 0; 1115138568Ssam if (ni->ni_challenge != NULL) { 1116283538Sadrian IEEE80211_FREE(ni->ni_challenge, M_80211_NODE); 1117138568Ssam ni->ni_challenge = NULL; 1118138568Ssam } 1119138568Ssam /* 1120138568Ssam * Preserve SSID, WPA, and WME ie's so the bss node is 1121138568Ssam * reusable during a re-auth/re-assoc state transition. 1122138568Ssam * If we remove these data they will not be recreated 1123138568Ssam * because they come from a probe-response or beacon frame 1124138568Ssam * which cannot be expected prior to the association-response. 1125138568Ssam * This should not be an issue when operating in other modes 1126138568Ssam * as stations leaving always go through a full state transition 1127138568Ssam * which will rebuild this state. 1128138568Ssam * 1129138568Ssam * XXX does this leave us open to inheriting old state? 1130138568Ssam */ 1131254315Srpaulo for (i = 0; i < nitems(ni->ni_rxfrag); i++) 1132138568Ssam if (ni->ni_rxfrag[i] != NULL) { 1133138568Ssam m_freem(ni->ni_rxfrag[i]); 1134138568Ssam ni->ni_rxfrag[i] = NULL; 1135138568Ssam } 1136148863Ssam /* 1137148863Ssam * Must be careful here to remove any key map entry w/o a LOR. 1138148863Ssam */ 1139148863Ssam ieee80211_node_delucastkey(ni); 1140116742Ssam} 1141116742Ssam 1142116742Ssamstatic void 1143138568Ssamnode_free(struct ieee80211_node *ni) 1144116742Ssam{ 1145138568Ssam struct ieee80211com *ic = ni->ni_ic; 1146138568Ssam 1147214894Sbschmidt ieee80211_ratectl_node_deinit(ni); 1148138568Ssam ic->ic_node_cleanup(ni); 1149178354Ssam ieee80211_ies_cleanup(&ni->ni_ies); 1150184288Ssam ieee80211_psq_cleanup(&ni->ni_psq); 1151283538Sadrian IEEE80211_FREE(ni, M_80211_NODE); 1152116742Ssam} 1153116742Ssam 1154178354Ssamstatic void 1155178354Ssamnode_age(struct ieee80211_node *ni) 1156178354Ssam{ 1157178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1158184303Ssam 1159178354Ssam /* 1160178354Ssam * Age frames on the power save queue. 1161178354Ssam */ 1162184288Ssam if (ieee80211_node_psq_age(ni) != 0 && 1163184288Ssam ni->ni_psq.psq_len == 0 && vap->iv_set_tim != NULL) 1164178354Ssam vap->iv_set_tim(ni, 0); 1165178354Ssam /* 1166178354Ssam * Age out HT resources (e.g. frames on the 1167178354Ssam * A-MPDU reorder queues). 1168178354Ssam */ 1169178354Ssam if (ni->ni_associd != 0 && (ni->ni_flags & IEEE80211_NODE_HT)) 1170178354Ssam ieee80211_ht_node_age(ni); 1171178354Ssam} 1172178354Ssam 1173170530Ssamstatic int8_t 1174138568Ssamnode_getrssi(const struct ieee80211_node *ni) 1175120104Ssam{ 1176178354Ssam uint32_t avgrssi = ni->ni_avgrssi; 1177178354Ssam int32_t rssi; 1178178354Ssam 1179178354Ssam if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) 1180178354Ssam return 0; 1181178354Ssam rssi = IEEE80211_RSSI_GET(avgrssi); 1182178354Ssam return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 1183120104Ssam} 1184120104Ssam 1185116742Ssamstatic void 1186170530Ssamnode_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise) 1187170530Ssam{ 1188178354Ssam *rssi = node_getrssi(ni); 1189170530Ssam *noise = ni->ni_noise; 1190170530Ssam} 1191170530Ssam 1192170530Ssamstatic void 1193178354Ssamnode_getmimoinfo(const struct ieee80211_node *ni, 1194178354Ssam struct ieee80211_mimo_info *info) 1195116742Ssam{ 1196220445Sadrian int i; 1197220445Sadrian uint32_t avgrssi; 1198220445Sadrian int32_t rssi; 1199220445Sadrian 1200220445Sadrian bzero(info, sizeof(*info)); 1201220445Sadrian 1202220445Sadrian for (i = 0; i < ni->ni_mimo_chains; i++) { 1203220445Sadrian avgrssi = ni->ni_mimo_rssi_ctl[i]; 1204220445Sadrian if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) { 1205220935Sadrian info->rssi[i] = 0; 1206220445Sadrian } else { 1207220445Sadrian rssi = IEEE80211_RSSI_GET(avgrssi); 1208220935Sadrian info->rssi[i] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 1209220445Sadrian } 1210220935Sadrian info->noise[i] = ni->ni_mimo_noise_ctl[i]; 1211220445Sadrian } 1212220445Sadrian 1213220935Sadrian /* XXX ext radios? */ 1214220935Sadrian 1215220445Sadrian /* XXX EVM? */ 1216178354Ssam} 1217178354Ssam 1218178354Ssamstruct ieee80211_node * 1219178354Ssamieee80211_alloc_node(struct ieee80211_node_table *nt, 1220178354Ssam struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1221178354Ssam{ 1222138568Ssam struct ieee80211com *ic = nt->nt_ic; 1223178354Ssam struct ieee80211_node *ni; 1224116742Ssam int hash; 1225116742Ssam 1226179643Ssam ni = ic->ic_node_alloc(vap, macaddr); 1227178354Ssam if (ni == NULL) { 1228178354Ssam vap->iv_stats.is_rx_nodealloc++; 1229178354Ssam return NULL; 1230178354Ssam } 1231178354Ssam 1232178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1233140766Ssam "%s %p<%s> in %s table\n", __func__, ni, 1234138568Ssam ether_sprintf(macaddr), nt->nt_name); 1235138568Ssam 1236116742Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1237195618Srpaulo hash = IEEE80211_NODE_HASH(ic, macaddr); 1238138568Ssam ieee80211_node_initref(ni); /* mark referenced */ 1239138568Ssam ni->ni_chan = IEEE80211_CHAN_ANYC; 1240138568Ssam ni->ni_authmode = IEEE80211_AUTH_OPEN; 1241138568Ssam ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 1242183251Ssam ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1243178354Ssam ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 1244178354Ssam ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER; 1245139528Ssam ni->ni_inact_reload = nt->nt_inact_init; 1246139528Ssam ni->ni_inact = ni->ni_inact_reload; 1247170530Ssam ni->ni_ath_defkeyix = 0x7fff; 1248184288Ssam ieee80211_psq_init(&ni->ni_psq, "unknown"); 1249195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1250195618Srpaulo if (vap->iv_opmode == IEEE80211_M_MBSS) 1251195618Srpaulo ieee80211_mesh_node_init(vap, ni); 1252195618Srpaulo#endif 1253138568Ssam IEEE80211_NODE_LOCK(nt); 1254138568Ssam TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 1255138568Ssam LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 1256138568Ssam ni->ni_table = nt; 1257178354Ssam ni->ni_vap = vap; 1258138568Ssam ni->ni_ic = ic; 1259138568Ssam IEEE80211_NODE_UNLOCK(nt); 1260116742Ssam 1261184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 1262184277Ssam "%s: inact_reload %u", __func__, ni->ni_inact_reload); 1263184277Ssam 1264116742Ssam return ni; 1265116742Ssam} 1266116742Ssam 1267148777Ssam/* 1268148777Ssam * Craft a temporary node suitable for sending a management frame 1269148777Ssam * to the specified station. We craft only as much state as we 1270148777Ssam * need to do the work since the node will be immediately reclaimed 1271148777Ssam * once the send completes. 1272148777Ssam */ 1273116742Ssamstruct ieee80211_node * 1274178354Ssamieee80211_tmp_node(struct ieee80211vap *vap, 1275178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1276148777Ssam{ 1277178354Ssam struct ieee80211com *ic = vap->iv_ic; 1278148777Ssam struct ieee80211_node *ni; 1279148777Ssam 1280179643Ssam ni = ic->ic_node_alloc(vap, macaddr); 1281148777Ssam if (ni != NULL) { 1282183259Ssam struct ieee80211_node *bss = vap->iv_bss; 1283183259Ssam 1284178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1285148777Ssam "%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr)); 1286148777Ssam 1287178354Ssam ni->ni_table = NULL; /* NB: pedantic */ 1288178354Ssam ni->ni_ic = ic; /* NB: needed to set channel */ 1289178354Ssam ni->ni_vap = vap; 1290178354Ssam 1291148777Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1292183259Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); 1293148777Ssam ieee80211_node_initref(ni); /* mark referenced */ 1294148777Ssam /* NB: required by ieee80211_fix_rate */ 1295183259Ssam ieee80211_node_set_chan(ni, bss->ni_chan); 1296178354Ssam ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, 1297148777Ssam IEEE80211_KEYIX_NONE); 1298183259Ssam ni->ni_txpower = bss->ni_txpower; 1299148777Ssam /* XXX optimize away */ 1300184288Ssam ieee80211_psq_init(&ni->ni_psq, "unknown"); 1301217511Sbschmidt 1302217511Sbschmidt ieee80211_ratectl_node_init(ni); 1303148777Ssam } else { 1304148777Ssam /* XXX msg */ 1305178354Ssam vap->iv_stats.is_rx_nodealloc++; 1306148777Ssam } 1307148777Ssam return ni; 1308148777Ssam} 1309148777Ssam 1310148777Ssamstruct ieee80211_node * 1311178354Ssamieee80211_dup_bss(struct ieee80211vap *vap, 1312178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1313116742Ssam{ 1314178354Ssam struct ieee80211com *ic = vap->iv_ic; 1315138568Ssam struct ieee80211_node *ni; 1316138568Ssam 1317178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr); 1318116742Ssam if (ni != NULL) { 1319183259Ssam struct ieee80211_node *bss = vap->iv_bss; 1320127770Ssam /* 1321178354Ssam * Inherit from iv_bss. 1322127770Ssam */ 1323183259Ssam copy_bss(ni, bss); 1324183259Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); 1325183259Ssam ieee80211_node_set_chan(ni, bss->ni_chan); 1326178354Ssam } 1327116742Ssam return ni; 1328116742Ssam} 1329116742Ssam 1330178354Ssam/* 1331178354Ssam * Create a bss node for a legacy WDS vap. The far end does 1332178354Ssam * not associate so we just create create a new node and 1333178354Ssam * simulate an association. The caller is responsible for 1334178354Ssam * installing the node as the bss node and handling any further 1335178354Ssam * setup work like authorizing the port. 1336178354Ssam */ 1337178354Ssamstruct ieee80211_node * 1338178354Ssamieee80211_node_create_wds(struct ieee80211vap *vap, 1339178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], struct ieee80211_channel *chan) 1340178354Ssam{ 1341178354Ssam struct ieee80211com *ic = vap->iv_ic; 1342178354Ssam struct ieee80211_node *ni; 1343178354Ssam 1344178354Ssam /* XXX check if node already in sta table? */ 1345178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, bssid); 1346178354Ssam if (ni != NULL) { 1347178354Ssam ni->ni_wdsvap = vap; 1348178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bssid); 1349178354Ssam /* 1350178354Ssam * Inherit any manually configured settings. 1351178354Ssam */ 1352183259Ssam copy_bss(ni, vap->iv_bss); 1353178354Ssam ieee80211_node_set_chan(ni, chan); 1354178354Ssam /* NB: propagate ssid so available to WPA supplicant */ 1355178354Ssam ni->ni_esslen = vap->iv_des_ssid[0].len; 1356178354Ssam memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 1357178354Ssam /* NB: no associd for peer */ 1358178354Ssam /* 1359178354Ssam * There are no management frames to use to 1360178354Ssam * discover neighbor capabilities, so blindly 1361178354Ssam * propagate the local configuration. 1362178354Ssam */ 1363178354Ssam if (vap->iv_flags & IEEE80211_F_WME) 1364178354Ssam ni->ni_flags |= IEEE80211_NODE_QOS; 1365190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1366178354Ssam if (vap->iv_flags & IEEE80211_F_FF) 1367178354Ssam ni->ni_flags |= IEEE80211_NODE_FF; 1368190391Ssam#endif 1369178354Ssam if ((ic->ic_htcaps & IEEE80211_HTC_HT) && 1370193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_HT)) { 1371178354Ssam /* 1372178354Ssam * Device is HT-capable and HT is enabled for 1373178354Ssam * the vap; setup HT operation. On return 1374178354Ssam * ni_chan will be adjusted to an HT channel. 1375178354Ssam */ 1376178354Ssam ieee80211_ht_wds_init(ni); 1377178354Ssam } else { 1378178354Ssam struct ieee80211_channel *c = ni->ni_chan; 1379178354Ssam /* 1380178354Ssam * Force a legacy channel to be used. 1381178354Ssam */ 1382178354Ssam c = ieee80211_find_channel(ic, 1383178354Ssam c->ic_freq, c->ic_flags &~ IEEE80211_CHAN_HT); 1384178354Ssam KASSERT(c != NULL, ("no legacy channel, %u/%x", 1385178354Ssam ni->ni_chan->ic_freq, ni->ni_chan->ic_flags)); 1386178354Ssam ni->ni_chan = c; 1387178354Ssam } 1388178354Ssam } 1389178354Ssam return ni; 1390178354Ssam} 1391178354Ssam 1392178354Ssamstruct ieee80211_node * 1393138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1394178354Ssamieee80211_find_node_locked_debug(struct ieee80211_node_table *nt, 1395178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1396138568Ssam#else 1397178354Ssamieee80211_find_node_locked(struct ieee80211_node_table *nt, 1398178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1399138568Ssam#endif 1400116742Ssam{ 1401116742Ssam struct ieee80211_node *ni; 1402116742Ssam int hash; 1403116742Ssam 1404138568Ssam IEEE80211_NODE_LOCK_ASSERT(nt); 1405127772Ssam 1406195618Srpaulo hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr); 1407138568Ssam LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1408116742Ssam if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1409138568Ssam ieee80211_ref_node(ni); /* mark referenced */ 1410138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1411178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1412140766Ssam "%s (%s:%u) %p<%s> refcnt %d\n", __func__, 1413140766Ssam func, line, 1414140766Ssam ni, ether_sprintf(ni->ni_macaddr), 1415140766Ssam ieee80211_node_refcnt(ni)); 1416138568Ssam#endif 1417127772Ssam return ni; 1418116742Ssam } 1419116742Ssam } 1420127772Ssam return NULL; 1421127772Ssam} 1422178354Ssam 1423178354Ssamstruct ieee80211_node * 1424138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1425178354Ssamieee80211_find_node_debug(struct ieee80211_node_table *nt, 1426178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1427178354Ssam#else 1428178354Ssamieee80211_find_node(struct ieee80211_node_table *nt, 1429178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1430138568Ssam#endif 1431178354Ssam{ 1432178354Ssam struct ieee80211_node *ni; 1433127772Ssam 1434178354Ssam IEEE80211_NODE_LOCK(nt); 1435178354Ssam ni = ieee80211_find_node_locked(nt, macaddr); 1436178354Ssam IEEE80211_NODE_UNLOCK(nt); 1437178354Ssam return ni; 1438178354Ssam} 1439178354Ssam 1440127772Ssamstruct ieee80211_node * 1441138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1442178354Ssamieee80211_find_vap_node_locked_debug(struct ieee80211_node_table *nt, 1443178354Ssam const struct ieee80211vap *vap, 1444178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1445138568Ssam#else 1446178354Ssamieee80211_find_vap_node_locked(struct ieee80211_node_table *nt, 1447178354Ssam const struct ieee80211vap *vap, 1448178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1449138568Ssam#endif 1450127772Ssam{ 1451127772Ssam struct ieee80211_node *ni; 1452178354Ssam int hash; 1453127772Ssam 1454178354Ssam IEEE80211_NODE_LOCK_ASSERT(nt); 1455178354Ssam 1456195618Srpaulo hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr); 1457178354Ssam LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1458178354Ssam if (ni->ni_vap == vap && 1459178354Ssam IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1460178354Ssam ieee80211_ref_node(ni); /* mark referenced */ 1461178354Ssam#ifdef IEEE80211_DEBUG_REFCNT 1462178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1463178354Ssam "%s (%s:%u) %p<%s> refcnt %d\n", __func__, 1464178354Ssam func, line, 1465178354Ssam ni, ether_sprintf(ni->ni_macaddr), 1466178354Ssam ieee80211_node_refcnt(ni)); 1467178354Ssam#endif 1468178354Ssam return ni; 1469178354Ssam } 1470178354Ssam } 1471178354Ssam return NULL; 1472178354Ssam} 1473178354Ssam 1474178354Ssamstruct ieee80211_node * 1475178354Ssam#ifdef IEEE80211_DEBUG_REFCNT 1476178354Ssamieee80211_find_vap_node_debug(struct ieee80211_node_table *nt, 1477178354Ssam const struct ieee80211vap *vap, 1478178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1479178354Ssam#else 1480178354Ssamieee80211_find_vap_node(struct ieee80211_node_table *nt, 1481178354Ssam const struct ieee80211vap *vap, 1482178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1483178354Ssam#endif 1484178354Ssam{ 1485178354Ssam struct ieee80211_node *ni; 1486178354Ssam 1487138568Ssam IEEE80211_NODE_LOCK(nt); 1488178354Ssam ni = ieee80211_find_vap_node_locked(nt, vap, macaddr); 1489138568Ssam IEEE80211_NODE_UNLOCK(nt); 1490116742Ssam return ni; 1491116742Ssam} 1492116742Ssam 1493116742Ssam/* 1494138568Ssam * Fake up a node; this handles node discovery in adhoc mode. 1495138568Ssam * Note that for the driver's benefit we we treat this like 1496138568Ssam * an association so the driver has an opportunity to setup 1497138568Ssam * it's private state. 1498138568Ssam */ 1499138568Ssamstruct ieee80211_node * 1500178354Ssamieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, 1501170530Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1502138568Ssam{ 1503138568Ssam struct ieee80211_node *ni; 1504138568Ssam 1505245928Sadrian IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC, 1506153073Ssam "%s: mac<%s>\n", __func__, ether_sprintf(macaddr)); 1507178354Ssam ni = ieee80211_dup_bss(vap, macaddr); 1508138568Ssam if (ni != NULL) { 1509178354Ssam struct ieee80211com *ic = vap->iv_ic; 1510178354Ssam 1511138568Ssam /* XXX no rate negotiation; just dup */ 1512178354Ssam ni->ni_rates = vap->iv_bss->ni_rates; 1513188869Ssam if (ieee80211_iserp_rateset(&ni->ni_rates)) 1514188869Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 1515178354Ssam if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 1516153404Ssam /* 1517170530Ssam * In adhoc demo mode there are no management 1518170530Ssam * frames to use to discover neighbor capabilities, 1519337951Skevans * so blindly propagate the local configuration 1520170530Ssam * so we can do interesting things (e.g. use 1521170530Ssam * WME to disable ACK's). 1522153404Ssam */ 1523178354Ssam if (vap->iv_flags & IEEE80211_F_WME) 1524153404Ssam ni->ni_flags |= IEEE80211_NODE_QOS; 1525190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1526178354Ssam if (vap->iv_flags & IEEE80211_F_FF) 1527170530Ssam ni->ni_flags |= IEEE80211_NODE_FF; 1528190391Ssam#endif 1529153404Ssam } 1530193966Ssam ieee80211_node_setuptxparms(ni); 1531214894Sbschmidt ieee80211_ratectl_node_init(ni); 1532178354Ssam if (ic->ic_newassoc != NULL) 1533178354Ssam ic->ic_newassoc(ni, 1); 1534170530Ssam /* XXX not right for 802.1x/WPA */ 1535170530Ssam ieee80211_node_authorize(ni); 1536138568Ssam } 1537138568Ssam return ni; 1538138568Ssam} 1539138568Ssam 1540148936Ssamvoid 1541153073Ssamieee80211_init_neighbor(struct ieee80211_node *ni, 1542153073Ssam const struct ieee80211_frame *wh, 1543153073Ssam const struct ieee80211_scanparams *sp) 1544153073Ssam{ 1545245928Sadrian int do_ht_setup = 0; 1546245928Sadrian 1547153073Ssam ni->ni_esslen = sp->ssid[1]; 1548153073Ssam memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1549153073Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1550153073Ssam memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1551153073Ssam ni->ni_intval = sp->bintval; 1552153073Ssam ni->ni_capinfo = sp->capinfo; 1553153073Ssam ni->ni_chan = ni->ni_ic->ic_curchan; 1554153073Ssam ni->ni_fhdwell = sp->fhdwell; 1555153073Ssam ni->ni_fhindex = sp->fhindex; 1556153073Ssam ni->ni_erp = sp->erp; 1557153073Ssam ni->ni_timoff = sp->timoff; 1558195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1559195618Srpaulo if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS) 1560195618Srpaulo ieee80211_mesh_init_neighbor(ni, wh, sp); 1561195618Srpaulo#endif 1562178354Ssam if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) { 1563178354Ssam ieee80211_ies_expand(&ni->ni_ies); 1564186659Ssam if (ni->ni_ies.wme_ie != NULL) 1565186659Ssam ni->ni_flags |= IEEE80211_NODE_QOS; 1566186659Ssam else 1567186659Ssam ni->ni_flags &= ~IEEE80211_NODE_QOS; 1568190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1569178354Ssam if (ni->ni_ies.ath_ie != NULL) 1570178354Ssam ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 1571190391Ssam#endif 1572245928Sadrian if (ni->ni_ies.htcap_ie != NULL) 1573245928Sadrian ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie); 1574245928Sadrian if (ni->ni_ies.htinfo_ie != NULL) 1575245928Sadrian ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie); 1576245928Sadrian 1577245928Sadrian if ((ni->ni_ies.htcap_ie != NULL) && 1578245928Sadrian (ni->ni_ies.htinfo_ie != NULL) && 1579245928Sadrian (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) { 1580245928Sadrian do_ht_setup = 1; 1581245928Sadrian } 1582178354Ssam } 1583178354Ssam 1584153073Ssam /* NB: must be after ni_chan is setup */ 1585165887Ssam ieee80211_setup_rates(ni, sp->rates, sp->xrates, 1586165887Ssam IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | 1587165887Ssam IEEE80211_F_DONEGO | IEEE80211_F_DODEL); 1588245928Sadrian 1589245928Sadrian /* 1590245928Sadrian * If the neighbor is HT compatible, flip that on. 1591245928Sadrian */ 1592245928Sadrian if (do_ht_setup) { 1593245928Sadrian IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 1594245928Sadrian "%s: doing HT setup\n", __func__); 1595245928Sadrian ieee80211_ht_node_init(ni); 1596245928Sadrian ieee80211_ht_updateparams(ni, 1597245928Sadrian ni->ni_ies.htcap_ie, 1598245928Sadrian ni->ni_ies.htinfo_ie); 1599245928Sadrian ieee80211_setup_htrates(ni, 1600245928Sadrian ni->ni_ies.htcap_ie, 1601245928Sadrian IEEE80211_F_JOIN | IEEE80211_F_DOBRS); 1602245928Sadrian ieee80211_setup_basic_htrates(ni, 1603245928Sadrian ni->ni_ies.htinfo_ie); 1604245928Sadrian ieee80211_node_setuptxparms(ni); 1605245928Sadrian ieee80211_ratectl_node_init(ni); 1606245928Sadrian } 1607153073Ssam} 1608153073Ssam 1609148936Ssam/* 1610148936Ssam * Do node discovery in adhoc mode on receipt of a beacon 1611148936Ssam * or probe response frame. Note that for the driver's 1612148936Ssam * benefit we we treat this like an association so the 1613148936Ssam * driver has an opportunity to setup it's private state. 1614148936Ssam */ 1615148936Ssamstruct ieee80211_node * 1616178354Ssamieee80211_add_neighbor(struct ieee80211vap *vap, 1617148936Ssam const struct ieee80211_frame *wh, 1618148936Ssam const struct ieee80211_scanparams *sp) 1619148936Ssam{ 1620148936Ssam struct ieee80211_node *ni; 1621148936Ssam 1622245928Sadrian IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 1623153073Ssam "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2)); 1624178354Ssam ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */ 1625148936Ssam if (ni != NULL) { 1626178354Ssam struct ieee80211com *ic = vap->iv_ic; 1627178354Ssam 1628153073Ssam ieee80211_init_neighbor(ni, wh, sp); 1629188869Ssam if (ieee80211_iserp_rateset(&ni->ni_rates)) 1630188869Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 1631193966Ssam ieee80211_node_setuptxparms(ni); 1632214894Sbschmidt ieee80211_ratectl_node_init(ni); 1633148936Ssam if (ic->ic_newassoc != NULL) 1634148936Ssam ic->ic_newassoc(ni, 1); 1635148936Ssam /* XXX not right for 802.1x/WPA */ 1636148936Ssam ieee80211_node_authorize(ni); 1637148936Ssam } 1638148936Ssam return ni; 1639148936Ssam} 1640148936Ssam 1641179220Ssam#define IS_PROBEREQ(wh) \ 1642179220Ssam ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) \ 1643179220Ssam == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ)) 1644179220Ssam#define IS_BCAST_PROBEREQ(wh) \ 1645179220Ssam (IS_PROBEREQ(wh) && IEEE80211_IS_MULTICAST( \ 1646179220Ssam ((const struct ieee80211_frame *)(wh))->i_addr3)) 1647170530Ssam 1648179220Ssamstatic __inline struct ieee80211_node * 1649179220Ssam_find_rxnode(struct ieee80211_node_table *nt, 1650179220Ssam const struct ieee80211_frame_min *wh) 1651179220Ssam{ 1652179220Ssam if (IS_BCAST_PROBEREQ(wh)) 1653179220Ssam return NULL; /* spam bcast probe req to all vap's */ 1654179220Ssam return ieee80211_find_node_locked(nt, wh->i_addr2); 1655179220Ssam} 1656179220Ssam 1657138568Ssam/* 1658138568Ssam * Locate the node for sender, track state, and then pass the 1659179220Ssam * (referenced) node up to the 802.11 layer for its use. Note 1660179220Ssam * we can return NULL if the sender is not in the table. 1661138568Ssam */ 1662138568Ssamstruct ieee80211_node * 1663138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1664138568Ssamieee80211_find_rxnode_debug(struct ieee80211com *ic, 1665138568Ssam const struct ieee80211_frame_min *wh, const char *func, int line) 1666138568Ssam#else 1667138568Ssamieee80211_find_rxnode(struct ieee80211com *ic, 1668138568Ssam const struct ieee80211_frame_min *wh) 1669138568Ssam#endif 1670138568Ssam{ 1671138568Ssam struct ieee80211_node_table *nt; 1672138568Ssam struct ieee80211_node *ni; 1673138568Ssam 1674170530Ssam nt = &ic->ic_sta; 1675138568Ssam IEEE80211_NODE_LOCK(nt); 1676179220Ssam ni = _find_rxnode(nt, wh); 1677138568Ssam IEEE80211_NODE_UNLOCK(nt); 1678138568Ssam 1679148863Ssam return ni; 1680148863Ssam} 1681148863Ssam 1682148863Ssam/* 1683148863Ssam * Like ieee80211_find_rxnode but use the supplied h/w 1684148863Ssam * key index as a hint to locate the node in the key 1685148863Ssam * mapping table. If an entry is present at the key 1686148863Ssam * index we return it; otherwise do a normal lookup and 1687148863Ssam * update the mapping table if the station has a unicast 1688148863Ssam * key assigned to it. 1689148863Ssam */ 1690148863Ssamstruct ieee80211_node * 1691148863Ssam#ifdef IEEE80211_DEBUG_REFCNT 1692148863Ssamieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1693148863Ssam const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1694148863Ssam const char *func, int line) 1695148863Ssam#else 1696148863Ssamieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1697148863Ssam const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1698148863Ssam#endif 1699148863Ssam{ 1700148863Ssam struct ieee80211_node_table *nt; 1701148863Ssam struct ieee80211_node *ni; 1702148863Ssam 1703170530Ssam nt = &ic->ic_sta; 1704148863Ssam IEEE80211_NODE_LOCK(nt); 1705148863Ssam if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1706148863Ssam ni = nt->nt_keyixmap[keyix]; 1707148863Ssam else 1708148863Ssam ni = NULL; 1709148863Ssam if (ni == NULL) { 1710179220Ssam ni = _find_rxnode(nt, wh); 1711178354Ssam if (ni != NULL && nt->nt_keyixmap != NULL) { 1712148863Ssam /* 1713148863Ssam * If the station has a unicast key cache slot 1714148863Ssam * assigned update the key->node mapping table. 1715148863Ssam */ 1716148863Ssam keyix = ni->ni_ucastkey.wk_rxkeyix; 1717148863Ssam /* XXX can keyixmap[keyix] != NULL? */ 1718148863Ssam if (keyix < nt->nt_keyixmax && 1719148863Ssam nt->nt_keyixmap[keyix] == NULL) { 1720178354Ssam IEEE80211_DPRINTF(ni->ni_vap, 1721178354Ssam IEEE80211_MSG_NODE, 1722148863Ssam "%s: add key map entry %p<%s> refcnt %d\n", 1723148863Ssam __func__, ni, ether_sprintf(ni->ni_macaddr), 1724148863Ssam ieee80211_node_refcnt(ni)+1); 1725148863Ssam nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1726148863Ssam } 1727148863Ssam } 1728179220Ssam } else { 1729179220Ssam if (IS_BCAST_PROBEREQ(wh)) 1730179220Ssam ni = NULL; /* spam bcast probe req to all vap's */ 1731179220Ssam else 1732179220Ssam ieee80211_ref_node(ni); 1733179220Ssam } 1734148863Ssam IEEE80211_NODE_UNLOCK(nt); 1735148863Ssam 1736148863Ssam return ni; 1737148863Ssam} 1738179220Ssam#undef IS_BCAST_PROBEREQ 1739179220Ssam#undef IS_PROBEREQ 1740138568Ssam 1741138568Ssam/* 1742127772Ssam * Return a reference to the appropriate node for sending 1743127772Ssam * a data frame. This handles node discovery in adhoc networks. 1744127772Ssam */ 1745127772Ssamstruct ieee80211_node * 1746138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1747178354Ssamieee80211_find_txnode_debug(struct ieee80211vap *vap, 1748178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], 1749138568Ssam const char *func, int line) 1750138568Ssam#else 1751178354Ssamieee80211_find_txnode(struct ieee80211vap *vap, 1752178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1753138568Ssam#endif 1754127772Ssam{ 1755178354Ssam struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta; 1756127772Ssam struct ieee80211_node *ni; 1757127772Ssam 1758127772Ssam /* 1759127772Ssam * The destination address should be in the node table 1760148863Ssam * unless this is a multicast/broadcast frame. We can 1761148863Ssam * also optimize station mode operation, all frames go 1762148863Ssam * to the bss node. 1763127772Ssam */ 1764127772Ssam /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ 1765138568Ssam IEEE80211_NODE_LOCK(nt); 1766178354Ssam if (vap->iv_opmode == IEEE80211_M_STA || 1767178354Ssam vap->iv_opmode == IEEE80211_M_WDS || 1768178354Ssam IEEE80211_IS_MULTICAST(macaddr)) 1769178354Ssam ni = ieee80211_ref_node(vap->iv_bss); 1770186099Ssam else 1771178354Ssam ni = ieee80211_find_node_locked(nt, macaddr); 1772138568Ssam IEEE80211_NODE_UNLOCK(nt); 1773138568Ssam 1774138568Ssam if (ni == NULL) { 1775178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS || 1776178354Ssam vap->iv_opmode == IEEE80211_M_AHDEMO) { 1777140497Ssam /* 1778140497Ssam * In adhoc mode cons up a node for the destination. 1779140497Ssam * Note that we need an additional reference for the 1780178354Ssam * caller to be consistent with 1781178354Ssam * ieee80211_find_node_locked. 1782140497Ssam */ 1783178354Ssam ni = ieee80211_fakeup_adhoc_node(vap, macaddr); 1784140497Ssam if (ni != NULL) 1785140497Ssam (void) ieee80211_ref_node(ni); 1786140497Ssam } else { 1787178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, macaddr, 1788178354Ssam "no node, discard frame (%s)", __func__); 1789178354Ssam vap->iv_stats.is_tx_nonode++; 1790127772Ssam } 1791127772Ssam } 1792127772Ssam return ni; 1793127772Ssam} 1794127772Ssam 1795116742Ssamstatic void 1796138568Ssam_ieee80211_free_node(struct ieee80211_node *ni) 1797116742Ssam{ 1798138568Ssam struct ieee80211_node_table *nt = ni->ni_table; 1799119150Ssam 1800179641Ssam /* 1801179641Ssam * NB: careful about referencing the vap as it may be 1802179641Ssam * gone if the last reference was held by a driver. 1803179641Ssam * We know the com will always be present so it's safe 1804179641Ssam * to use ni_ic below to reclaim resources. 1805179641Ssam */ 1806179641Ssam#if 0 1807178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1808140766Ssam "%s %p<%s> in %s table\n", __func__, ni, 1809140766Ssam ether_sprintf(ni->ni_macaddr), 1810138568Ssam nt != NULL ? nt->nt_name : "<gone>"); 1811179641Ssam#endif 1812179641Ssam if (ni->ni_associd != 0) { 1813179641Ssam struct ieee80211vap *vap = ni->ni_vap; 1814179641Ssam if (vap->iv_aid_bitmap != NULL) 1815179641Ssam IEEE80211_AID_CLR(vap, ni->ni_associd); 1816179641Ssam } 1817138568Ssam if (nt != NULL) { 1818138568Ssam TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1819138568Ssam LIST_REMOVE(ni, ni_hash); 1820138568Ssam } 1821179641Ssam ni->ni_ic->ic_node_free(ni); 1822116742Ssam} 1823116742Ssam 1824282404Sadrian/* 1825282404Sadrian * Clear any entry in the unicast key mapping table. 1826282404Sadrian */ 1827282404Sadrianstatic int 1828282404Sadriannode_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1829282404Sadrian{ 1830282404Sadrian ieee80211_keyix keyix; 1831282404Sadrian 1832282404Sadrian keyix = ni->ni_ucastkey.wk_rxkeyix; 1833282404Sadrian if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1834282404Sadrian nt->nt_keyixmap[keyix] == ni) { 1835282404Sadrian IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1836282404Sadrian "%s: %p<%s> clear key map entry %u\n", 1837282404Sadrian __func__, ni, ether_sprintf(ni->ni_macaddr), keyix); 1838282404Sadrian nt->nt_keyixmap[keyix] = NULL; 1839282404Sadrian ieee80211_node_decref(ni); 1840282404Sadrian return 1; 1841282404Sadrian } 1842282404Sadrian 1843282404Sadrian return 0; 1844282404Sadrian} 1845282404Sadrian 1846116742Ssamvoid 1847138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1848138568Ssamieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1849138568Ssam#else 1850138568Ssamieee80211_free_node(struct ieee80211_node *ni) 1851138568Ssam#endif 1852116742Ssam{ 1853138568Ssam struct ieee80211_node_table *nt = ni->ni_table; 1854119150Ssam 1855138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1856178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1857140766Ssam "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni, 1858138568Ssam ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1); 1859138568Ssam#endif 1860148863Ssam if (nt != NULL) { 1861148863Ssam IEEE80211_NODE_LOCK(nt); 1862148863Ssam if (ieee80211_node_dectestref(ni)) { 1863148863Ssam /* 1864148863Ssam * Last reference, reclaim state. 1865148863Ssam */ 1866138568Ssam _ieee80211_free_node(ni); 1867282404Sadrian } else if (ieee80211_node_refcnt(ni) == 1) 1868282404Sadrian if (node_clear_keyixmap(nt, ni)) 1869148863Ssam _ieee80211_free_node(ni); 1870148863Ssam IEEE80211_NODE_UNLOCK(nt); 1871148863Ssam } else { 1872148863Ssam if (ieee80211_node_dectestref(ni)) 1873138568Ssam _ieee80211_free_node(ni); 1874116742Ssam } 1875116742Ssam} 1876116742Ssam 1877138568Ssam/* 1878148863Ssam * Reclaim a unicast key and clear any key cache state. 1879148863Ssam */ 1880148863Ssamint 1881148863Ssamieee80211_node_delucastkey(struct ieee80211_node *ni) 1882148863Ssam{ 1883179641Ssam struct ieee80211com *ic = ni->ni_ic; 1884179641Ssam struct ieee80211_node_table *nt = &ic->ic_sta; 1885148863Ssam struct ieee80211_node *nikey; 1886148863Ssam ieee80211_keyix keyix; 1887148863Ssam int isowned, status; 1888148863Ssam 1889148863Ssam /* 1890148863Ssam * NB: We must beware of LOR here; deleting the key 1891148863Ssam * can cause the crypto layer to block traffic updates 1892148863Ssam * which can generate a LOR against the node table lock; 1893148863Ssam * grab it here and stash the key index for our use below. 1894148863Ssam * 1895148863Ssam * Must also beware of recursion on the node table lock. 1896148863Ssam * When called from node_cleanup we may already have 1897148863Ssam * the node table lock held. Unfortunately there's no 1898148863Ssam * way to separate out this path so we must do this 1899148863Ssam * conditionally. 1900148863Ssam */ 1901148863Ssam isowned = IEEE80211_NODE_IS_LOCKED(nt); 1902148863Ssam if (!isowned) 1903148863Ssam IEEE80211_NODE_LOCK(nt); 1904179641Ssam nikey = NULL; 1905179641Ssam status = 1; /* NB: success */ 1906186144Ssam if (ni->ni_ucastkey.wk_keyix != IEEE80211_KEYIX_NONE) { 1907179641Ssam keyix = ni->ni_ucastkey.wk_rxkeyix; 1908179641Ssam status = ieee80211_crypto_delkey(ni->ni_vap, &ni->ni_ucastkey); 1909179641Ssam if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1910179641Ssam nikey = nt->nt_keyixmap[keyix]; 1911201758Smbr nt->nt_keyixmap[keyix] = NULL; 1912179641Ssam } 1913179641Ssam } 1914148863Ssam if (!isowned) 1915178354Ssam IEEE80211_NODE_UNLOCK(nt); 1916148863Ssam 1917148863Ssam if (nikey != NULL) { 1918148863Ssam KASSERT(nikey == ni, 1919148863Ssam ("key map out of sync, ni %p nikey %p", ni, nikey)); 1920179641Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1921148863Ssam "%s: delete key map entry %p<%s> refcnt %d\n", 1922148863Ssam __func__, ni, ether_sprintf(ni->ni_macaddr), 1923148863Ssam ieee80211_node_refcnt(ni)-1); 1924148863Ssam ieee80211_free_node(ni); 1925148863Ssam } 1926148863Ssam return status; 1927148863Ssam} 1928148863Ssam 1929148863Ssam/* 1930138568Ssam * Reclaim a node. If this is the last reference count then 1931138568Ssam * do the normal free work. Otherwise remove it from the node 1932138568Ssam * table and mark it gone by clearing the back-reference. 1933138568Ssam */ 1934138568Ssamstatic void 1935138568Ssamnode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1936116742Ssam{ 1937138568Ssam 1938148863Ssam IEEE80211_NODE_LOCK_ASSERT(nt); 1939148863Ssam 1940178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1941140766Ssam "%s: remove %p<%s> from %s table, refcnt %d\n", 1942140766Ssam __func__, ni, ether_sprintf(ni->ni_macaddr), 1943140766Ssam nt->nt_name, ieee80211_node_refcnt(ni)-1); 1944148863Ssam /* 1945148863Ssam * Clear any entry in the unicast key mapping table. 1946148863Ssam * We need to do it here so rx lookups don't find it 1947148863Ssam * in the mapping table even if it's not in the hash 1948148863Ssam * table. We cannot depend on the mapping table entry 1949148863Ssam * being cleared because the node may not be free'd. 1950148863Ssam */ 1951282404Sadrian (void)node_clear_keyixmap(nt, ni); 1952138568Ssam if (!ieee80211_node_dectestref(ni)) { 1953138568Ssam /* 1954138568Ssam * Other references are present, just remove the 1955138568Ssam * node from the table so it cannot be found. When 1956138568Ssam * the references are dropped storage will be 1957140753Ssam * reclaimed. 1958138568Ssam */ 1959138568Ssam TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1960138568Ssam LIST_REMOVE(ni, ni_hash); 1961138568Ssam ni->ni_table = NULL; /* clear reference */ 1962138568Ssam } else 1963138568Ssam _ieee80211_free_node(ni); 1964138568Ssam} 1965138568Ssam 1966178354Ssam/* 1967178354Ssam * Node table support. 1968178354Ssam */ 1969178354Ssam 1970178354Ssamstatic void 1971178354Ssamieee80211_node_table_init(struct ieee80211com *ic, 1972178354Ssam struct ieee80211_node_table *nt, 1973178354Ssam const char *name, int inact, int keyixmax) 1974178354Ssam{ 1975178354Ssam 1976178354Ssam nt->nt_ic = ic; 1977283529Sglebius IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name); 1978178354Ssam TAILQ_INIT(&nt->nt_node); 1979178354Ssam nt->nt_name = name; 1980178354Ssam nt->nt_inact_init = inact; 1981178354Ssam nt->nt_keyixmax = keyixmax; 1982178354Ssam if (nt->nt_keyixmax > 0) { 1983283538Sadrian nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC( 1984184210Sdes keyixmax * sizeof(struct ieee80211_node *), 1985283538Sadrian M_80211_NODE, 1986283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 1987178354Ssam if (nt->nt_keyixmap == NULL) 1988283529Sglebius ic_printf(ic, 1989178354Ssam "Cannot allocate key index map with %u entries\n", 1990178354Ssam keyixmax); 1991178354Ssam } else 1992178354Ssam nt->nt_keyixmap = NULL; 1993178354Ssam} 1994178354Ssam 1995178354Ssamstatic void 1996178354Ssamieee80211_node_table_reset(struct ieee80211_node_table *nt, 1997178354Ssam struct ieee80211vap *match) 1998178354Ssam{ 1999178354Ssam struct ieee80211_node *ni, *next; 2000178354Ssam 2001178354Ssam IEEE80211_NODE_LOCK(nt); 2002178354Ssam TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) { 2003178354Ssam if (match != NULL && ni->ni_vap != match) 2004178354Ssam continue; 2005178354Ssam /* XXX can this happen? if so need's work */ 2006138568Ssam if (ni->ni_associd != 0) { 2007178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2008178354Ssam 2009178354Ssam if (vap->iv_auth->ia_node_leave != NULL) 2010178354Ssam vap->iv_auth->ia_node_leave(ni); 2011178354Ssam if (vap->iv_aid_bitmap != NULL) 2012178354Ssam IEEE80211_AID_CLR(vap, ni->ni_associd); 2013138568Ssam } 2014178354Ssam ni->ni_wdsvap = NULL; /* clear reference */ 2015138568Ssam node_reclaim(nt, ni); 2016138568Ssam } 2017178354Ssam if (match != NULL && match->iv_opmode == IEEE80211_M_WDS) { 2018178354Ssam /* 2019178354Ssam * Make a separate pass to clear references to this vap 2020178354Ssam * held by DWDS entries. They will not be matched above 2021178354Ssam * because ni_vap will point to the ap vap but we still 2022178354Ssam * need to clear ni_wdsvap when the WDS vap is destroyed 2023178354Ssam * and/or reset. 2024178354Ssam */ 2025178354Ssam TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) 2026178354Ssam if (ni->ni_wdsvap == match) 2027178354Ssam ni->ni_wdsvap = NULL; 2028178354Ssam } 2029178354Ssam IEEE80211_NODE_UNLOCK(nt); 2030116742Ssam} 2031116742Ssam 2032178354Ssamstatic void 2033178354Ssamieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 2034178354Ssam{ 2035178354Ssam ieee80211_node_table_reset(nt, NULL); 2036178354Ssam if (nt->nt_keyixmap != NULL) { 2037178354Ssam#ifdef DIAGNOSTIC 2038178354Ssam /* XXX verify all entries are NULL */ 2039178354Ssam int i; 2040178354Ssam for (i = 0; i < nt->nt_keyixmax; i++) 2041178354Ssam if (nt->nt_keyixmap[i] != NULL) 2042178354Ssam printf("%s: %s[%u] still active\n", __func__, 2043178354Ssam nt->nt_name, i); 2044178354Ssam#endif 2045283538Sadrian IEEE80211_FREE(nt->nt_keyixmap, M_80211_NODE); 2046178354Ssam nt->nt_keyixmap = NULL; 2047178354Ssam } 2048178354Ssam IEEE80211_NODE_LOCK_DESTROY(nt); 2049178354Ssam} 2050178354Ssam 2051138568Ssamstatic void 2052302018Sadriantimeout_stations(void *arg __unused, struct ieee80211_node *ni) 2053116742Ssam{ 2054302018Sadrian struct ieee80211com *ic = ni->ni_ic; 2055302018Sadrian struct ieee80211vap *vap = ni->ni_vap; 2056116742Ssam 2057302018Sadrian /* 2058302018Sadrian * Only process stations when in RUN state. This 2059302018Sadrian * insures, for example, that we don't timeout an 2060302018Sadrian * inactive station during CAC. Note that CSA state 2061302018Sadrian * is actually handled in ieee80211_node_timeout as 2062302018Sadrian * it applies to more than timeout processing. 2063302018Sadrian */ 2064302018Sadrian if (vap->iv_state != IEEE80211_S_RUN) 2065302018Sadrian return; 2066302018Sadrian /* 2067302018Sadrian * Ignore entries for which have yet to receive an 2068302018Sadrian * authentication frame. These are transient and 2069302018Sadrian * will be reclaimed when the last reference to them 2070302018Sadrian * goes away (when frame xmits complete). 2071302018Sadrian */ 2072302018Sadrian if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 2073302018Sadrian vap->iv_opmode == IEEE80211_M_STA) && 2074302018Sadrian (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 2075302018Sadrian return; 2076302018Sadrian /* 2077302018Sadrian * Free fragment if not needed anymore 2078302018Sadrian * (last fragment older than 1s). 2079302018Sadrian * XXX doesn't belong here, move to node_age 2080302018Sadrian */ 2081302018Sadrian if (ni->ni_rxfrag[0] != NULL && 2082302018Sadrian ticks > ni->ni_rxfragstamp + hz) { 2083302018Sadrian m_freem(ni->ni_rxfrag[0]); 2084302018Sadrian ni->ni_rxfrag[0] = NULL; 2085302018Sadrian } 2086302018Sadrian if (ni->ni_inact > 0) { 2087302018Sadrian ni->ni_inact--; 2088302018Sadrian IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 2089302018Sadrian "%s: inact %u inact_reload %u nrates %u", 2090302018Sadrian __func__, ni->ni_inact, ni->ni_inact_reload, 2091302018Sadrian ni->ni_rates.rs_nrates); 2092302018Sadrian } 2093302018Sadrian /* 2094302018Sadrian * Special case ourself; we may be idle for extended periods 2095302018Sadrian * of time and regardless reclaiming our state is wrong. 2096302018Sadrian * XXX run ic_node_age 2097302018Sadrian */ 2098302018Sadrian /* XXX before inact decrement? */ 2099302018Sadrian if (ni == vap->iv_bss) 2100302018Sadrian return; 2101337951Skevans if (ni->ni_associd != 0 || 2102302018Sadrian (vap->iv_opmode == IEEE80211_M_IBSS || 2103302018Sadrian vap->iv_opmode == IEEE80211_M_AHDEMO)) { 2104138568Ssam /* 2105302018Sadrian * Age/drain resources held by the station. 2106147788Ssam */ 2107302018Sadrian ic->ic_node_age(ni); 2108178354Ssam /* 2109302018Sadrian * Probe the station before time it out. We 2110302018Sadrian * send a null data frame which may not be 2111302018Sadrian * universally supported by drivers (need it 2112302018Sadrian * for ps-poll support so it should be...). 2113302018Sadrian * 2114302018Sadrian * XXX don't probe the station unless we've 2115302018Sadrian * received a frame from them (and have 2116302018Sadrian * some idea of the rates they are capable 2117302018Sadrian * of); this will get fixed more properly 2118302018Sadrian * soon with better handling of the rate set. 2119178354Ssam */ 2120178354Ssam if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 2121302018Sadrian (0 < ni->ni_inact && 2122302018Sadrian ni->ni_inact <= vap->iv_inact_probe) && 2123302018Sadrian ni->ni_rates.rs_nrates != 0) { 2124178354Ssam IEEE80211_NOTE(vap, 2125302018Sadrian IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 2126302018Sadrian ni, "%s", 2127302018Sadrian "probe station due to inactivity"); 2128138568Ssam /* 2129302018Sadrian * Grab a reference so the node cannot 2130302018Sadrian * be reclaimed before we send the frame. 2131302018Sadrian * ieee80211_send_nulldata understands 2132302018Sadrian * we've done this and reclaims the 2133302018Sadrian * ref for us as needed. 2134119150Ssam */ 2135302018Sadrian /* XXX fix this (not required anymore). */ 2136172229Ssam ieee80211_ref_node(ni); 2137302018Sadrian /* XXX useless */ 2138302018Sadrian ieee80211_send_nulldata(ni); 2139302018Sadrian /* XXX stat? */ 2140302018Sadrian return; 2141120483Ssam } 2142116742Ssam } 2143302018Sadrian if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 2144302018Sadrian ni->ni_inact <= 0) { 2145302018Sadrian IEEE80211_NOTE(vap, 2146302018Sadrian IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 2147302018Sadrian "station timed out due to inactivity " 2148302018Sadrian "(refcnt %u)", ieee80211_node_refcnt(ni)); 2149302018Sadrian /* 2150302018Sadrian * Send a deauthenticate frame and drop the station. 2151302018Sadrian * This is somewhat complicated due to reference counts 2152302018Sadrian * and locking. At this point a station will typically 2153302018Sadrian * have a reference count of 2. ieee80211_node_leave 2154302018Sadrian * will do a "free" of the node which will drop the 2155302018Sadrian * reference count. But in the meantime a reference 2156302018Sadrian * wil be held by the deauth frame. The actual reclaim 2157302018Sadrian * of the node will happen either after the tx is 2158302018Sadrian * completed or by ieee80211_node_leave. 2159302018Sadrian */ 2160302018Sadrian if (ni->ni_associd != 0) { 2161302018Sadrian IEEE80211_SEND_MGMT(ni, 2162302018Sadrian IEEE80211_FC0_SUBTYPE_DEAUTH, 2163302018Sadrian IEEE80211_REASON_AUTH_EXPIRE); 2164302018Sadrian } 2165302018Sadrian ieee80211_node_leave(ni); 2166302018Sadrian vap->iv_stats.is_node_timeout++; 2167302018Sadrian } 2168302018Sadrian} 2169138568Ssam 2170302018Sadrian/* 2171302018Sadrian * Timeout inactive stations and do related housekeeping. 2172302018Sadrian */ 2173302018Sadrianstatic void 2174302018Sadrianieee80211_timeout_stations(struct ieee80211com *ic) 2175302018Sadrian{ 2176302018Sadrian struct ieee80211_node_table *nt = &ic->ic_sta; 2177302018Sadrian 2178302018Sadrian ieee80211_iterate_nodes(nt, timeout_stations, NULL); 2179170530Ssam} 2180138568Ssam 2181178354Ssam/* 2182178354Ssam * Aggressively reclaim resources. This should be used 2183178354Ssam * only in a critical situation to reclaim mbuf resources. 2184178354Ssam */ 2185170530Ssamvoid 2186178354Ssamieee80211_drain(struct ieee80211com *ic) 2187178354Ssam{ 2188178354Ssam struct ieee80211_node_table *nt = &ic->ic_sta; 2189178354Ssam struct ieee80211vap *vap; 2190178354Ssam struct ieee80211_node *ni; 2191178354Ssam 2192178354Ssam IEEE80211_NODE_LOCK(nt); 2193178354Ssam TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2194178354Ssam /* 2195178354Ssam * Ignore entries for which have yet to receive an 2196178354Ssam * authentication frame. These are transient and 2197178354Ssam * will be reclaimed when the last reference to them 2198178354Ssam * goes away (when frame xmits complete). 2199178354Ssam */ 2200178354Ssam vap = ni->ni_vap; 2201178354Ssam /* 2202178354Ssam * Only process stations when in RUN state. This 2203178354Ssam * insures, for example, that we don't timeout an 2204178354Ssam * inactive station during CAC. Note that CSA state 2205178354Ssam * is actually handled in ieee80211_node_timeout as 2206178354Ssam * it applies to more than timeout processing. 2207178354Ssam */ 2208178354Ssam if (vap->iv_state != IEEE80211_S_RUN) 2209178354Ssam continue; 2210178354Ssam /* XXX can vap be NULL? */ 2211178354Ssam if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 2212178354Ssam vap->iv_opmode == IEEE80211_M_STA) && 2213178354Ssam (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 2214178354Ssam continue; 2215178354Ssam /* 2216178354Ssam * Free fragments. 2217178354Ssam * XXX doesn't belong here, move to node_drain 2218178354Ssam */ 2219178354Ssam if (ni->ni_rxfrag[0] != NULL) { 2220178354Ssam m_freem(ni->ni_rxfrag[0]); 2221178354Ssam ni->ni_rxfrag[0] = NULL; 2222178354Ssam } 2223178354Ssam /* 2224178354Ssam * Drain resources held by the station. 2225178354Ssam */ 2226178354Ssam ic->ic_node_drain(ni); 2227178354Ssam } 2228178354Ssam IEEE80211_NODE_UNLOCK(nt); 2229178354Ssam} 2230178354Ssam 2231178354Ssam/* 2232178354Ssam * Per-ieee80211com inactivity timer callback. 2233178354Ssam */ 2234178354Ssamvoid 2235170530Ssamieee80211_node_timeout(void *arg) 2236170530Ssam{ 2237170530Ssam struct ieee80211com *ic = arg; 2238170530Ssam 2239178354Ssam /* 2240178354Ssam * Defer timeout processing if a channel switch is pending. 2241178354Ssam * We typically need to be mute so not doing things that 2242178354Ssam * might generate frames is good to handle in one place. 2243298995Spfg * Suppressing the station timeout processing may extend the 2244178354Ssam * lifetime of inactive stations (by not decrementing their 2245178354Ssam * idle counters) but this should be ok unless the CSA is 2246178354Ssam * active for an unusually long time. 2247178354Ssam */ 2248178354Ssam if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) { 2249178354Ssam ieee80211_scan_timeout(ic); 2250178354Ssam ieee80211_timeout_stations(ic); 2251195379Ssam ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT); 2252170530Ssam 2253178354Ssam IEEE80211_LOCK(ic); 2254178354Ssam ieee80211_erp_timeout(ic); 2255178354Ssam ieee80211_ht_timeout(ic); 2256178354Ssam IEEE80211_UNLOCK(ic); 2257178354Ssam } 2258170530Ssam callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 2259170530Ssam ieee80211_node_timeout, ic); 2260116742Ssam} 2261116742Ssam 2262239312Sadrian/* 2263239312Sadrian * Iterate over the node table and return an array of ref'ed nodes. 2264239312Sadrian * 2265239312Sadrian * This is separated out from calling the actual node function so that 2266239312Sadrian * no LORs will occur. 2267239312Sadrian * 2268239312Sadrian * If there are too many nodes (ie, the number of nodes doesn't fit 2269239312Sadrian * within 'max_aid' entries) then the node references will be freed 2270239312Sadrian * and an error will be returned. 2271239312Sadrian * 2272239312Sadrian * The responsibility of allocating and freeing "ni_arr" is up to 2273239312Sadrian * the caller. 2274239312Sadrian */ 2275239312Sadrianint 2276239312Sadrianieee80211_iterate_nt(struct ieee80211_node_table *nt, 2277239312Sadrian struct ieee80211_node **ni_arr, uint16_t max_aid) 2278116742Ssam{ 2279239312Sadrian int i, j, ret; 2280116742Ssam struct ieee80211_node *ni; 2281116742Ssam 2282239312Sadrian IEEE80211_NODE_LOCK(nt); 2283239312Sadrian 2284239312Sadrian i = ret = 0; 2285138568Ssam TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2286239312Sadrian if (i >= max_aid) { 2287239312Sadrian ret = E2BIG; 2288283529Sglebius ic_printf(nt->nt_ic, "Node array overflow: max=%u", 2289283529Sglebius max_aid); 2290239312Sadrian break; 2291138568Ssam } 2292239312Sadrian ni_arr[i] = ieee80211_ref_node(ni); 2293239312Sadrian i++; 2294138568Ssam } 2295239312Sadrian 2296239312Sadrian /* 2297239312Sadrian * It's safe to unlock here. 2298239312Sadrian * 2299239312Sadrian * If we're successful, the list is returned. 2300239312Sadrian * If we're unsuccessful, the list is ignored 2301239312Sadrian * and we remove our references. 2302239312Sadrian * 2303239312Sadrian * This avoids any potential LOR with 2304239312Sadrian * ieee80211_free_node(). 2305239312Sadrian */ 2306138568Ssam IEEE80211_NODE_UNLOCK(nt); 2307138568Ssam 2308239312Sadrian /* 2309239312Sadrian * If ret is non-zero, we hit some kind of error. 2310239312Sadrian * Rather than walking some nodes, we'll walk none 2311239312Sadrian * of them. 2312239312Sadrian */ 2313239312Sadrian if (ret) { 2314239312Sadrian for (j = 0; j < i; j++) { 2315239312Sadrian /* ieee80211_free_node() locks by itself */ 2316239312Sadrian ieee80211_free_node(ni_arr[j]); 2317239312Sadrian } 2318239312Sadrian } 2319239312Sadrian 2320239312Sadrian return (ret); 2321116742Ssam} 2322138568Ssam 2323239312Sadrian/* 2324239312Sadrian * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes() 2325239312Sadrian * reference in the source. 2326239312Sadrian * 2327239312Sadrian * Note that this fetches 'max_aid' from the first VAP, rather than finding 2328239312Sadrian * the largest max_aid from all VAPs. 2329239312Sadrian */ 2330138568Ssamvoid 2331239312Sadrianieee80211_iterate_nodes(struct ieee80211_node_table *nt, 2332239312Sadrian ieee80211_iter_func *f, void *arg) 2333239312Sadrian{ 2334239312Sadrian struct ieee80211_node **ni_arr; 2335239319Sadrian size_t size; 2336239312Sadrian int i; 2337239312Sadrian uint16_t max_aid; 2338240574Sadrian struct ieee80211vap *vap; 2339239312Sadrian 2340240574Sadrian /* Overdoing it default */ 2341240574Sadrian max_aid = IEEE80211_AID_MAX; 2342240574Sadrian 2343240574Sadrian /* Handle the case of there being no vaps just yet */ 2344240574Sadrian vap = TAILQ_FIRST(&nt->nt_ic->ic_vaps); 2345240574Sadrian if (vap != NULL) 2346240574Sadrian max_aid = vap->iv_max_aid; 2347240574Sadrian 2348239312Sadrian size = max_aid * sizeof(struct ieee80211_node *); 2349283538Sadrian ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE, 2350283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 2351239312Sadrian if (ni_arr == NULL) 2352239312Sadrian return; 2353239312Sadrian 2354239312Sadrian /* 2355239312Sadrian * If this fails, the node table won't have any 2356239312Sadrian * valid entries - ieee80211_iterate_nt() frees 2357239312Sadrian * the references to them. So don't try walking 2358239312Sadrian * the table; just skip to the end and free the 2359239312Sadrian * temporary memory. 2360239312Sadrian */ 2361239319Sadrian if (ieee80211_iterate_nt(nt, ni_arr, max_aid) != 0) 2362239312Sadrian goto done; 2363239312Sadrian 2364239312Sadrian for (i = 0; i < max_aid; i++) { 2365239312Sadrian if (ni_arr[i] == NULL) /* end of the list */ 2366239312Sadrian break; 2367239312Sadrian (*f)(arg, ni_arr[i]); 2368239312Sadrian /* ieee80211_free_node() locks by itself */ 2369239312Sadrian ieee80211_free_node(ni_arr[i]); 2370239312Sadrian } 2371239312Sadrian 2372239312Sadriandone: 2373283538Sadrian IEEE80211_FREE(ni_arr, M_80211_NODE); 2374239312Sadrian} 2375239312Sadrian 2376239312Sadrianvoid 2377138568Ssamieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 2378138568Ssam{ 2379138568Ssam printf("0x%p: mac %s refcnt %d\n", ni, 2380138568Ssam ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); 2381302018Sadrian printf("\tauthmode %u flags 0x%x\n", 2382302018Sadrian ni->ni_authmode, ni->ni_flags); 2383138568Ssam printf("\tassocid 0x%x txpower %u vlan %u\n", 2384138568Ssam ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 2385138568Ssam printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 2386167439Ssam ni->ni_txseqs[IEEE80211_NONQOS_TID], 2387167439Ssam ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT, 2388167439Ssam ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK, 2389138568Ssam ni->ni_rxfragstamp); 2390192468Ssam printf("\trssi %d noise %d intval %u capinfo 0x%x\n", 2391192468Ssam node_getrssi(ni), ni->ni_noise, 2392170530Ssam ni->ni_intval, ni->ni_capinfo); 2393138568Ssam printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n", 2394138568Ssam ether_sprintf(ni->ni_bssid), 2395138568Ssam ni->ni_esslen, ni->ni_essid, 2396138568Ssam ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 2397184277Ssam printf("\tinact %u inact_reload %u txrate %u\n", 2398184277Ssam ni->ni_inact, ni->ni_inact_reload, ni->ni_txrate); 2399170530Ssam printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n", 2400170530Ssam ni->ni_htcap, ni->ni_htparam, 2401170530Ssam ni->ni_htctlchan, ni->ni_ht2ndchan); 2402170530Ssam printf("\thtopmode %x htstbc %x chw %u\n", 2403170530Ssam ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw); 2404138568Ssam} 2405138568Ssam 2406138568Ssamvoid 2407138568Ssamieee80211_dump_nodes(struct ieee80211_node_table *nt) 2408138568Ssam{ 2409138568Ssam ieee80211_iterate_nodes(nt, 2410138568Ssam (ieee80211_iter_func *) ieee80211_dump_node, nt); 2411138568Ssam} 2412138568Ssam 2413179642Ssamstatic void 2414179642Ssamieee80211_notify_erp_locked(struct ieee80211com *ic) 2415172211Ssam{ 2416178354Ssam struct ieee80211vap *vap; 2417178354Ssam 2418178354Ssam IEEE80211_LOCK_ASSERT(ic); 2419178354Ssam 2420178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 2421178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2422178354Ssam ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP); 2423172211Ssam} 2424172211Ssam 2425179642Ssamvoid 2426179642Ssamieee80211_notify_erp(struct ieee80211com *ic) 2427179642Ssam{ 2428179642Ssam IEEE80211_LOCK(ic); 2429179642Ssam ieee80211_notify_erp_locked(ic); 2430179642Ssam IEEE80211_UNLOCK(ic); 2431179642Ssam} 2432179642Ssam 2433138568Ssam/* 2434138568Ssam * Handle a station joining an 11g network. 2435138568Ssam */ 2436138568Ssamstatic void 2437178354Ssamieee80211_node_join_11g(struct ieee80211_node *ni) 2438138568Ssam{ 2439178354Ssam struct ieee80211com *ic = ni->ni_ic; 2440138568Ssam 2441173273Ssam IEEE80211_LOCK_ASSERT(ic); 2442173273Ssam 2443138568Ssam /* 2444138568Ssam * Station isn't capable of short slot time. Bump 2445138568Ssam * the count of long slot time stations and disable 2446138568Ssam * use of short slot time. Note that the actual switch 2447138568Ssam * over to long slot time use may not occur until the 2448138568Ssam * next beacon transmission (per sec. 7.3.1.4 of 11g). 2449138568Ssam */ 2450138568Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2451138568Ssam ic->ic_longslotsta++; 2452178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2453172211Ssam "station needs long slot time, count %d", 2454172211Ssam ic->ic_longslotsta); 2455138568Ssam /* XXX vap's w/ conflicting needs won't work */ 2456170530Ssam if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) { 2457170530Ssam /* 2458170530Ssam * Don't force slot time when switched to turbo 2459170530Ssam * mode as non-ERP stations won't be present; this 2460170530Ssam * need only be done when on the normal G channel. 2461170530Ssam */ 2462170530Ssam ieee80211_set_shortslottime(ic, 0); 2463170530Ssam } 2464138568Ssam } 2465138568Ssam /* 2466138568Ssam * If the new station is not an ERP station 2467138568Ssam * then bump the counter and enable protection 2468138568Ssam * if configured. 2469138568Ssam */ 2470178354Ssam if (!ieee80211_iserp_rateset(&ni->ni_rates)) { 2471138568Ssam ic->ic_nonerpsta++; 2472178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2473172211Ssam "station is !ERP, %d non-ERP stations associated", 2474172211Ssam ic->ic_nonerpsta); 2475138568Ssam /* 2476138568Ssam * If station does not support short preamble 2477138568Ssam * then we must enable use of Barker preamble. 2478138568Ssam */ 2479138568Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 2480178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2481172211Ssam "%s", "station needs long preamble"); 2482138568Ssam ic->ic_flags |= IEEE80211_F_USEBARKER; 2483138568Ssam ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 2484138568Ssam } 2485172211Ssam /* 2486178354Ssam * If protection is configured and this is the first 2487178354Ssam * indication we should use protection, enable it. 2488172211Ssam */ 2489172211Ssam if (ic->ic_protmode != IEEE80211_PROT_NONE && 2490172211Ssam ic->ic_nonerpsta == 1 && 2491172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 2492178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2493172211Ssam "%s: enable use of protection\n", __func__); 2494172211Ssam ic->ic_flags |= IEEE80211_F_USEPROT; 2495179642Ssam ieee80211_notify_erp_locked(ic); 2496172211Ssam } 2497138568Ssam } else 2498138568Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 2499138568Ssam} 2500138568Ssam 2501138568Ssamvoid 2502178354Ssamieee80211_node_join(struct ieee80211_node *ni, int resp) 2503138568Ssam{ 2504178354Ssam struct ieee80211com *ic = ni->ni_ic; 2505178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2506138568Ssam int newassoc; 2507138568Ssam 2508138568Ssam if (ni->ni_associd == 0) { 2509170530Ssam uint16_t aid; 2510138568Ssam 2511178354Ssam KASSERT(vap->iv_aid_bitmap != NULL, ("no aid bitmap")); 2512138568Ssam /* 2513138568Ssam * It would be good to search the bitmap 2514138568Ssam * more efficiently, but this will do for now. 2515138568Ssam */ 2516178354Ssam for (aid = 1; aid < vap->iv_max_aid; aid++) { 2517178354Ssam if (!IEEE80211_AID_ISSET(vap, aid)) 2518138568Ssam break; 2519138568Ssam } 2520178354Ssam if (aid >= vap->iv_max_aid) { 2521179640Ssam IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_TOOMANY); 2522178354Ssam ieee80211_node_leave(ni); 2523138568Ssam return; 2524138568Ssam } 2525138568Ssam ni->ni_associd = aid | 0xc000; 2526173273Ssam ni->ni_jointime = time_uptime; 2527178354Ssam IEEE80211_LOCK(ic); 2528178354Ssam IEEE80211_AID_SET(vap, ni->ni_associd); 2529178354Ssam vap->iv_sta_assoc++; 2530138568Ssam ic->ic_sta_assoc++; 2531173273Ssam 2532173273Ssam if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 2533173273Ssam ieee80211_ht_node_join(ni); 2534170530Ssam if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 2535170530Ssam IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 2536178354Ssam ieee80211_node_join_11g(ni); 2537173273Ssam IEEE80211_UNLOCK(ic); 2538173273Ssam 2539173273Ssam newassoc = 1; 2540138568Ssam } else 2541138568Ssam newassoc = 0; 2542138568Ssam 2543178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 2544183256Ssam "station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s", 2545139523Ssam IEEE80211_NODE_AID(ni), 2546139523Ssam ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2547139523Ssam ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2548139523Ssam ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2549170530Ssam ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "", 2550170530Ssam ni->ni_flags & IEEE80211_NODE_HT ? 2551182834Ssam (ni->ni_chw == 40 ? ", HT40" : ", HT20") : "", 2552173273Ssam ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "", 2553183255Ssam ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" : 2554183255Ssam ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "", 2555183256Ssam ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "", 2556178354Ssam IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ? 2557170530Ssam ", fast-frames" : "", 2558178354Ssam IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ? 2559170530Ssam ", turbo" : "" 2560139523Ssam ); 2561138568Ssam 2562193966Ssam ieee80211_node_setuptxparms(ni); 2563214894Sbschmidt ieee80211_ratectl_node_init(ni); 2564138568Ssam /* give driver a chance to setup state like ni_txrate */ 2565139524Ssam if (ic->ic_newassoc != NULL) 2566148307Ssam ic->ic_newassoc(ni, newassoc); 2567178354Ssam IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_SUCCESS); 2568138568Ssam /* tell the authenticator about new station */ 2569178354Ssam if (vap->iv_auth->ia_node_join != NULL) 2570178354Ssam vap->iv_auth->ia_node_join(ni); 2571178354Ssam ieee80211_notify_node_join(ni, 2572173866Ssam resp == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 2573138568Ssam} 2574138568Ssam 2575172211Ssamstatic void 2576172211Ssamdisable_protection(struct ieee80211com *ic) 2577172211Ssam{ 2578172211Ssam KASSERT(ic->ic_nonerpsta == 0 && 2579172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0, 2580172211Ssam ("%d non ERP stations, flags 0x%x", ic->ic_nonerpsta, 2581172211Ssam ic->ic_flags_ext)); 2582172211Ssam 2583172211Ssam ic->ic_flags &= ~IEEE80211_F_USEPROT; 2584172211Ssam /* XXX verify mode? */ 2585172211Ssam if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2586172211Ssam ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 2587172211Ssam ic->ic_flags &= ~IEEE80211_F_USEBARKER; 2588172211Ssam } 2589179642Ssam ieee80211_notify_erp_locked(ic); 2590172211Ssam} 2591172211Ssam 2592138568Ssam/* 2593138568Ssam * Handle a station leaving an 11g network. 2594138568Ssam */ 2595138568Ssamstatic void 2596178354Ssamieee80211_node_leave_11g(struct ieee80211_node *ni) 2597138568Ssam{ 2598178354Ssam struct ieee80211com *ic = ni->ni_ic; 2599138568Ssam 2600173273Ssam IEEE80211_LOCK_ASSERT(ic); 2601173273Ssam 2602170530Ssam KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan), 2603178354Ssam ("not in 11g, bss %u:0x%x", ic->ic_bsschan->ic_freq, 2604178354Ssam ic->ic_bsschan->ic_flags)); 2605138568Ssam 2606138568Ssam /* 2607138568Ssam * If a long slot station do the slot time bookkeeping. 2608138568Ssam */ 2609138568Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2610138568Ssam KASSERT(ic->ic_longslotsta > 0, 2611138568Ssam ("bogus long slot station count %d", ic->ic_longslotsta)); 2612138568Ssam ic->ic_longslotsta--; 2613178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2614172211Ssam "long slot time station leaves, count now %d", 2615172211Ssam ic->ic_longslotsta); 2616138568Ssam if (ic->ic_longslotsta == 0) { 2617138568Ssam /* 2618138568Ssam * Re-enable use of short slot time if supported 2619138568Ssam * and not operating in IBSS mode (per spec). 2620138568Ssam */ 2621138568Ssam if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2622138568Ssam ic->ic_opmode != IEEE80211_M_IBSS) { 2623178354Ssam IEEE80211_DPRINTF(ni->ni_vap, 2624178354Ssam IEEE80211_MSG_ASSOC, 2625138568Ssam "%s: re-enable use of short slot time\n", 2626138568Ssam __func__); 2627138568Ssam ieee80211_set_shortslottime(ic, 1); 2628138568Ssam } 2629138568Ssam } 2630138568Ssam } 2631138568Ssam /* 2632138568Ssam * If a non-ERP station do the protection-related bookkeeping. 2633138568Ssam */ 2634138568Ssam if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2635138568Ssam KASSERT(ic->ic_nonerpsta > 0, 2636138568Ssam ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2637138568Ssam ic->ic_nonerpsta--; 2638178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2639172211Ssam "non-ERP station leaves, count now %d%s", ic->ic_nonerpsta, 2640172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) ? 2641172211Ssam " (non-ERP sta present)" : ""); 2642172211Ssam if (ic->ic_nonerpsta == 0 && 2643172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 2644178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2645138568Ssam "%s: disable use of protection\n", __func__); 2646172211Ssam disable_protection(ic); 2647138568Ssam } 2648138568Ssam } 2649138568Ssam} 2650138568Ssam 2651138568Ssam/* 2652172211Ssam * Time out presence of an overlapping bss with non-ERP 2653172211Ssam * stations. When operating in hostap mode we listen for 2654172211Ssam * beacons from other stations and if we identify a non-ERP 2655172211Ssam * station is present we enable protection. To identify 2656172211Ssam * when all non-ERP stations are gone we time out this 2657172211Ssam * condition. 2658172211Ssam */ 2659172211Ssamstatic void 2660172211Ssamieee80211_erp_timeout(struct ieee80211com *ic) 2661172211Ssam{ 2662172211Ssam 2663172211Ssam IEEE80211_LOCK_ASSERT(ic); 2664172211Ssam 2665172211Ssam if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) && 2666297405Sadrian ieee80211_time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) { 2667178354Ssam#if 0 2668178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2669178354Ssam "%s", "age out non-ERP sta present on channel"); 2670178354Ssam#endif 2671172211Ssam ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR; 2672172211Ssam if (ic->ic_nonerpsta == 0) 2673172211Ssam disable_protection(ic); 2674172211Ssam } 2675172211Ssam} 2676172211Ssam 2677172211Ssam/* 2678138568Ssam * Handle bookkeeping for station deauthentication/disassociation 2679138568Ssam * when operating as an ap. 2680138568Ssam */ 2681138568Ssamvoid 2682178354Ssamieee80211_node_leave(struct ieee80211_node *ni) 2683138568Ssam{ 2684178354Ssam struct ieee80211com *ic = ni->ni_ic; 2685178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2686140499Ssam struct ieee80211_node_table *nt = ni->ni_table; 2687138568Ssam 2688178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 2689172211Ssam "station with aid %d leaves", IEEE80211_NODE_AID(ni)); 2690138568Ssam 2691178354Ssam KASSERT(vap->iv_opmode != IEEE80211_M_STA, 2692178354Ssam ("unexpected operating mode %u", vap->iv_opmode)); 2693138568Ssam /* 2694138568Ssam * If node wasn't previously associated all 2695138568Ssam * we need to do is reclaim the reference. 2696138568Ssam */ 2697138568Ssam /* XXX ibss mode bypasses 11g and notification */ 2698138568Ssam if (ni->ni_associd == 0) 2699138568Ssam goto done; 2700138568Ssam /* 2701138568Ssam * Tell the authenticator the station is leaving. 2702138568Ssam * Note that we must do this before yanking the 2703138568Ssam * association id as the authenticator uses the 2704138568Ssam * associd to locate it's state block. 2705138568Ssam */ 2706178354Ssam if (vap->iv_auth->ia_node_leave != NULL) 2707178354Ssam vap->iv_auth->ia_node_leave(ni); 2708173273Ssam 2709173273Ssam IEEE80211_LOCK(ic); 2710178354Ssam IEEE80211_AID_CLR(vap, ni->ni_associd); 2711178354Ssam vap->iv_sta_assoc--; 2712138568Ssam ic->ic_sta_assoc--; 2713138568Ssam 2714173273Ssam if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 2715173273Ssam ieee80211_ht_node_leave(ni); 2716170530Ssam if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 2717170530Ssam IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 2718178354Ssam ieee80211_node_leave_11g(ni); 2719173273Ssam IEEE80211_UNLOCK(ic); 2720138568Ssam /* 2721138568Ssam * Cleanup station state. In particular clear various 2722138568Ssam * state that might otherwise be reused if the node 2723138568Ssam * is reused before the reference count goes to zero 2724138568Ssam * (and memory is reclaimed). 2725138568Ssam */ 2726178354Ssam ieee80211_sta_leave(ni); 2727138568Ssamdone: 2728140499Ssam /* 2729140499Ssam * Remove the node from any table it's recorded in and 2730140499Ssam * drop the caller's reference. Removal from the table 2731140499Ssam * is important to insure the node is not reprocessed 2732140499Ssam * for inactivity. 2733140499Ssam */ 2734140499Ssam if (nt != NULL) { 2735140499Ssam IEEE80211_NODE_LOCK(nt); 2736140499Ssam node_reclaim(nt, ni); 2737140499Ssam IEEE80211_NODE_UNLOCK(nt); 2738140499Ssam } else 2739140499Ssam ieee80211_free_node(ni); 2740138568Ssam} 2741138568Ssam 2742178354Ssamstruct rssiinfo { 2743178354Ssam struct ieee80211vap *vap; 2744178354Ssam int rssi_samples; 2745178354Ssam uint32_t rssi_total; 2746178354Ssam}; 2747178354Ssam 2748178354Ssamstatic void 2749178354Ssamget_hostap_rssi(void *arg, struct ieee80211_node *ni) 2750178354Ssam{ 2751178354Ssam struct rssiinfo *info = arg; 2752178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2753178354Ssam int8_t rssi; 2754178354Ssam 2755178354Ssam if (info->vap != vap) 2756178354Ssam return; 2757178354Ssam /* only associated stations */ 2758178354Ssam if (ni->ni_associd == 0) 2759178354Ssam return; 2760178354Ssam rssi = vap->iv_ic->ic_node_getrssi(ni); 2761178354Ssam if (rssi != 0) { 2762178354Ssam info->rssi_samples++; 2763178354Ssam info->rssi_total += rssi; 2764178354Ssam } 2765178354Ssam} 2766178354Ssam 2767178354Ssamstatic void 2768178354Ssamget_adhoc_rssi(void *arg, struct ieee80211_node *ni) 2769178354Ssam{ 2770178354Ssam struct rssiinfo *info = arg; 2771178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2772178354Ssam int8_t rssi; 2773178354Ssam 2774178354Ssam if (info->vap != vap) 2775178354Ssam return; 2776178354Ssam /* only neighbors */ 2777178354Ssam /* XXX check bssid */ 2778178354Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 2779178354Ssam return; 2780178354Ssam rssi = vap->iv_ic->ic_node_getrssi(ni); 2781178354Ssam if (rssi != 0) { 2782178354Ssam info->rssi_samples++; 2783178354Ssam info->rssi_total += rssi; 2784178354Ssam } 2785178354Ssam} 2786178354Ssam 2787195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 2788195618Srpaulostatic void 2789195618Srpauloget_mesh_rssi(void *arg, struct ieee80211_node *ni) 2790195618Srpaulo{ 2791195618Srpaulo struct rssiinfo *info = arg; 2792195618Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2793195618Srpaulo int8_t rssi; 2794195618Srpaulo 2795195618Srpaulo if (info->vap != vap) 2796195618Srpaulo return; 2797195618Srpaulo /* only neighbors that peered successfully */ 2798195618Srpaulo if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 2799195618Srpaulo return; 2800195618Srpaulo rssi = vap->iv_ic->ic_node_getrssi(ni); 2801195618Srpaulo if (rssi != 0) { 2802195618Srpaulo info->rssi_samples++; 2803195618Srpaulo info->rssi_total += rssi; 2804195618Srpaulo } 2805195618Srpaulo} 2806195618Srpaulo#endif /* IEEE80211_SUPPORT_MESH */ 2807195618Srpaulo 2808170530Ssamint8_t 2809178354Ssamieee80211_getrssi(struct ieee80211vap *vap) 2810138568Ssam{ 2811138568Ssam#define NZ(x) ((x) == 0 ? 1 : (x)) 2812178354Ssam struct ieee80211com *ic = vap->iv_ic; 2813178354Ssam struct rssiinfo info; 2814138568Ssam 2815178354Ssam info.rssi_total = 0; 2816178354Ssam info.rssi_samples = 0; 2817178354Ssam info.vap = vap; 2818178354Ssam switch (vap->iv_opmode) { 2819138568Ssam case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2820138568Ssam case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2821178354Ssam ieee80211_iterate_nodes(&ic->ic_sta, get_adhoc_rssi, &info); 2822178354Ssam break; 2823138568Ssam case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2824178354Ssam ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info); 2825138568Ssam break; 2826195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 2827195618Srpaulo case IEEE80211_M_MBSS: /* average of all mesh neighbors */ 2828195618Srpaulo ieee80211_iterate_nodes(&ic->ic_sta, get_mesh_rssi, &info); 2829195618Srpaulo break; 2830195618Srpaulo#endif 2831138568Ssam case IEEE80211_M_MONITOR: /* XXX */ 2832138568Ssam case IEEE80211_M_STA: /* use stats from associated ap */ 2833138568Ssam default: 2834178354Ssam if (vap->iv_bss != NULL) 2835178354Ssam info.rssi_total = ic->ic_node_getrssi(vap->iv_bss); 2836178354Ssam info.rssi_samples = 1; 2837138568Ssam break; 2838138568Ssam } 2839178354Ssam return info.rssi_total / NZ(info.rssi_samples); 2840138568Ssam#undef NZ 2841138568Ssam} 2842138568Ssam 2843170530Ssamvoid 2844178354Ssamieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise) 2845138568Ssam{ 2846138568Ssam 2847178354Ssam if (vap->iv_bss == NULL) /* NB: shouldn't happen */ 2848170530Ssam return; 2849178354Ssam vap->iv_ic->ic_node_getsignal(vap->iv_bss, rssi, noise); 2850170530Ssam /* for non-station mode return avg'd rssi accounting */ 2851178354Ssam if (vap->iv_opmode != IEEE80211_M_STA) 2852178354Ssam *rssi = ieee80211_getrssi(vap); 2853138568Ssam} 2854