ieee80211_node.c revision 297733
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: head/sys/net80211/ieee80211_node.c 297733 2016-04-09 09:31:28Z bz $"); 29116742Ssam 30178354Ssam#include "opt_wlan.h" 31178354Ssam 32116742Ssam#include <sys/param.h> 33116742Ssam#include <sys/systm.h> 34116742Ssam#include <sys/mbuf.h> 35116742Ssam#include <sys/malloc.h> 36116742Ssam#include <sys/kernel.h> 37138568Ssam 38116742Ssam#include <sys/socket.h> 39116742Ssam 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 76159139Sdds#ifdef IEEE80211_DEBUG_REFCNT 77159139Sdds#define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line 78159139Sdds#else 79159139Sdds#define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__ 80159139Sdds#endif 81159139Sdds 82170530Ssamstatic int ieee80211_sta_join1(struct ieee80211_node *); 83170530Ssam 84179643Ssamstatic struct ieee80211_node *node_alloc(struct ieee80211vap *, 85179643Ssam const uint8_t [IEEE80211_ADDR_LEN]); 86138568Ssamstatic void node_cleanup(struct ieee80211_node *); 87138568Ssamstatic void node_free(struct ieee80211_node *); 88178354Ssamstatic void node_age(struct ieee80211_node *); 89170530Ssamstatic int8_t node_getrssi(const struct ieee80211_node *); 90170530Ssamstatic void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *); 91178354Ssamstatic void node_getmimoinfo(const struct ieee80211_node *, 92178354Ssam struct ieee80211_mimo_info *); 93116742Ssam 94138568Ssamstatic void _ieee80211_free_node(struct ieee80211_node *); 95120104Ssam 96282372Sadrianstatic void node_reclaim(struct ieee80211_node_table *nt, 97282372Sadrian struct ieee80211_node *ni); 98138568Ssamstatic void ieee80211_node_table_init(struct ieee80211com *ic, 99148863Ssam struct ieee80211_node_table *nt, const char *name, 100170530Ssam int inact, int keymaxix); 101178354Ssamstatic void ieee80211_node_table_reset(struct ieee80211_node_table *, 102178354Ssam struct ieee80211vap *); 103138568Ssamstatic void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 104172211Ssamstatic void ieee80211_erp_timeout(struct ieee80211com *); 105138568Ssam 106127876SsamMALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 107178354SsamMALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie"); 108120481Ssam 109116742Ssamvoid 110138568Ssamieee80211_node_attach(struct ieee80211com *ic) 111116742Ssam{ 112195379Ssam /* XXX really want maxlen enforced per-sta */ 113195379Ssam ieee80211_ageq_init(&ic->ic_stageq, ic->ic_max_keyix * 8, 114195379Ssam "802.11 staging q"); 115178354Ssam ieee80211_node_table_init(ic, &ic->ic_sta, "station", 116178354Ssam IEEE80211_INACT_INIT, ic->ic_max_keyix); 117283291Sjkim callout_init(&ic->ic_inact, 1); 118178354Ssam callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 119178354Ssam ieee80211_node_timeout, ic); 120116742Ssam 121138568Ssam ic->ic_node_alloc = node_alloc; 122138568Ssam ic->ic_node_free = node_free; 123138568Ssam ic->ic_node_cleanup = node_cleanup; 124178354Ssam ic->ic_node_age = node_age; 125178354Ssam ic->ic_node_drain = node_age; /* NB: same as age */ 126138568Ssam ic->ic_node_getrssi = node_getrssi; 127170530Ssam ic->ic_node_getsignal = node_getsignal; 128178354Ssam ic->ic_node_getmimoinfo = node_getmimoinfo; 129138568Ssam 130178354Ssam /* 131178354Ssam * Set flags to be propagated to all vap's; 132178354Ssam * these define default behaviour/configuration. 133178354Ssam */ 134178354Ssam ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */ 135178354Ssam} 136138568Ssam 137178354Ssamvoid 138178354Ssamieee80211_node_detach(struct ieee80211com *ic) 139178354Ssam{ 140170530Ssam 141178354Ssam callout_drain(&ic->ic_inact); 142178354Ssam ieee80211_node_table_cleanup(&ic->ic_sta); 143195379Ssam ieee80211_ageq_cleanup(&ic->ic_stageq); 144178354Ssam} 145172062Ssam 146178354Ssamvoid 147178354Ssamieee80211_node_vattach(struct ieee80211vap *vap) 148178354Ssam{ 149178354Ssam /* NB: driver can override */ 150178354Ssam vap->iv_max_aid = IEEE80211_AID_DEF; 151178354Ssam 152178354Ssam /* default station inactivity timer setings */ 153178354Ssam vap->iv_inact_init = IEEE80211_INACT_INIT; 154178354Ssam vap->iv_inact_auth = IEEE80211_INACT_AUTH; 155178354Ssam vap->iv_inact_run = IEEE80211_INACT_RUN; 156178354Ssam vap->iv_inact_probe = IEEE80211_INACT_PROBE; 157184277Ssam 158184277Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_INACT, 159184277Ssam "%s: init %u auth %u run %u probe %u\n", __func__, 160184277Ssam vap->iv_inact_init, vap->iv_inact_auth, 161184277Ssam vap->iv_inact_run, vap->iv_inact_probe); 162148863Ssam} 163148863Ssam 164148863Ssamvoid 165178354Ssamieee80211_node_latevattach(struct ieee80211vap *vap) 166148863Ssam{ 167178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 168178354Ssam /* XXX should we allow max aid to be zero? */ 169178354Ssam if (vap->iv_max_aid < IEEE80211_AID_MIN) { 170178354Ssam vap->iv_max_aid = IEEE80211_AID_MIN; 171178354Ssam if_printf(vap->iv_ifp, 172178354Ssam "WARNING: max aid too small, changed to %d\n", 173178354Ssam vap->iv_max_aid); 174178354Ssam } 175283538Sadrian vap->iv_aid_bitmap = (uint32_t *) IEEE80211_MALLOC( 176184210Sdes howmany(vap->iv_max_aid, 32) * sizeof(uint32_t), 177283538Sadrian M_80211_NODE, 178283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 179178354Ssam if (vap->iv_aid_bitmap == NULL) { 180178354Ssam /* XXX no way to recover */ 181178354Ssam printf("%s: no memory for AID bitmap, max aid %d!\n", 182178354Ssam __func__, vap->iv_max_aid); 183178354Ssam vap->iv_max_aid = 0; 184178354Ssam } 185138568Ssam } 186138568Ssam 187178354Ssam ieee80211_reset_bss(vap); 188118887Ssam 189178354Ssam vap->iv_auth = ieee80211_authenticator_get(vap->iv_bss->ni_authmode); 190116742Ssam} 191116742Ssam 192116742Ssamvoid 193178354Ssamieee80211_node_vdetach(struct ieee80211vap *vap) 194116742Ssam{ 195178354Ssam struct ieee80211com *ic = vap->iv_ic; 196116742Ssam 197178354Ssam ieee80211_node_table_reset(&ic->ic_sta, vap); 198178354Ssam if (vap->iv_bss != NULL) { 199178354Ssam ieee80211_free_node(vap->iv_bss); 200178354Ssam vap->iv_bss = NULL; 201138568Ssam } 202178354Ssam if (vap->iv_aid_bitmap != NULL) { 203283538Sadrian IEEE80211_FREE(vap->iv_aid_bitmap, M_80211_NODE); 204178354Ssam vap->iv_aid_bitmap = NULL; 205138568Ssam } 206116742Ssam} 207116742Ssam 208138568Ssam/* 209138568Ssam * Port authorize/unauthorize interfaces for use by an authenticator. 210138568Ssam */ 211138568Ssam 212138568Ssamvoid 213148302Ssamieee80211_node_authorize(struct ieee80211_node *ni) 214138568Ssam{ 215184277Ssam struct ieee80211vap *vap = ni->ni_vap; 216184277Ssam 217138568Ssam ni->ni_flags |= IEEE80211_NODE_AUTH; 218184277Ssam ni->ni_inact_reload = vap->iv_inact_run; 219172062Ssam ni->ni_inact = ni->ni_inact_reload; 220184277Ssam 221184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 222184277Ssam "%s: inact_reload %u", __func__, ni->ni_inact_reload); 223138568Ssam} 224138568Ssam 225138568Ssamvoid 226148302Ssamieee80211_node_unauthorize(struct ieee80211_node *ni) 227138568Ssam{ 228184277Ssam struct ieee80211vap *vap = ni->ni_vap; 229184277Ssam 230138568Ssam ni->ni_flags &= ~IEEE80211_NODE_AUTH; 231184277Ssam ni->ni_inact_reload = vap->iv_inact_auth; 232172062Ssam if (ni->ni_inact > ni->ni_inact_reload) 233172062Ssam ni->ni_inact = ni->ni_inact_reload; 234184277Ssam 235184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 236184277Ssam "%s: inact_reload %u inact %u", __func__, 237184277Ssam ni->ni_inact_reload, ni->ni_inact); 238138568Ssam} 239138568Ssam 240116742Ssam/* 241183251Ssam * Fix tx parameters for a node according to ``association state''. 242183251Ssam */ 243193966Ssamvoid 244193966Ssamieee80211_node_setuptxparms(struct ieee80211_node *ni) 245183251Ssam{ 246183251Ssam struct ieee80211vap *vap = ni->ni_vap; 247187898Ssam enum ieee80211_phymode mode; 248183251Ssam 249183251Ssam if (ni->ni_flags & IEEE80211_NODE_HT) { 250183251Ssam if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 251187898Ssam mode = IEEE80211_MODE_11NA; 252183251Ssam else 253187898Ssam mode = IEEE80211_MODE_11NG; 254183251Ssam } else { /* legacy rate handling */ 255187898Ssam if (IEEE80211_IS_CHAN_ST(ni->ni_chan)) 256187898Ssam mode = IEEE80211_MODE_STURBO_A; 257188782Ssam else if (IEEE80211_IS_CHAN_HALF(ni->ni_chan)) 258188782Ssam mode = IEEE80211_MODE_HALF; 259188782Ssam else if (IEEE80211_IS_CHAN_QUARTER(ni->ni_chan)) 260188782Ssam mode = IEEE80211_MODE_QUARTER; 261191015Ssam /* NB: 108A should be handled as 11a */ 262187898Ssam else if (IEEE80211_IS_CHAN_A(ni->ni_chan)) 263187898Ssam mode = IEEE80211_MODE_11A; 264191015Ssam else if (IEEE80211_IS_CHAN_108G(ni->ni_chan) || 265191015Ssam (ni->ni_flags & IEEE80211_NODE_ERP)) 266187898Ssam mode = IEEE80211_MODE_11G; 267183251Ssam else 268187898Ssam mode = IEEE80211_MODE_11B; 269183251Ssam } 270187898Ssam ni->ni_txparms = &vap->iv_txparms[mode]; 271183251Ssam} 272183251Ssam 273183251Ssam/* 274138568Ssam * Set/change the channel. The rate set is also updated as 275138568Ssam * to insure a consistent view by drivers. 276178354Ssam * XXX should be private but hostap needs it to deal with CSA 277138568Ssam */ 278178354Ssamvoid 279178354Ssamieee80211_node_set_chan(struct ieee80211_node *ni, 280178354Ssam struct ieee80211_channel *chan) 281138568Ssam{ 282178354Ssam struct ieee80211com *ic = ni->ni_ic; 283183251Ssam struct ieee80211vap *vap = ni->ni_vap; 284183251Ssam enum ieee80211_phymode mode; 285170530Ssam 286178354Ssam KASSERT(chan != IEEE80211_CHAN_ANYC, ("no channel")); 287178354Ssam 288138568Ssam ni->ni_chan = chan; 289183251Ssam mode = ieee80211_chan2mode(chan); 290170530Ssam if (IEEE80211_IS_CHAN_HT(chan)) { 291170530Ssam /* 292219602Sbschmidt * We must install the legacy rate est in ni_rates and the 293170530Ssam * HT rate set in ni_htrates. 294170530Ssam */ 295170530Ssam ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); 296183251Ssam /* 297183251Ssam * Setup bss tx parameters based on operating mode. We 298183251Ssam * use legacy rates when operating in a mixed HT+non-HT bss 299183251Ssam * and non-ERP rates in 11g for mixed ERP+non-ERP bss. 300183251Ssam */ 301183251Ssam if (mode == IEEE80211_MODE_11NA && 302193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) 303183251Ssam mode = IEEE80211_MODE_11A; 304183251Ssam else if (mode == IEEE80211_MODE_11NG && 305193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) 306183251Ssam mode = IEEE80211_MODE_11G; 307183251Ssam if (mode == IEEE80211_MODE_11G && 308183251Ssam (vap->iv_flags & IEEE80211_F_PUREG) == 0) 309183251Ssam mode = IEEE80211_MODE_11B; 310170530Ssam } 311183251Ssam ni->ni_txparms = &vap->iv_txparms[mode]; 312165569Ssam ni->ni_rates = *ieee80211_get_suprates(ic, chan); 313138568Ssam} 314138568Ssam 315141658Ssamstatic __inline void 316141658Ssamcopy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 317141658Ssam{ 318141658Ssam /* propagate useful state */ 319141658Ssam nbss->ni_authmode = obss->ni_authmode; 320141658Ssam nbss->ni_txpower = obss->ni_txpower; 321141658Ssam nbss->ni_vlan = obss->ni_vlan; 322141658Ssam /* XXX statistics? */ 323178354Ssam /* XXX legacy WDS bssid? */ 324141658Ssam} 325141658Ssam 326116742Ssamvoid 327178354Ssamieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan) 328116742Ssam{ 329178354Ssam struct ieee80211com *ic = vap->iv_ic; 330116742Ssam struct ieee80211_node *ni; 331116742Ssam 332178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, 333297731Sadrian "%s: creating %s on channel %u%c\n", __func__, 334195618Srpaulo ieee80211_opmode_name[vap->iv_opmode], 335297731Sadrian ieee80211_chan2ieee(ic, chan), 336297731Sadrian ieee80211_channel_type_char(chan)); 337138568Ssam 338178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 339140753Ssam if (ni == NULL) { 340140753Ssam /* XXX recovery? */ 341138568Ssam return; 342138568Ssam } 343178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 344178354Ssam ni->ni_esslen = vap->iv_des_ssid[0].len; 345178354Ssam memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 346178354Ssam if (vap->iv_bss != NULL) 347178354Ssam copy_bss(ni, vap->iv_bss); 348148843Ssam ni->ni_intval = ic->ic_bintval; 349178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) 350116742Ssam ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 351116742Ssam if (ic->ic_phytype == IEEE80211_T_FH) { 352116742Ssam ni->ni_fhdwell = 200; /* XXX */ 353116742Ssam ni->ni_fhindex = 1; 354116742Ssam } 355178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 356178354Ssam vap->iv_flags |= IEEE80211_F_SIBSS; 357138568Ssam ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 358178354Ssam if (vap->iv_flags & IEEE80211_F_DESBSSID) 359178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 360167282Ssam else { 361167282Ssam get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN); 362167282Ssam /* clear group bit, add local bit */ 363167282Ssam ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02; 364167282Ssam } 365178354Ssam } else if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 366178354Ssam if (vap->iv_flags & IEEE80211_F_DESBSSID) 367178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 368153403Ssam else 369186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 370186904Ssam if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 371186904Ssam#endif 372153403Ssam memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 373195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 374195618Srpaulo } else if (vap->iv_opmode == IEEE80211_M_MBSS) { 375195618Srpaulo ni->ni_meshidlen = vap->iv_mesh->ms_idlen; 376195618Srpaulo memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen); 377195618Srpaulo#endif 378138568Ssam } 379138568Ssam /* 380138568Ssam * Fix the channel and related attributes. 381138568Ssam */ 382178354Ssam /* clear DFS CAC state on previous channel */ 383178354Ssam if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && 384178354Ssam ic->ic_bsschan->ic_freq != chan->ic_freq && 385178354Ssam IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) 386178354Ssam ieee80211_dfs_cac_clear(ic, ic->ic_bsschan); 387170530Ssam ic->ic_bsschan = chan; 388178354Ssam ieee80211_node_set_chan(ni, chan); 389170530Ssam ic->ic_curmode = ieee80211_chan2mode(chan); 390138568Ssam /* 391178354Ssam * Do mode-specific setup. 392138568Ssam */ 393170530Ssam if (IEEE80211_IS_CHAN_FULL(chan)) { 394170530Ssam if (IEEE80211_IS_CHAN_ANYG(chan)) { 395170530Ssam /* 396178354Ssam * Use a mixed 11b/11g basic rate set. 397170530Ssam */ 398178354Ssam ieee80211_setbasicrates(&ni->ni_rates, 399178354Ssam IEEE80211_MODE_11G); 400178354Ssam if (vap->iv_flags & IEEE80211_F_PUREG) { 401178354Ssam /* 402178354Ssam * Also mark OFDM rates basic so 11b 403178354Ssam * stations do not join (WiFi compliance). 404178354Ssam */ 405178354Ssam ieee80211_addbasicrates(&ni->ni_rates, 406178354Ssam IEEE80211_MODE_11A); 407178354Ssam } 408170530Ssam } else if (IEEE80211_IS_CHAN_B(chan)) { 409170530Ssam /* 410170530Ssam * Force pure 11b rate set. 411170530Ssam */ 412178354Ssam ieee80211_setbasicrates(&ni->ni_rates, 413170530Ssam IEEE80211_MODE_11B); 414170530Ssam } 415170530Ssam } 416138568Ssam 417170530Ssam (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); 418116742Ssam} 419116742Ssam 420170530Ssam/* 421170530Ssam * Reset bss state on transition to the INIT state. 422170530Ssam * Clear any stations from the table (they have been 423170530Ssam * deauth'd) and reset the bss node (clears key, rate 424170530Ssam * etc. state). 425170530Ssam */ 426138568Ssamvoid 427178354Ssamieee80211_reset_bss(struct ieee80211vap *vap) 428138568Ssam{ 429178354Ssam struct ieee80211com *ic = vap->iv_ic; 430138568Ssam struct ieee80211_node *ni, *obss; 431138568Ssam 432178354Ssam ieee80211_node_table_reset(&ic->ic_sta, vap); 433178354Ssam /* XXX multi-bss: wrong */ 434170530Ssam ieee80211_reset_erp(ic); 435140753Ssam 436178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 437207322Srpaulo KASSERT(ni != NULL, ("unable to setup initial BSS node")); 438178354Ssam obss = vap->iv_bss; 439178354Ssam vap->iv_bss = ieee80211_ref_node(ni); 440141658Ssam if (obss != NULL) { 441141658Ssam copy_bss(ni, obss); 442148843Ssam ni->ni_intval = ic->ic_bintval; 443138568Ssam ieee80211_free_node(obss); 444178354Ssam } else 445178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 446138568Ssam} 447138568Ssam 448170530Ssamstatic int 449170530Ssammatch_ssid(const struct ieee80211_node *ni, 450170530Ssam int nssid, const struct ieee80211_scan_ssid ssids[]) 451170530Ssam{ 452170530Ssam int i; 453148432Ssam 454170530Ssam for (i = 0; i < nssid; i++) { 455170530Ssam if (ni->ni_esslen == ssids[i].len && 456170530Ssam memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0) 457170530Ssam return 1; 458170530Ssam } 459170530Ssam return 0; 460170530Ssam} 461170530Ssam 462170530Ssam/* 463170530Ssam * Test a node for suitability/compatibility. 464170530Ssam */ 465127767Ssamstatic int 466178354Ssamcheck_bss(struct ieee80211vap *vap, struct ieee80211_node *ni) 467127767Ssam{ 468178354Ssam struct ieee80211com *ic = ni->ni_ic; 469170530Ssam uint8_t rate; 470170530Ssam 471170530Ssam if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 472170530Ssam return 0; 473178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 474170530Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 475170530Ssam return 0; 476170530Ssam } else { 477170530Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 478170530Ssam return 0; 479170530Ssam } 480178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) { 481170530Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 482170530Ssam return 0; 483170530Ssam } else { 484170530Ssam /* XXX does this mean privacy is supported or required? */ 485170530Ssam if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 486170530Ssam return 0; 487170530Ssam } 488170530Ssam rate = ieee80211_fix_rate(ni, &ni->ni_rates, 489170530Ssam IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 490170530Ssam if (rate & IEEE80211_RATE_BASIC) 491170530Ssam return 0; 492178354Ssam if (vap->iv_des_nssid != 0 && 493178354Ssam !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 494170530Ssam return 0; 495178354Ssam if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 496178354Ssam !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 497170530Ssam return 0; 498170530Ssam return 1; 499170530Ssam} 500170530Ssam 501170530Ssam#ifdef IEEE80211_DEBUG 502170530Ssam/* 503170530Ssam * Display node suitability/compatibility. 504170530Ssam */ 505170530Ssamstatic void 506178354Ssamcheck_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni) 507170530Ssam{ 508178354Ssam struct ieee80211com *ic = ni->ni_ic; 509170530Ssam uint8_t rate; 510127767Ssam int fail; 511127767Ssam 512127767Ssam fail = 0; 513127767Ssam if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 514127767Ssam fail |= 0x01; 515178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 516127767Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 517127767Ssam fail |= 0x02; 518127767Ssam } else { 519127767Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 520127767Ssam fail |= 0x02; 521127767Ssam } 522178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) { 523127767Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 524127767Ssam fail |= 0x04; 525127767Ssam } else { 526127767Ssam /* XXX does this mean privacy is supported or required? */ 527127767Ssam if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 528127767Ssam fail |= 0x04; 529127767Ssam } 530167442Ssam rate = ieee80211_fix_rate(ni, &ni->ni_rates, 531165887Ssam IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 532127767Ssam if (rate & IEEE80211_RATE_BASIC) 533127767Ssam fail |= 0x08; 534178354Ssam if (vap->iv_des_nssid != 0 && 535178354Ssam !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 536127767Ssam fail |= 0x10; 537178354Ssam if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 538178354Ssam !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 539127767Ssam fail |= 0x20; 540127767Ssam 541170530Ssam printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); 542170530Ssam printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); 543170530Ssam printf(" %3d%c", 544170530Ssam ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); 545170530Ssam printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 546170530Ssam fail & 0x08 ? '!' : ' '); 547170530Ssam printf(" %4s%c", 548170530Ssam (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 549170530Ssam (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 550170530Ssam "????", 551170530Ssam fail & 0x02 ? '!' : ' '); 552170530Ssam printf(" %3s%c ", 553170530Ssam (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no", 554170530Ssam fail & 0x04 ? '!' : ' '); 555170530Ssam ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 556170530Ssam printf("%s\n", fail & 0x10 ? "!" : ""); 557138568Ssam} 558170530Ssam#endif /* IEEE80211_DEBUG */ 559138568Ssam 560297728Sadrian 561297728Sadrianint 562297728Sadrianieee80211_ibss_merge_check(struct ieee80211_node *ni) 563297728Sadrian{ 564297728Sadrian struct ieee80211vap *vap = ni->ni_vap; 565297728Sadrian 566297728Sadrian if (ni == vap->iv_bss || 567297728Sadrian IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { 568297728Sadrian /* unchanged, nothing to do */ 569297728Sadrian return 0; 570297728Sadrian } 571297728Sadrian 572297728Sadrian if (!check_bss(vap, ni)) { 573297728Sadrian /* capabilities mismatch */ 574297728Sadrian IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 575297728Sadrian "%s: merge failed, capabilities mismatch\n", __func__); 576297728Sadrian#ifdef IEEE80211_DEBUG 577297728Sadrian if (ieee80211_msg_assoc(vap)) 578297728Sadrian check_bss_debug(vap, ni); 579297728Sadrian#endif 580297728Sadrian vap->iv_stats.is_ibss_capmismatch++; 581297728Sadrian return 0; 582297728Sadrian } 583297728Sadrian 584297728Sadrian return 1; 585297728Sadrian} 586297728Sadrian 587138568Ssam/* 588138568Ssam * Handle 802.11 ad hoc network merge. The 589138568Ssam * convention, set by the Wireless Ethernet Compatibility Alliance 590138568Ssam * (WECA), is that an 802.11 station will change its BSSID to match 591138568Ssam * the "oldest" 802.11 ad hoc network, on the same channel, that 592138568Ssam * has the station's desired SSID. The "oldest" 802.11 network 593138568Ssam * sends beacons with the greatest TSF timestamp. 594138568Ssam * 595138568Ssam * The caller is assumed to validate TSF's before attempting a merge. 596138568Ssam * 597138568Ssam * Return !0 if the BSSID changed, 0 otherwise. 598138568Ssam */ 599138568Ssamint 600148306Ssamieee80211_ibss_merge(struct ieee80211_node *ni) 601138568Ssam{ 602297733Sbz#ifdef IEEE80211_DEBUG 603178354Ssam struct ieee80211vap *vap = ni->ni_vap; 604148306Ssam struct ieee80211com *ic = ni->ni_ic; 605178354Ssam#endif 606138568Ssam 607297728Sadrian if (! ieee80211_ibss_merge_check(ni)) 608138568Ssam return 0; 609297728Sadrian 610178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 611138568Ssam "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__, 612138568Ssam ether_sprintf(ni->ni_bssid), 613138568Ssam ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 614138568Ssam ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 615138568Ssam ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 616138568Ssam ); 617170530Ssam return ieee80211_sta_join1(ieee80211_ref_node(ni)); 618138568Ssam} 619138568Ssam 620138568Ssam/* 621178354Ssam * Calculate HT channel promotion flags for all vaps. 622178354Ssam * This assumes ni_chan have been setup for each vap. 623173273Ssam */ 624178354Ssamstatic int 625178354Ssamgethtadjustflags(struct ieee80211com *ic) 626178354Ssam{ 627178354Ssam struct ieee80211vap *vap; 628178354Ssam int flags; 629178354Ssam 630178354Ssam flags = 0; 631178354Ssam /* XXX locking */ 632178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 633178354Ssam if (vap->iv_state < IEEE80211_S_RUN) 634178354Ssam continue; 635178354Ssam switch (vap->iv_opmode) { 636178354Ssam case IEEE80211_M_WDS: 637178354Ssam case IEEE80211_M_STA: 638178354Ssam case IEEE80211_M_AHDEMO: 639178354Ssam case IEEE80211_M_HOSTAP: 640178354Ssam case IEEE80211_M_IBSS: 641195618Srpaulo case IEEE80211_M_MBSS: 642178354Ssam flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan); 643178354Ssam break; 644178354Ssam default: 645178354Ssam break; 646178354Ssam } 647178354Ssam } 648178354Ssam return flags; 649178354Ssam} 650178354Ssam 651178354Ssam/* 652178354Ssam * Check if the current channel needs to change based on whether 653184303Ssam * any vap's are using HT20/HT40. This is used to sync the state 654184303Ssam * of ic_curchan after a channel width change on a running vap. 655178354Ssam */ 656173273Ssamvoid 657178354Ssamieee80211_sync_curchan(struct ieee80211com *ic) 658173273Ssam{ 659178354Ssam struct ieee80211_channel *c; 660178354Ssam 661178354Ssam c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic)); 662178354Ssam if (c != ic->ic_curchan) { 663178354Ssam ic->ic_curchan = c; 664178354Ssam ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 665190532Ssam ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); 666191746Sthompsa IEEE80211_UNLOCK(ic); 667178354Ssam ic->ic_set_channel(ic); 668192468Ssam ieee80211_radiotap_chan_change(ic); 669191746Sthompsa IEEE80211_LOCK(ic); 670178354Ssam } 671178354Ssam} 672178354Ssam 673178354Ssam/* 674191746Sthompsa * Setup the current channel. The request channel may be 675178354Ssam * promoted if other vap's are operating with HT20/HT40. 676178354Ssam */ 677178354Ssamvoid 678191746Sthompsaieee80211_setupcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 679178354Ssam{ 680178354Ssam if (ic->ic_htcaps & IEEE80211_HTC_HT) { 681178354Ssam int flags = gethtadjustflags(ic); 682178354Ssam /* 683178354Ssam * Check for channel promotion required to support the 684178354Ssam * set of running vap's. This assumes we are called 685178354Ssam * after ni_chan is setup for each vap. 686178354Ssam */ 687193655Ssam /* NB: this assumes IEEE80211_FHT_USEHT40 > IEEE80211_FHT_HT */ 688178354Ssam if (flags > ieee80211_htchanflags(c)) 689178354Ssam c = ieee80211_ht_adjust_channel(ic, c, flags); 690178354Ssam } 691178354Ssam ic->ic_bsschan = ic->ic_curchan = c; 692173273Ssam ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 693190532Ssam ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); 694173273Ssam} 695173273Ssam 696173273Ssam/* 697191746Sthompsa * Change the current channel. The channel change is guaranteed to have 698191746Sthompsa * happened before the next state change. 699191746Sthompsa */ 700191746Sthompsavoid 701191746Sthompsaieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 702191746Sthompsa{ 703191746Sthompsa ieee80211_setupcurchan(ic, c); 704191746Sthompsa ieee80211_runtask(ic, &ic->ic_chan_task); 705191746Sthompsa} 706191746Sthompsa 707233452Sadrianvoid 708233452Sadrianieee80211_update_chw(struct ieee80211com *ic) 709233452Sadrian{ 710233452Sadrian 711233452Sadrian ieee80211_setupcurchan(ic, ic->ic_curchan); 712233452Sadrian ieee80211_runtask(ic, &ic->ic_chw_task); 713233452Sadrian} 714233452Sadrian 715191746Sthompsa/* 716138568Ssam * Join the specified IBSS/BSS network. The node is assumed to 717138568Ssam * be passed in with a held reference. 718138568Ssam */ 719170530Ssamstatic int 720170530Ssamieee80211_sta_join1(struct ieee80211_node *selbs) 721138568Ssam{ 722178354Ssam struct ieee80211vap *vap = selbs->ni_vap; 723170530Ssam struct ieee80211com *ic = selbs->ni_ic; 724138568Ssam struct ieee80211_node *obss; 725170530Ssam int canreassoc; 726138568Ssam 727138568Ssam /* 728138568Ssam * Committed to selbs, setup state. 729138568Ssam */ 730178354Ssam obss = vap->iv_bss; 731170530Ssam /* 732170530Ssam * Check if old+new node have the same address in which 733170530Ssam * case we can reassociate when operating in sta mode. 734170530Ssam */ 735170530Ssam canreassoc = (obss != NULL && 736178354Ssam vap->iv_state == IEEE80211_S_RUN && 737170530Ssam IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr)); 738178354Ssam vap->iv_bss = selbs; /* NB: caller assumed to bump refcnt */ 739153352Ssam if (obss != NULL) { 740282372Sadrian struct ieee80211_node_table *nt = obss->ni_table; 741282372Sadrian 742153352Ssam copy_bss(selbs, obss); 743188541Ssam ieee80211_node_decref(obss); /* iv_bss reference */ 744282372Sadrian 745282372Sadrian IEEE80211_NODE_LOCK(nt); 746282372Sadrian node_reclaim(nt, obss); /* station table reference */ 747282372Sadrian IEEE80211_NODE_UNLOCK(nt); 748282372Sadrian 749178354Ssam obss = NULL; /* NB: guard against later use */ 750153352Ssam } 751165887Ssam 752138568Ssam /* 753165887Ssam * Delete unusable rates; we've already checked 754165887Ssam * that the negotiated rate set is acceptable. 755165887Ssam */ 756178354Ssam ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates, 757167442Ssam IEEE80211_F_DODEL | IEEE80211_F_JOIN); 758165887Ssam 759178354Ssam ieee80211_setcurchan(ic, selbs->ni_chan); 760165887Ssam /* 761138568Ssam * Set the erp state (mostly the slot time) to deal with 762138568Ssam * the auto-select case; this should be redundant if the 763138568Ssam * mode is locked. 764138568Ssam */ 765138568Ssam ieee80211_reset_erp(ic); 766178354Ssam ieee80211_wme_initparams(vap); 767140753Ssam 768178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 769170530Ssam if (canreassoc) { 770170530Ssam /* Reassociate */ 771178354Ssam ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1); 772170530Ssam } else { 773170530Ssam /* 774170530Ssam * Act as if we received a DEAUTH frame in case we 775170530Ssam * are invoked from the RUN state. This will cause 776170530Ssam * us to try to re-authenticate if we are operating 777170530Ssam * as a station. 778170530Ssam */ 779178354Ssam ieee80211_new_state(vap, IEEE80211_S_AUTH, 780170530Ssam IEEE80211_FC0_SUBTYPE_DEAUTH); 781170530Ssam } 782170530Ssam } else 783178354Ssam ieee80211_new_state(vap, IEEE80211_S_RUN, -1); 784138568Ssam return 1; 785116742Ssam} 786116742Ssam 787170530Ssamint 788184274Ssamieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan, 789170530Ssam const struct ieee80211_scan_entry *se) 790170530Ssam{ 791178354Ssam struct ieee80211com *ic = vap->iv_ic; 792170530Ssam struct ieee80211_node *ni; 793170530Ssam 794178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr); 795170530Ssam if (ni == NULL) { 796170530Ssam /* XXX msg */ 797170530Ssam return 0; 798170530Ssam } 799245928Sadrian 800170530Ssam /* 801170530Ssam * Expand scan state into node's format. 802170530Ssam * XXX may not need all this stuff 803170530Ssam */ 804170530Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid); 805170530Ssam ni->ni_esslen = se->se_ssid[1]; 806170530Ssam memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen); 807170530Ssam ni->ni_tstamp.tsf = se->se_tstamp.tsf; 808170530Ssam ni->ni_intval = se->se_intval; 809170530Ssam ni->ni_capinfo = se->se_capinfo; 810184274Ssam ni->ni_chan = chan; 811170530Ssam ni->ni_timoff = se->se_timoff; 812170530Ssam ni->ni_fhdwell = se->se_fhdwell; 813170530Ssam ni->ni_fhindex = se->se_fhindex; 814170530Ssam ni->ni_erp = se->se_erp; 815178354Ssam IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi); 816170530Ssam ni->ni_noise = se->se_noise; 817186870Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 818186870Ssam /* NB: only infrastructure mode requires an associd */ 819186870Ssam ni->ni_flags |= IEEE80211_NODE_ASSOCID; 820186870Ssam } 821178354Ssam 822178354Ssam if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) { 823178354Ssam ieee80211_ies_expand(&ni->ni_ies); 824190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 825178354Ssam if (ni->ni_ies.ath_ie != NULL) 826178354Ssam ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 827190391Ssam#endif 828178354Ssam if (ni->ni_ies.htcap_ie != NULL) 829178354Ssam ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie); 830178354Ssam if (ni->ni_ies.htinfo_ie != NULL) 831178354Ssam ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie); 832195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 833195618Srpaulo if (ni->ni_ies.meshid_ie != NULL) 834195618Srpaulo ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie); 835195618Srpaulo#endif 836186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 837186904Ssam if (ni->ni_ies.tdma_ie != NULL) 838186904Ssam ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie); 839186904Ssam#endif 840173864Ssam } 841170530Ssam 842178354Ssam vap->iv_dtim_period = se->se_dtimperiod; 843178354Ssam vap->iv_dtim_count = 0; 844170530Ssam 845170530Ssam /* NB: must be after ni_chan is setup */ 846170530Ssam ieee80211_setup_rates(ni, se->se_rates, se->se_xrates, 847170530Ssam IEEE80211_F_DOSORT); 848184279Ssam if (ieee80211_iserp_rateset(&ni->ni_rates)) 849184279Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 850245928Sadrian 851245928Sadrian /* 852245928Sadrian * Setup HT state for this node if it's available, otherwise 853245928Sadrian * non-STA modes won't pick this state up. 854245928Sadrian * 855245928Sadrian * For IBSS and related modes that don't go through an 856245928Sadrian * association request/response, the only appropriate place 857245928Sadrian * to setup the HT state is here. 858245928Sadrian */ 859245928Sadrian if (ni->ni_ies.htinfo_ie != NULL && 860245928Sadrian ni->ni_ies.htcap_ie != NULL && 861245928Sadrian vap->iv_flags_ht & IEEE80211_FHT_HT) { 862245928Sadrian ieee80211_ht_node_init(ni); 863245928Sadrian ieee80211_ht_updateparams(ni, 864245928Sadrian ni->ni_ies.htcap_ie, 865245928Sadrian ni->ni_ies.htinfo_ie); 866245928Sadrian ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie, 867245928Sadrian IEEE80211_F_JOIN | IEEE80211_F_DOBRS); 868245928Sadrian ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie); 869245928Sadrian } 870245928Sadrian /* XXX else check for ath FF? */ 871245928Sadrian /* XXX QoS? Difficult given that WME config is specific to a master */ 872245928Sadrian 873193966Ssam ieee80211_node_setuptxparms(ni); 874214894Sbschmidt ieee80211_ratectl_node_init(ni); 875170530Ssam 876170530Ssam return ieee80211_sta_join1(ieee80211_ref_node(ni)); 877170530Ssam} 878170530Ssam 879138568Ssam/* 880138568Ssam * Leave the specified IBSS/BSS network. The node is assumed to 881138568Ssam * be passed in with a held reference. 882138568Ssam */ 883138568Ssamvoid 884178354Ssamieee80211_sta_leave(struct ieee80211_node *ni) 885138568Ssam{ 886178354Ssam struct ieee80211com *ic = ni->ni_ic; 887178354Ssam 888138568Ssam ic->ic_node_cleanup(ni); 889178354Ssam ieee80211_notify_node_leave(ni); 890138568Ssam} 891138568Ssam 892178354Ssam/* 893178354Ssam * Send a deauthenticate frame and drop the station. 894178354Ssam */ 895178354Ssamvoid 896178354Ssamieee80211_node_deauth(struct ieee80211_node *ni, int reason) 897178354Ssam{ 898282404Sadrian /* NB: bump the refcnt to be sure temporary nodes are not reclaimed */ 899178354Ssam ieee80211_ref_node(ni); 900178354Ssam if (ni->ni_associd != 0) 901178354Ssam IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); 902178354Ssam ieee80211_node_leave(ni); 903178354Ssam ieee80211_free_node(ni); 904178354Ssam} 905178354Ssam 906116742Ssamstatic struct ieee80211_node * 907179643Ssamnode_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 908116742Ssam{ 909127768Ssam struct ieee80211_node *ni; 910138568Ssam 911283538Sadrian ni = (struct ieee80211_node *) IEEE80211_MALLOC(sizeof(struct ieee80211_node), 912283538Sadrian M_80211_NODE, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 913127768Ssam return ni; 914116742Ssam} 915116742Ssam 916138568Ssam/* 917178354Ssam * Initialize an ie blob with the specified data. If previous 918178354Ssam * data exists re-use the data block. As a side effect we clear 919178354Ssam * all references to specific ie's; the caller is required to 920178354Ssam * recalculate them. 921178354Ssam */ 922178354Ssamint 923178354Ssamieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len) 924178354Ssam{ 925178354Ssam /* NB: assumes data+len are the last fields */ 926178354Ssam memset(ies, 0, offsetof(struct ieee80211_ies, data)); 927178354Ssam if (ies->data != NULL && ies->len != len) { 928178354Ssam /* data size changed */ 929283538Sadrian IEEE80211_FREE(ies->data, M_80211_NODE_IE); 930178354Ssam ies->data = NULL; 931178354Ssam } 932178354Ssam if (ies->data == NULL) { 933283538Sadrian ies->data = (uint8_t *) IEEE80211_MALLOC(len, M_80211_NODE_IE, 934283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 935178354Ssam if (ies->data == NULL) { 936178354Ssam ies->len = 0; 937178354Ssam /* NB: pointers have already been zero'd above */ 938178354Ssam return 0; 939178354Ssam } 940178354Ssam } 941178354Ssam memcpy(ies->data, data, len); 942178354Ssam ies->len = len; 943178354Ssam return 1; 944178354Ssam} 945178354Ssam 946178354Ssam/* 947178354Ssam * Reclaim storage for an ie blob. 948178354Ssam */ 949178354Ssamvoid 950178354Ssamieee80211_ies_cleanup(struct ieee80211_ies *ies) 951178354Ssam{ 952178354Ssam if (ies->data != NULL) 953283538Sadrian IEEE80211_FREE(ies->data, M_80211_NODE_IE); 954178354Ssam} 955178354Ssam 956178354Ssam/* 957178354Ssam * Expand an ie blob data contents and to fillin individual 958178354Ssam * ie pointers. The data blob is assumed to be well-formed; 959178354Ssam * we don't do any validity checking of ie lengths. 960178354Ssam */ 961178354Ssamvoid 962178354Ssamieee80211_ies_expand(struct ieee80211_ies *ies) 963178354Ssam{ 964178354Ssam uint8_t *ie; 965178354Ssam int ielen; 966178354Ssam 967178354Ssam ie = ies->data; 968178354Ssam ielen = ies->len; 969178354Ssam while (ielen > 0) { 970178354Ssam switch (ie[0]) { 971178354Ssam case IEEE80211_ELEMID_VENDOR: 972178354Ssam if (iswpaoui(ie)) 973178354Ssam ies->wpa_ie = ie; 974178354Ssam else if (iswmeoui(ie)) 975178354Ssam ies->wme_ie = ie; 976190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 977178354Ssam else if (isatherosoui(ie)) 978178354Ssam ies->ath_ie = ie; 979190391Ssam#endif 980186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 981186904Ssam else if (istdmaoui(ie)) 982186904Ssam ies->tdma_ie = ie; 983186904Ssam#endif 984178354Ssam break; 985178354Ssam case IEEE80211_ELEMID_RSN: 986178354Ssam ies->rsn_ie = ie; 987178354Ssam break; 988178354Ssam case IEEE80211_ELEMID_HTCAP: 989178354Ssam ies->htcap_ie = ie; 990178354Ssam break; 991245928Sadrian case IEEE80211_ELEMID_HTINFO: 992245928Sadrian ies->htinfo_ie = ie; 993245928Sadrian break; 994195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 995195618Srpaulo case IEEE80211_ELEMID_MESHID: 996195618Srpaulo ies->meshid_ie = ie; 997195618Srpaulo break; 998195618Srpaulo#endif 999178354Ssam } 1000178354Ssam ielen -= 2 + ie[1]; 1001178354Ssam ie += 2 + ie[1]; 1002178354Ssam } 1003178354Ssam} 1004178354Ssam 1005178354Ssam/* 1006138568Ssam * Reclaim any resources in a node and reset any critical 1007138568Ssam * state. Typically nodes are free'd immediately after, 1008138568Ssam * but in some cases the storage may be reused so we need 1009138568Ssam * to insure consistent state (should probably fix that). 1010138568Ssam */ 1011116742Ssamstatic void 1012138568Ssamnode_cleanup(struct ieee80211_node *ni) 1013116742Ssam{ 1014178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1015195379Ssam struct ieee80211com *ic = ni->ni_ic; 1016170530Ssam int i; 1017138568Ssam 1018138568Ssam /* NB: preserve ni_table */ 1019138568Ssam if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 1020178354Ssam if (vap->iv_opmode != IEEE80211_M_STA) 1021178354Ssam vap->iv_ps_sta--; 1022138568Ssam ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 1023178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 1024178354Ssam "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); 1025138568Ssam } 1026147788Ssam /* 1027173273Ssam * Cleanup any HT-related state. 1028173273Ssam */ 1029173273Ssam if (ni->ni_flags & IEEE80211_NODE_HT) 1030173273Ssam ieee80211_ht_node_cleanup(ni); 1031190579Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1032297603Sadrian /* Always do FF node cleanup; for A-MSDU */ 1033297603Sadrian ieee80211_ff_node_cleanup(ni); 1034190579Ssam#endif 1035195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1036173273Ssam /* 1037195618Srpaulo * Cleanup any mesh-related state. 1038195618Srpaulo */ 1039195618Srpaulo if (vap->iv_opmode == IEEE80211_M_MBSS) 1040195618Srpaulo ieee80211_mesh_node_cleanup(ni); 1041195618Srpaulo#endif 1042195618Srpaulo /* 1043195379Ssam * Clear any staging queue entries. 1044195379Ssam */ 1045195379Ssam ieee80211_ageq_drain_node(&ic->ic_stageq, ni); 1046195379Ssam 1047195379Ssam /* 1048147788Ssam * Clear AREF flag that marks the authorization refcnt bump 1049147788Ssam * has happened. This is probably not needed as the node 1050147788Ssam * should always be removed from the table so not found but 1051147788Ssam * do it just in case. 1052186099Ssam * Likewise clear the ASSOCID flag as these flags are intended 1053186099Ssam * to be managed in tandem. 1054147788Ssam */ 1055186099Ssam ni->ni_flags &= ~(IEEE80211_NODE_AREF | IEEE80211_NODE_ASSOCID); 1056138568Ssam 1057138568Ssam /* 1058138568Ssam * Drain power save queue and, if needed, clear TIM. 1059138568Ssam */ 1060184288Ssam if (ieee80211_node_psq_drain(ni) != 0 && vap->iv_set_tim != NULL) 1061178354Ssam vap->iv_set_tim(ni, 0); 1062138568Ssam 1063138568Ssam ni->ni_associd = 0; 1064138568Ssam if (ni->ni_challenge != NULL) { 1065283538Sadrian IEEE80211_FREE(ni->ni_challenge, M_80211_NODE); 1066138568Ssam ni->ni_challenge = NULL; 1067138568Ssam } 1068138568Ssam /* 1069138568Ssam * Preserve SSID, WPA, and WME ie's so the bss node is 1070138568Ssam * reusable during a re-auth/re-assoc state transition. 1071138568Ssam * If we remove these data they will not be recreated 1072138568Ssam * because they come from a probe-response or beacon frame 1073138568Ssam * which cannot be expected prior to the association-response. 1074138568Ssam * This should not be an issue when operating in other modes 1075138568Ssam * as stations leaving always go through a full state transition 1076138568Ssam * which will rebuild this state. 1077138568Ssam * 1078138568Ssam * XXX does this leave us open to inheriting old state? 1079138568Ssam */ 1080254315Srpaulo for (i = 0; i < nitems(ni->ni_rxfrag); i++) 1081138568Ssam if (ni->ni_rxfrag[i] != NULL) { 1082138568Ssam m_freem(ni->ni_rxfrag[i]); 1083138568Ssam ni->ni_rxfrag[i] = NULL; 1084138568Ssam } 1085148863Ssam /* 1086148863Ssam * Must be careful here to remove any key map entry w/o a LOR. 1087148863Ssam */ 1088148863Ssam ieee80211_node_delucastkey(ni); 1089116742Ssam} 1090116742Ssam 1091116742Ssamstatic void 1092138568Ssamnode_free(struct ieee80211_node *ni) 1093116742Ssam{ 1094138568Ssam struct ieee80211com *ic = ni->ni_ic; 1095138568Ssam 1096214894Sbschmidt ieee80211_ratectl_node_deinit(ni); 1097138568Ssam ic->ic_node_cleanup(ni); 1098178354Ssam ieee80211_ies_cleanup(&ni->ni_ies); 1099184288Ssam ieee80211_psq_cleanup(&ni->ni_psq); 1100283538Sadrian IEEE80211_FREE(ni, M_80211_NODE); 1101116742Ssam} 1102116742Ssam 1103178354Ssamstatic void 1104178354Ssamnode_age(struct ieee80211_node *ni) 1105178354Ssam{ 1106178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1107184303Ssam 1108184303Ssam IEEE80211_NODE_LOCK_ASSERT(&vap->iv_ic->ic_sta); 1109184303Ssam 1110178354Ssam /* 1111178354Ssam * Age frames on the power save queue. 1112178354Ssam */ 1113184288Ssam if (ieee80211_node_psq_age(ni) != 0 && 1114184288Ssam ni->ni_psq.psq_len == 0 && vap->iv_set_tim != NULL) 1115178354Ssam vap->iv_set_tim(ni, 0); 1116178354Ssam /* 1117178354Ssam * Age out HT resources (e.g. frames on the 1118178354Ssam * A-MPDU reorder queues). 1119178354Ssam */ 1120178354Ssam if (ni->ni_associd != 0 && (ni->ni_flags & IEEE80211_NODE_HT)) 1121178354Ssam ieee80211_ht_node_age(ni); 1122178354Ssam} 1123178354Ssam 1124170530Ssamstatic int8_t 1125138568Ssamnode_getrssi(const struct ieee80211_node *ni) 1126120104Ssam{ 1127178354Ssam uint32_t avgrssi = ni->ni_avgrssi; 1128178354Ssam int32_t rssi; 1129178354Ssam 1130178354Ssam if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) 1131178354Ssam return 0; 1132178354Ssam rssi = IEEE80211_RSSI_GET(avgrssi); 1133178354Ssam return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 1134120104Ssam} 1135120104Ssam 1136116742Ssamstatic void 1137170530Ssamnode_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise) 1138170530Ssam{ 1139178354Ssam *rssi = node_getrssi(ni); 1140170530Ssam *noise = ni->ni_noise; 1141170530Ssam} 1142170530Ssam 1143170530Ssamstatic void 1144178354Ssamnode_getmimoinfo(const struct ieee80211_node *ni, 1145178354Ssam struct ieee80211_mimo_info *info) 1146116742Ssam{ 1147220445Sadrian int i; 1148220445Sadrian uint32_t avgrssi; 1149220445Sadrian int32_t rssi; 1150220445Sadrian 1151220445Sadrian bzero(info, sizeof(*info)); 1152220445Sadrian 1153220445Sadrian for (i = 0; i < ni->ni_mimo_chains; i++) { 1154220445Sadrian avgrssi = ni->ni_mimo_rssi_ctl[i]; 1155220445Sadrian if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) { 1156220935Sadrian info->rssi[i] = 0; 1157220445Sadrian } else { 1158220445Sadrian rssi = IEEE80211_RSSI_GET(avgrssi); 1159220935Sadrian info->rssi[i] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 1160220445Sadrian } 1161220935Sadrian info->noise[i] = ni->ni_mimo_noise_ctl[i]; 1162220445Sadrian } 1163220445Sadrian 1164220935Sadrian /* XXX ext radios? */ 1165220935Sadrian 1166220445Sadrian /* XXX EVM? */ 1167178354Ssam} 1168178354Ssam 1169178354Ssamstruct ieee80211_node * 1170178354Ssamieee80211_alloc_node(struct ieee80211_node_table *nt, 1171178354Ssam struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1172178354Ssam{ 1173138568Ssam struct ieee80211com *ic = nt->nt_ic; 1174178354Ssam struct ieee80211_node *ni; 1175116742Ssam int hash; 1176116742Ssam 1177179643Ssam ni = ic->ic_node_alloc(vap, macaddr); 1178178354Ssam if (ni == NULL) { 1179178354Ssam vap->iv_stats.is_rx_nodealloc++; 1180178354Ssam return NULL; 1181178354Ssam } 1182178354Ssam 1183178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1184140766Ssam "%s %p<%s> in %s table\n", __func__, ni, 1185138568Ssam ether_sprintf(macaddr), nt->nt_name); 1186138568Ssam 1187116742Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1188195618Srpaulo hash = IEEE80211_NODE_HASH(ic, macaddr); 1189138568Ssam ieee80211_node_initref(ni); /* mark referenced */ 1190138568Ssam ni->ni_chan = IEEE80211_CHAN_ANYC; 1191138568Ssam ni->ni_authmode = IEEE80211_AUTH_OPEN; 1192138568Ssam ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 1193183251Ssam ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1194178354Ssam ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 1195178354Ssam ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER; 1196139528Ssam ni->ni_inact_reload = nt->nt_inact_init; 1197139528Ssam ni->ni_inact = ni->ni_inact_reload; 1198170530Ssam ni->ni_ath_defkeyix = 0x7fff; 1199184288Ssam ieee80211_psq_init(&ni->ni_psq, "unknown"); 1200195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1201195618Srpaulo if (vap->iv_opmode == IEEE80211_M_MBSS) 1202195618Srpaulo ieee80211_mesh_node_init(vap, ni); 1203195618Srpaulo#endif 1204138568Ssam IEEE80211_NODE_LOCK(nt); 1205138568Ssam TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 1206138568Ssam LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 1207138568Ssam ni->ni_table = nt; 1208178354Ssam ni->ni_vap = vap; 1209138568Ssam ni->ni_ic = ic; 1210138568Ssam IEEE80211_NODE_UNLOCK(nt); 1211116742Ssam 1212184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 1213184277Ssam "%s: inact_reload %u", __func__, ni->ni_inact_reload); 1214184277Ssam 1215217511Sbschmidt ieee80211_ratectl_node_init(ni); 1216217511Sbschmidt 1217116742Ssam return ni; 1218116742Ssam} 1219116742Ssam 1220148777Ssam/* 1221148777Ssam * Craft a temporary node suitable for sending a management frame 1222148777Ssam * to the specified station. We craft only as much state as we 1223148777Ssam * need to do the work since the node will be immediately reclaimed 1224148777Ssam * once the send completes. 1225148777Ssam */ 1226116742Ssamstruct ieee80211_node * 1227178354Ssamieee80211_tmp_node(struct ieee80211vap *vap, 1228178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1229148777Ssam{ 1230178354Ssam struct ieee80211com *ic = vap->iv_ic; 1231148777Ssam struct ieee80211_node *ni; 1232148777Ssam 1233179643Ssam ni = ic->ic_node_alloc(vap, macaddr); 1234148777Ssam if (ni != NULL) { 1235183259Ssam struct ieee80211_node *bss = vap->iv_bss; 1236183259Ssam 1237178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1238148777Ssam "%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr)); 1239148777Ssam 1240178354Ssam ni->ni_table = NULL; /* NB: pedantic */ 1241178354Ssam ni->ni_ic = ic; /* NB: needed to set channel */ 1242178354Ssam ni->ni_vap = vap; 1243178354Ssam 1244148777Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1245183259Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); 1246148777Ssam ieee80211_node_initref(ni); /* mark referenced */ 1247148777Ssam /* NB: required by ieee80211_fix_rate */ 1248183259Ssam ieee80211_node_set_chan(ni, bss->ni_chan); 1249178354Ssam ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, 1250148777Ssam IEEE80211_KEYIX_NONE); 1251183259Ssam ni->ni_txpower = bss->ni_txpower; 1252148777Ssam /* XXX optimize away */ 1253184288Ssam ieee80211_psq_init(&ni->ni_psq, "unknown"); 1254217511Sbschmidt 1255217511Sbschmidt ieee80211_ratectl_node_init(ni); 1256148777Ssam } else { 1257148777Ssam /* XXX msg */ 1258178354Ssam vap->iv_stats.is_rx_nodealloc++; 1259148777Ssam } 1260148777Ssam return ni; 1261148777Ssam} 1262148777Ssam 1263148777Ssamstruct ieee80211_node * 1264178354Ssamieee80211_dup_bss(struct ieee80211vap *vap, 1265178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1266116742Ssam{ 1267178354Ssam struct ieee80211com *ic = vap->iv_ic; 1268138568Ssam struct ieee80211_node *ni; 1269138568Ssam 1270178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr); 1271116742Ssam if (ni != NULL) { 1272183259Ssam struct ieee80211_node *bss = vap->iv_bss; 1273127770Ssam /* 1274178354Ssam * Inherit from iv_bss. 1275127770Ssam */ 1276183259Ssam copy_bss(ni, bss); 1277183259Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); 1278183259Ssam ieee80211_node_set_chan(ni, bss->ni_chan); 1279178354Ssam } 1280116742Ssam return ni; 1281116742Ssam} 1282116742Ssam 1283178354Ssam/* 1284178354Ssam * Create a bss node for a legacy WDS vap. The far end does 1285178354Ssam * not associate so we just create create a new node and 1286178354Ssam * simulate an association. The caller is responsible for 1287178354Ssam * installing the node as the bss node and handling any further 1288178354Ssam * setup work like authorizing the port. 1289178354Ssam */ 1290178354Ssamstruct ieee80211_node * 1291178354Ssamieee80211_node_create_wds(struct ieee80211vap *vap, 1292178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], struct ieee80211_channel *chan) 1293178354Ssam{ 1294178354Ssam struct ieee80211com *ic = vap->iv_ic; 1295178354Ssam struct ieee80211_node *ni; 1296178354Ssam 1297178354Ssam /* XXX check if node already in sta table? */ 1298178354Ssam ni = ieee80211_alloc_node(&ic->ic_sta, vap, bssid); 1299178354Ssam if (ni != NULL) { 1300178354Ssam ni->ni_wdsvap = vap; 1301178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bssid); 1302178354Ssam /* 1303178354Ssam * Inherit any manually configured settings. 1304178354Ssam */ 1305183259Ssam copy_bss(ni, vap->iv_bss); 1306178354Ssam ieee80211_node_set_chan(ni, chan); 1307178354Ssam /* NB: propagate ssid so available to WPA supplicant */ 1308178354Ssam ni->ni_esslen = vap->iv_des_ssid[0].len; 1309178354Ssam memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 1310178354Ssam /* NB: no associd for peer */ 1311178354Ssam /* 1312178354Ssam * There are no management frames to use to 1313178354Ssam * discover neighbor capabilities, so blindly 1314178354Ssam * propagate the local configuration. 1315178354Ssam */ 1316178354Ssam if (vap->iv_flags & IEEE80211_F_WME) 1317178354Ssam ni->ni_flags |= IEEE80211_NODE_QOS; 1318190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1319178354Ssam if (vap->iv_flags & IEEE80211_F_FF) 1320178354Ssam ni->ni_flags |= IEEE80211_NODE_FF; 1321190391Ssam#endif 1322178354Ssam if ((ic->ic_htcaps & IEEE80211_HTC_HT) && 1323193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_HT)) { 1324178354Ssam /* 1325178354Ssam * Device is HT-capable and HT is enabled for 1326178354Ssam * the vap; setup HT operation. On return 1327178354Ssam * ni_chan will be adjusted to an HT channel. 1328178354Ssam */ 1329178354Ssam ieee80211_ht_wds_init(ni); 1330178354Ssam } else { 1331178354Ssam struct ieee80211_channel *c = ni->ni_chan; 1332178354Ssam /* 1333178354Ssam * Force a legacy channel to be used. 1334178354Ssam */ 1335178354Ssam c = ieee80211_find_channel(ic, 1336178354Ssam c->ic_freq, c->ic_flags &~ IEEE80211_CHAN_HT); 1337178354Ssam KASSERT(c != NULL, ("no legacy channel, %u/%x", 1338178354Ssam ni->ni_chan->ic_freq, ni->ni_chan->ic_flags)); 1339178354Ssam ni->ni_chan = c; 1340178354Ssam } 1341178354Ssam } 1342178354Ssam return ni; 1343178354Ssam} 1344178354Ssam 1345178354Ssamstruct ieee80211_node * 1346138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1347178354Ssamieee80211_find_node_locked_debug(struct ieee80211_node_table *nt, 1348178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1349138568Ssam#else 1350178354Ssamieee80211_find_node_locked(struct ieee80211_node_table *nt, 1351178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1352138568Ssam#endif 1353116742Ssam{ 1354116742Ssam struct ieee80211_node *ni; 1355116742Ssam int hash; 1356116742Ssam 1357138568Ssam IEEE80211_NODE_LOCK_ASSERT(nt); 1358127772Ssam 1359195618Srpaulo hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr); 1360138568Ssam LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1361116742Ssam if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1362138568Ssam ieee80211_ref_node(ni); /* mark referenced */ 1363138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1364178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1365140766Ssam "%s (%s:%u) %p<%s> refcnt %d\n", __func__, 1366140766Ssam func, line, 1367140766Ssam ni, ether_sprintf(ni->ni_macaddr), 1368140766Ssam ieee80211_node_refcnt(ni)); 1369138568Ssam#endif 1370127772Ssam return ni; 1371116742Ssam } 1372116742Ssam } 1373127772Ssam return NULL; 1374127772Ssam} 1375178354Ssam 1376178354Ssamstruct ieee80211_node * 1377138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1378178354Ssamieee80211_find_node_debug(struct ieee80211_node_table *nt, 1379178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1380178354Ssam#else 1381178354Ssamieee80211_find_node(struct ieee80211_node_table *nt, 1382178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1383138568Ssam#endif 1384178354Ssam{ 1385178354Ssam struct ieee80211_node *ni; 1386127772Ssam 1387178354Ssam IEEE80211_NODE_LOCK(nt); 1388178354Ssam ni = ieee80211_find_node_locked(nt, macaddr); 1389178354Ssam IEEE80211_NODE_UNLOCK(nt); 1390178354Ssam return ni; 1391178354Ssam} 1392178354Ssam 1393127772Ssamstruct ieee80211_node * 1394138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1395178354Ssamieee80211_find_vap_node_locked_debug(struct ieee80211_node_table *nt, 1396178354Ssam const struct ieee80211vap *vap, 1397178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1398138568Ssam#else 1399178354Ssamieee80211_find_vap_node_locked(struct ieee80211_node_table *nt, 1400178354Ssam const struct ieee80211vap *vap, 1401178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1402138568Ssam#endif 1403127772Ssam{ 1404127772Ssam struct ieee80211_node *ni; 1405178354Ssam int hash; 1406127772Ssam 1407178354Ssam IEEE80211_NODE_LOCK_ASSERT(nt); 1408178354Ssam 1409195618Srpaulo hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr); 1410178354Ssam LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1411178354Ssam if (ni->ni_vap == vap && 1412178354Ssam IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1413178354Ssam ieee80211_ref_node(ni); /* mark referenced */ 1414178354Ssam#ifdef IEEE80211_DEBUG_REFCNT 1415178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1416178354Ssam "%s (%s:%u) %p<%s> refcnt %d\n", __func__, 1417178354Ssam func, line, 1418178354Ssam ni, ether_sprintf(ni->ni_macaddr), 1419178354Ssam ieee80211_node_refcnt(ni)); 1420178354Ssam#endif 1421178354Ssam return ni; 1422178354Ssam } 1423178354Ssam } 1424178354Ssam return NULL; 1425178354Ssam} 1426178354Ssam 1427178354Ssamstruct ieee80211_node * 1428178354Ssam#ifdef IEEE80211_DEBUG_REFCNT 1429178354Ssamieee80211_find_vap_node_debug(struct ieee80211_node_table *nt, 1430178354Ssam const struct ieee80211vap *vap, 1431178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1432178354Ssam#else 1433178354Ssamieee80211_find_vap_node(struct ieee80211_node_table *nt, 1434178354Ssam const struct ieee80211vap *vap, 1435178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1436178354Ssam#endif 1437178354Ssam{ 1438178354Ssam struct ieee80211_node *ni; 1439178354Ssam 1440138568Ssam IEEE80211_NODE_LOCK(nt); 1441178354Ssam ni = ieee80211_find_vap_node_locked(nt, vap, macaddr); 1442138568Ssam IEEE80211_NODE_UNLOCK(nt); 1443116742Ssam return ni; 1444116742Ssam} 1445116742Ssam 1446116742Ssam/* 1447138568Ssam * Fake up a node; this handles node discovery in adhoc mode. 1448138568Ssam * Note that for the driver's benefit we we treat this like 1449138568Ssam * an association so the driver has an opportunity to setup 1450138568Ssam * it's private state. 1451138568Ssam */ 1452138568Ssamstruct ieee80211_node * 1453178354Ssamieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, 1454170530Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1455138568Ssam{ 1456138568Ssam struct ieee80211_node *ni; 1457138568Ssam 1458245928Sadrian IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC, 1459153073Ssam "%s: mac<%s>\n", __func__, ether_sprintf(macaddr)); 1460178354Ssam ni = ieee80211_dup_bss(vap, macaddr); 1461138568Ssam if (ni != NULL) { 1462178354Ssam struct ieee80211com *ic = vap->iv_ic; 1463178354Ssam 1464138568Ssam /* XXX no rate negotiation; just dup */ 1465178354Ssam ni->ni_rates = vap->iv_bss->ni_rates; 1466188869Ssam if (ieee80211_iserp_rateset(&ni->ni_rates)) 1467188869Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 1468178354Ssam if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 1469153404Ssam /* 1470170530Ssam * In adhoc demo mode there are no management 1471170530Ssam * frames to use to discover neighbor capabilities, 1472170530Ssam * so blindly propagate the local configuration 1473170530Ssam * so we can do interesting things (e.g. use 1474170530Ssam * WME to disable ACK's). 1475153404Ssam */ 1476178354Ssam if (vap->iv_flags & IEEE80211_F_WME) 1477153404Ssam ni->ni_flags |= IEEE80211_NODE_QOS; 1478190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1479178354Ssam if (vap->iv_flags & IEEE80211_F_FF) 1480170530Ssam ni->ni_flags |= IEEE80211_NODE_FF; 1481190391Ssam#endif 1482153404Ssam } 1483193966Ssam ieee80211_node_setuptxparms(ni); 1484214894Sbschmidt ieee80211_ratectl_node_init(ni); 1485178354Ssam if (ic->ic_newassoc != NULL) 1486178354Ssam ic->ic_newassoc(ni, 1); 1487170530Ssam /* XXX not right for 802.1x/WPA */ 1488170530Ssam ieee80211_node_authorize(ni); 1489138568Ssam } 1490138568Ssam return ni; 1491138568Ssam} 1492138568Ssam 1493148936Ssamvoid 1494153073Ssamieee80211_init_neighbor(struct ieee80211_node *ni, 1495153073Ssam const struct ieee80211_frame *wh, 1496153073Ssam const struct ieee80211_scanparams *sp) 1497153073Ssam{ 1498245928Sadrian int do_ht_setup = 0; 1499245928Sadrian 1500153073Ssam ni->ni_esslen = sp->ssid[1]; 1501153073Ssam memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1502153073Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1503153073Ssam memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1504153073Ssam ni->ni_intval = sp->bintval; 1505153073Ssam ni->ni_capinfo = sp->capinfo; 1506153073Ssam ni->ni_chan = ni->ni_ic->ic_curchan; 1507153073Ssam ni->ni_fhdwell = sp->fhdwell; 1508153073Ssam ni->ni_fhindex = sp->fhindex; 1509153073Ssam ni->ni_erp = sp->erp; 1510153073Ssam ni->ni_timoff = sp->timoff; 1511195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 1512195618Srpaulo if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS) 1513195618Srpaulo ieee80211_mesh_init_neighbor(ni, wh, sp); 1514195618Srpaulo#endif 1515178354Ssam if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) { 1516178354Ssam ieee80211_ies_expand(&ni->ni_ies); 1517186659Ssam if (ni->ni_ies.wme_ie != NULL) 1518186659Ssam ni->ni_flags |= IEEE80211_NODE_QOS; 1519186659Ssam else 1520186659Ssam ni->ni_flags &= ~IEEE80211_NODE_QOS; 1521190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1522178354Ssam if (ni->ni_ies.ath_ie != NULL) 1523178354Ssam ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 1524190391Ssam#endif 1525245928Sadrian if (ni->ni_ies.htcap_ie != NULL) 1526245928Sadrian ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie); 1527245928Sadrian if (ni->ni_ies.htinfo_ie != NULL) 1528245928Sadrian ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie); 1529245928Sadrian 1530245928Sadrian if ((ni->ni_ies.htcap_ie != NULL) && 1531245928Sadrian (ni->ni_ies.htinfo_ie != NULL) && 1532245928Sadrian (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) { 1533245928Sadrian do_ht_setup = 1; 1534245928Sadrian } 1535178354Ssam } 1536178354Ssam 1537153073Ssam /* NB: must be after ni_chan is setup */ 1538165887Ssam ieee80211_setup_rates(ni, sp->rates, sp->xrates, 1539165887Ssam IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | 1540165887Ssam IEEE80211_F_DONEGO | IEEE80211_F_DODEL); 1541245928Sadrian 1542245928Sadrian /* 1543245928Sadrian * If the neighbor is HT compatible, flip that on. 1544245928Sadrian */ 1545245928Sadrian if (do_ht_setup) { 1546245928Sadrian IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 1547245928Sadrian "%s: doing HT setup\n", __func__); 1548245928Sadrian ieee80211_ht_node_init(ni); 1549245928Sadrian ieee80211_ht_updateparams(ni, 1550245928Sadrian ni->ni_ies.htcap_ie, 1551245928Sadrian ni->ni_ies.htinfo_ie); 1552245928Sadrian ieee80211_setup_htrates(ni, 1553245928Sadrian ni->ni_ies.htcap_ie, 1554245928Sadrian IEEE80211_F_JOIN | IEEE80211_F_DOBRS); 1555245928Sadrian ieee80211_setup_basic_htrates(ni, 1556245928Sadrian ni->ni_ies.htinfo_ie); 1557245928Sadrian ieee80211_node_setuptxparms(ni); 1558245928Sadrian ieee80211_ratectl_node_init(ni); 1559245928Sadrian } 1560153073Ssam} 1561153073Ssam 1562148936Ssam/* 1563148936Ssam * Do node discovery in adhoc mode on receipt of a beacon 1564148936Ssam * or probe response frame. Note that for the driver's 1565148936Ssam * benefit we we treat this like an association so the 1566148936Ssam * driver has an opportunity to setup it's private state. 1567148936Ssam */ 1568148936Ssamstruct ieee80211_node * 1569178354Ssamieee80211_add_neighbor(struct ieee80211vap *vap, 1570148936Ssam const struct ieee80211_frame *wh, 1571148936Ssam const struct ieee80211_scanparams *sp) 1572148936Ssam{ 1573148936Ssam struct ieee80211_node *ni; 1574148936Ssam 1575245928Sadrian IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 1576153073Ssam "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2)); 1577178354Ssam ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */ 1578148936Ssam if (ni != NULL) { 1579178354Ssam struct ieee80211com *ic = vap->iv_ic; 1580178354Ssam 1581153073Ssam ieee80211_init_neighbor(ni, wh, sp); 1582188869Ssam if (ieee80211_iserp_rateset(&ni->ni_rates)) 1583188869Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 1584193966Ssam ieee80211_node_setuptxparms(ni); 1585214894Sbschmidt ieee80211_ratectl_node_init(ni); 1586148936Ssam if (ic->ic_newassoc != NULL) 1587148936Ssam ic->ic_newassoc(ni, 1); 1588148936Ssam /* XXX not right for 802.1x/WPA */ 1589148936Ssam ieee80211_node_authorize(ni); 1590148936Ssam } 1591148936Ssam return ni; 1592148936Ssam} 1593148936Ssam 1594179220Ssam#define IS_PROBEREQ(wh) \ 1595179220Ssam ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) \ 1596179220Ssam == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ)) 1597179220Ssam#define IS_BCAST_PROBEREQ(wh) \ 1598179220Ssam (IS_PROBEREQ(wh) && IEEE80211_IS_MULTICAST( \ 1599179220Ssam ((const struct ieee80211_frame *)(wh))->i_addr3)) 1600170530Ssam 1601179220Ssamstatic __inline struct ieee80211_node * 1602179220Ssam_find_rxnode(struct ieee80211_node_table *nt, 1603179220Ssam const struct ieee80211_frame_min *wh) 1604179220Ssam{ 1605179220Ssam if (IS_BCAST_PROBEREQ(wh)) 1606179220Ssam return NULL; /* spam bcast probe req to all vap's */ 1607179220Ssam return ieee80211_find_node_locked(nt, wh->i_addr2); 1608179220Ssam} 1609179220Ssam 1610138568Ssam/* 1611138568Ssam * Locate the node for sender, track state, and then pass the 1612179220Ssam * (referenced) node up to the 802.11 layer for its use. Note 1613179220Ssam * we can return NULL if the sender is not in the table. 1614138568Ssam */ 1615138568Ssamstruct ieee80211_node * 1616138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1617138568Ssamieee80211_find_rxnode_debug(struct ieee80211com *ic, 1618138568Ssam const struct ieee80211_frame_min *wh, const char *func, int line) 1619138568Ssam#else 1620138568Ssamieee80211_find_rxnode(struct ieee80211com *ic, 1621138568Ssam const struct ieee80211_frame_min *wh) 1622138568Ssam#endif 1623138568Ssam{ 1624138568Ssam struct ieee80211_node_table *nt; 1625138568Ssam struct ieee80211_node *ni; 1626138568Ssam 1627170530Ssam nt = &ic->ic_sta; 1628138568Ssam IEEE80211_NODE_LOCK(nt); 1629179220Ssam ni = _find_rxnode(nt, wh); 1630138568Ssam IEEE80211_NODE_UNLOCK(nt); 1631138568Ssam 1632148863Ssam return ni; 1633148863Ssam} 1634148863Ssam 1635148863Ssam/* 1636148863Ssam * Like ieee80211_find_rxnode but use the supplied h/w 1637148863Ssam * key index as a hint to locate the node in the key 1638148863Ssam * mapping table. If an entry is present at the key 1639148863Ssam * index we return it; otherwise do a normal lookup and 1640148863Ssam * update the mapping table if the station has a unicast 1641148863Ssam * key assigned to it. 1642148863Ssam */ 1643148863Ssamstruct ieee80211_node * 1644148863Ssam#ifdef IEEE80211_DEBUG_REFCNT 1645148863Ssamieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1646148863Ssam const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1647148863Ssam const char *func, int line) 1648148863Ssam#else 1649148863Ssamieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1650148863Ssam const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1651148863Ssam#endif 1652148863Ssam{ 1653148863Ssam struct ieee80211_node_table *nt; 1654148863Ssam struct ieee80211_node *ni; 1655148863Ssam 1656170530Ssam nt = &ic->ic_sta; 1657148863Ssam IEEE80211_NODE_LOCK(nt); 1658148863Ssam if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1659148863Ssam ni = nt->nt_keyixmap[keyix]; 1660148863Ssam else 1661148863Ssam ni = NULL; 1662148863Ssam if (ni == NULL) { 1663179220Ssam ni = _find_rxnode(nt, wh); 1664178354Ssam if (ni != NULL && nt->nt_keyixmap != NULL) { 1665148863Ssam /* 1666148863Ssam * If the station has a unicast key cache slot 1667148863Ssam * assigned update the key->node mapping table. 1668148863Ssam */ 1669148863Ssam keyix = ni->ni_ucastkey.wk_rxkeyix; 1670148863Ssam /* XXX can keyixmap[keyix] != NULL? */ 1671148863Ssam if (keyix < nt->nt_keyixmax && 1672148863Ssam nt->nt_keyixmap[keyix] == NULL) { 1673178354Ssam IEEE80211_DPRINTF(ni->ni_vap, 1674178354Ssam IEEE80211_MSG_NODE, 1675148863Ssam "%s: add key map entry %p<%s> refcnt %d\n", 1676148863Ssam __func__, ni, ether_sprintf(ni->ni_macaddr), 1677148863Ssam ieee80211_node_refcnt(ni)+1); 1678148863Ssam nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1679148863Ssam } 1680148863Ssam } 1681179220Ssam } else { 1682179220Ssam if (IS_BCAST_PROBEREQ(wh)) 1683179220Ssam ni = NULL; /* spam bcast probe req to all vap's */ 1684179220Ssam else 1685179220Ssam ieee80211_ref_node(ni); 1686179220Ssam } 1687148863Ssam IEEE80211_NODE_UNLOCK(nt); 1688148863Ssam 1689148863Ssam return ni; 1690148863Ssam} 1691179220Ssam#undef IS_BCAST_PROBEREQ 1692179220Ssam#undef IS_PROBEREQ 1693138568Ssam 1694138568Ssam/* 1695127772Ssam * Return a reference to the appropriate node for sending 1696127772Ssam * a data frame. This handles node discovery in adhoc networks. 1697127772Ssam */ 1698127772Ssamstruct ieee80211_node * 1699138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1700178354Ssamieee80211_find_txnode_debug(struct ieee80211vap *vap, 1701178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN], 1702138568Ssam const char *func, int line) 1703138568Ssam#else 1704178354Ssamieee80211_find_txnode(struct ieee80211vap *vap, 1705178354Ssam const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1706138568Ssam#endif 1707127772Ssam{ 1708178354Ssam struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta; 1709127772Ssam struct ieee80211_node *ni; 1710127772Ssam 1711127772Ssam /* 1712127772Ssam * The destination address should be in the node table 1713148863Ssam * unless this is a multicast/broadcast frame. We can 1714148863Ssam * also optimize station mode operation, all frames go 1715148863Ssam * to the bss node. 1716127772Ssam */ 1717127772Ssam /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ 1718138568Ssam IEEE80211_NODE_LOCK(nt); 1719178354Ssam if (vap->iv_opmode == IEEE80211_M_STA || 1720178354Ssam vap->iv_opmode == IEEE80211_M_WDS || 1721178354Ssam IEEE80211_IS_MULTICAST(macaddr)) 1722178354Ssam ni = ieee80211_ref_node(vap->iv_bss); 1723186099Ssam else 1724178354Ssam ni = ieee80211_find_node_locked(nt, macaddr); 1725138568Ssam IEEE80211_NODE_UNLOCK(nt); 1726138568Ssam 1727138568Ssam if (ni == NULL) { 1728178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS || 1729178354Ssam vap->iv_opmode == IEEE80211_M_AHDEMO) { 1730140497Ssam /* 1731140497Ssam * In adhoc mode cons up a node for the destination. 1732140497Ssam * Note that we need an additional reference for the 1733178354Ssam * caller to be consistent with 1734178354Ssam * ieee80211_find_node_locked. 1735140497Ssam */ 1736178354Ssam ni = ieee80211_fakeup_adhoc_node(vap, macaddr); 1737140497Ssam if (ni != NULL) 1738140497Ssam (void) ieee80211_ref_node(ni); 1739140497Ssam } else { 1740178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, macaddr, 1741178354Ssam "no node, discard frame (%s)", __func__); 1742178354Ssam vap->iv_stats.is_tx_nonode++; 1743127772Ssam } 1744127772Ssam } 1745127772Ssam return ni; 1746127772Ssam} 1747127772Ssam 1748116742Ssamstatic void 1749138568Ssam_ieee80211_free_node(struct ieee80211_node *ni) 1750116742Ssam{ 1751138568Ssam struct ieee80211_node_table *nt = ni->ni_table; 1752119150Ssam 1753179641Ssam /* 1754179641Ssam * NB: careful about referencing the vap as it may be 1755179641Ssam * gone if the last reference was held by a driver. 1756179641Ssam * We know the com will always be present so it's safe 1757179641Ssam * to use ni_ic below to reclaim resources. 1758179641Ssam */ 1759179641Ssam#if 0 1760178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1761140766Ssam "%s %p<%s> in %s table\n", __func__, ni, 1762140766Ssam ether_sprintf(ni->ni_macaddr), 1763138568Ssam nt != NULL ? nt->nt_name : "<gone>"); 1764179641Ssam#endif 1765179641Ssam if (ni->ni_associd != 0) { 1766179641Ssam struct ieee80211vap *vap = ni->ni_vap; 1767179641Ssam if (vap->iv_aid_bitmap != NULL) 1768179641Ssam IEEE80211_AID_CLR(vap, ni->ni_associd); 1769179641Ssam } 1770138568Ssam if (nt != NULL) { 1771138568Ssam TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1772138568Ssam LIST_REMOVE(ni, ni_hash); 1773138568Ssam } 1774179641Ssam ni->ni_ic->ic_node_free(ni); 1775116742Ssam} 1776116742Ssam 1777282404Sadrian/* 1778282404Sadrian * Clear any entry in the unicast key mapping table. 1779282404Sadrian */ 1780282404Sadrianstatic int 1781282404Sadriannode_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1782282404Sadrian{ 1783282404Sadrian ieee80211_keyix keyix; 1784282404Sadrian 1785282404Sadrian keyix = ni->ni_ucastkey.wk_rxkeyix; 1786282404Sadrian if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1787282404Sadrian nt->nt_keyixmap[keyix] == ni) { 1788282404Sadrian IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1789282404Sadrian "%s: %p<%s> clear key map entry %u\n", 1790282404Sadrian __func__, ni, ether_sprintf(ni->ni_macaddr), keyix); 1791282404Sadrian nt->nt_keyixmap[keyix] = NULL; 1792282404Sadrian ieee80211_node_decref(ni); 1793282404Sadrian return 1; 1794282404Sadrian } 1795282404Sadrian 1796282404Sadrian return 0; 1797282404Sadrian} 1798282404Sadrian 1799116742Ssamvoid 1800138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1801138568Ssamieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1802138568Ssam#else 1803138568Ssamieee80211_free_node(struct ieee80211_node *ni) 1804138568Ssam#endif 1805116742Ssam{ 1806138568Ssam struct ieee80211_node_table *nt = ni->ni_table; 1807119150Ssam 1808138568Ssam#ifdef IEEE80211_DEBUG_REFCNT 1809178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1810140766Ssam "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni, 1811138568Ssam ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1); 1812138568Ssam#endif 1813148863Ssam if (nt != NULL) { 1814148863Ssam IEEE80211_NODE_LOCK(nt); 1815148863Ssam if (ieee80211_node_dectestref(ni)) { 1816148863Ssam /* 1817148863Ssam * Last reference, reclaim state. 1818148863Ssam */ 1819138568Ssam _ieee80211_free_node(ni); 1820282404Sadrian } else if (ieee80211_node_refcnt(ni) == 1) 1821282404Sadrian if (node_clear_keyixmap(nt, ni)) 1822148863Ssam _ieee80211_free_node(ni); 1823148863Ssam IEEE80211_NODE_UNLOCK(nt); 1824148863Ssam } else { 1825148863Ssam if (ieee80211_node_dectestref(ni)) 1826138568Ssam _ieee80211_free_node(ni); 1827116742Ssam } 1828116742Ssam} 1829116742Ssam 1830138568Ssam/* 1831148863Ssam * Reclaim a unicast key and clear any key cache state. 1832148863Ssam */ 1833148863Ssamint 1834148863Ssamieee80211_node_delucastkey(struct ieee80211_node *ni) 1835148863Ssam{ 1836179641Ssam struct ieee80211com *ic = ni->ni_ic; 1837179641Ssam struct ieee80211_node_table *nt = &ic->ic_sta; 1838148863Ssam struct ieee80211_node *nikey; 1839148863Ssam ieee80211_keyix keyix; 1840148863Ssam int isowned, status; 1841148863Ssam 1842148863Ssam /* 1843148863Ssam * NB: We must beware of LOR here; deleting the key 1844148863Ssam * can cause the crypto layer to block traffic updates 1845148863Ssam * which can generate a LOR against the node table lock; 1846148863Ssam * grab it here and stash the key index for our use below. 1847148863Ssam * 1848148863Ssam * Must also beware of recursion on the node table lock. 1849148863Ssam * When called from node_cleanup we may already have 1850148863Ssam * the node table lock held. Unfortunately there's no 1851148863Ssam * way to separate out this path so we must do this 1852148863Ssam * conditionally. 1853148863Ssam */ 1854148863Ssam isowned = IEEE80211_NODE_IS_LOCKED(nt); 1855148863Ssam if (!isowned) 1856148863Ssam IEEE80211_NODE_LOCK(nt); 1857179641Ssam nikey = NULL; 1858179641Ssam status = 1; /* NB: success */ 1859186144Ssam if (ni->ni_ucastkey.wk_keyix != IEEE80211_KEYIX_NONE) { 1860179641Ssam keyix = ni->ni_ucastkey.wk_rxkeyix; 1861179641Ssam status = ieee80211_crypto_delkey(ni->ni_vap, &ni->ni_ucastkey); 1862179641Ssam if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1863179641Ssam nikey = nt->nt_keyixmap[keyix]; 1864201758Smbr nt->nt_keyixmap[keyix] = NULL; 1865179641Ssam } 1866179641Ssam } 1867148863Ssam if (!isowned) 1868178354Ssam IEEE80211_NODE_UNLOCK(nt); 1869148863Ssam 1870148863Ssam if (nikey != NULL) { 1871148863Ssam KASSERT(nikey == ni, 1872148863Ssam ("key map out of sync, ni %p nikey %p", ni, nikey)); 1873179641Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1874148863Ssam "%s: delete key map entry %p<%s> refcnt %d\n", 1875148863Ssam __func__, ni, ether_sprintf(ni->ni_macaddr), 1876148863Ssam ieee80211_node_refcnt(ni)-1); 1877148863Ssam ieee80211_free_node(ni); 1878148863Ssam } 1879148863Ssam return status; 1880148863Ssam} 1881148863Ssam 1882148863Ssam/* 1883138568Ssam * Reclaim a node. If this is the last reference count then 1884138568Ssam * do the normal free work. Otherwise remove it from the node 1885138568Ssam * table and mark it gone by clearing the back-reference. 1886138568Ssam */ 1887138568Ssamstatic void 1888138568Ssamnode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1889116742Ssam{ 1890138568Ssam 1891148863Ssam IEEE80211_NODE_LOCK_ASSERT(nt); 1892148863Ssam 1893178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1894140766Ssam "%s: remove %p<%s> from %s table, refcnt %d\n", 1895140766Ssam __func__, ni, ether_sprintf(ni->ni_macaddr), 1896140766Ssam nt->nt_name, ieee80211_node_refcnt(ni)-1); 1897148863Ssam /* 1898148863Ssam * Clear any entry in the unicast key mapping table. 1899148863Ssam * We need to do it here so rx lookups don't find it 1900148863Ssam * in the mapping table even if it's not in the hash 1901148863Ssam * table. We cannot depend on the mapping table entry 1902148863Ssam * being cleared because the node may not be free'd. 1903148863Ssam */ 1904282404Sadrian (void)node_clear_keyixmap(nt, ni); 1905138568Ssam if (!ieee80211_node_dectestref(ni)) { 1906138568Ssam /* 1907138568Ssam * Other references are present, just remove the 1908138568Ssam * node from the table so it cannot be found. When 1909138568Ssam * the references are dropped storage will be 1910140753Ssam * reclaimed. 1911138568Ssam */ 1912138568Ssam TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1913138568Ssam LIST_REMOVE(ni, ni_hash); 1914138568Ssam ni->ni_table = NULL; /* clear reference */ 1915138568Ssam } else 1916138568Ssam _ieee80211_free_node(ni); 1917138568Ssam} 1918138568Ssam 1919178354Ssam/* 1920178354Ssam * Node table support. 1921178354Ssam */ 1922178354Ssam 1923178354Ssamstatic void 1924178354Ssamieee80211_node_table_init(struct ieee80211com *ic, 1925178354Ssam struct ieee80211_node_table *nt, 1926178354Ssam const char *name, int inact, int keyixmax) 1927178354Ssam{ 1928178354Ssam 1929178354Ssam nt->nt_ic = ic; 1930283529Sglebius IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name); 1931283529Sglebius IEEE80211_NODE_ITERATE_LOCK_INIT(nt, ic->ic_name); 1932178354Ssam TAILQ_INIT(&nt->nt_node); 1933178354Ssam nt->nt_name = name; 1934178354Ssam nt->nt_scangen = 1; 1935178354Ssam nt->nt_inact_init = inact; 1936178354Ssam nt->nt_keyixmax = keyixmax; 1937178354Ssam if (nt->nt_keyixmax > 0) { 1938283538Sadrian nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC( 1939184210Sdes keyixmax * sizeof(struct ieee80211_node *), 1940283538Sadrian M_80211_NODE, 1941283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 1942178354Ssam if (nt->nt_keyixmap == NULL) 1943283529Sglebius ic_printf(ic, 1944178354Ssam "Cannot allocate key index map with %u entries\n", 1945178354Ssam keyixmax); 1946178354Ssam } else 1947178354Ssam nt->nt_keyixmap = NULL; 1948178354Ssam} 1949178354Ssam 1950178354Ssamstatic void 1951178354Ssamieee80211_node_table_reset(struct ieee80211_node_table *nt, 1952178354Ssam struct ieee80211vap *match) 1953178354Ssam{ 1954178354Ssam struct ieee80211_node *ni, *next; 1955178354Ssam 1956178354Ssam IEEE80211_NODE_LOCK(nt); 1957178354Ssam TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) { 1958178354Ssam if (match != NULL && ni->ni_vap != match) 1959178354Ssam continue; 1960178354Ssam /* XXX can this happen? if so need's work */ 1961138568Ssam if (ni->ni_associd != 0) { 1962178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1963178354Ssam 1964178354Ssam if (vap->iv_auth->ia_node_leave != NULL) 1965178354Ssam vap->iv_auth->ia_node_leave(ni); 1966178354Ssam if (vap->iv_aid_bitmap != NULL) 1967178354Ssam IEEE80211_AID_CLR(vap, ni->ni_associd); 1968138568Ssam } 1969178354Ssam ni->ni_wdsvap = NULL; /* clear reference */ 1970138568Ssam node_reclaim(nt, ni); 1971138568Ssam } 1972178354Ssam if (match != NULL && match->iv_opmode == IEEE80211_M_WDS) { 1973178354Ssam /* 1974178354Ssam * Make a separate pass to clear references to this vap 1975178354Ssam * held by DWDS entries. They will not be matched above 1976178354Ssam * because ni_vap will point to the ap vap but we still 1977178354Ssam * need to clear ni_wdsvap when the WDS vap is destroyed 1978178354Ssam * and/or reset. 1979178354Ssam */ 1980178354Ssam TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) 1981178354Ssam if (ni->ni_wdsvap == match) 1982178354Ssam ni->ni_wdsvap = NULL; 1983178354Ssam } 1984178354Ssam IEEE80211_NODE_UNLOCK(nt); 1985116742Ssam} 1986116742Ssam 1987178354Ssamstatic void 1988178354Ssamieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 1989178354Ssam{ 1990178354Ssam ieee80211_node_table_reset(nt, NULL); 1991178354Ssam if (nt->nt_keyixmap != NULL) { 1992178354Ssam#ifdef DIAGNOSTIC 1993178354Ssam /* XXX verify all entries are NULL */ 1994178354Ssam int i; 1995178354Ssam for (i = 0; i < nt->nt_keyixmax; i++) 1996178354Ssam if (nt->nt_keyixmap[i] != NULL) 1997178354Ssam printf("%s: %s[%u] still active\n", __func__, 1998178354Ssam nt->nt_name, i); 1999178354Ssam#endif 2000283538Sadrian IEEE80211_FREE(nt->nt_keyixmap, M_80211_NODE); 2001178354Ssam nt->nt_keyixmap = NULL; 2002178354Ssam } 2003178354Ssam IEEE80211_NODE_ITERATE_LOCK_DESTROY(nt); 2004178354Ssam IEEE80211_NODE_LOCK_DESTROY(nt); 2005178354Ssam} 2006178354Ssam 2007120483Ssam/* 2008138568Ssam * Timeout inactive stations and do related housekeeping. 2009138568Ssam * Note that we cannot hold the node lock while sending a 2010138568Ssam * frame as this would lead to a LOR. Instead we use a 2011138568Ssam * generation number to mark nodes that we've scanned and 2012138568Ssam * drop the lock and restart a scan if we have to time out 2013138568Ssam * a node. Since we are single-threaded by virtue of 2014120483Ssam * controlling the inactivity timer we can be sure this will 2015120483Ssam * process each node only once. 2016120483Ssam */ 2017138568Ssamstatic void 2018178354Ssamieee80211_timeout_stations(struct ieee80211com *ic) 2019116742Ssam{ 2020178354Ssam struct ieee80211_node_table *nt = &ic->ic_sta; 2021178354Ssam struct ieee80211vap *vap; 2022120483Ssam struct ieee80211_node *ni; 2023178354Ssam int gen = 0; 2024116742Ssam 2025178354Ssam IEEE80211_NODE_ITERATE_LOCK(nt); 2026154532Ssam gen = ++nt->nt_scangen; 2027120483Ssamrestart: 2028138568Ssam IEEE80211_NODE_LOCK(nt); 2029138568Ssam TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2030120483Ssam if (ni->ni_scangen == gen) /* previously handled */ 2031120483Ssam continue; 2032120483Ssam ni->ni_scangen = gen; 2033138568Ssam /* 2034147788Ssam * Ignore entries for which have yet to receive an 2035147788Ssam * authentication frame. These are transient and 2036147788Ssam * will be reclaimed when the last reference to them 2037147788Ssam * goes away (when frame xmits complete). 2038147788Ssam */ 2039178354Ssam vap = ni->ni_vap; 2040178354Ssam /* 2041178354Ssam * Only process stations when in RUN state. This 2042178354Ssam * insures, for example, that we don't timeout an 2043178354Ssam * inactive station during CAC. Note that CSA state 2044178354Ssam * is actually handled in ieee80211_node_timeout as 2045178354Ssam * it applies to more than timeout processing. 2046178354Ssam */ 2047178354Ssam if (vap->iv_state != IEEE80211_S_RUN) 2048178354Ssam continue; 2049178354Ssam /* XXX can vap be NULL? */ 2050178354Ssam if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 2051178354Ssam vap->iv_opmode == IEEE80211_M_STA) && 2052148323Ssam (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 2053147788Ssam continue; 2054147788Ssam /* 2055138568Ssam * Free fragment if not needed anymore 2056138568Ssam * (last fragment older than 1s). 2057178354Ssam * XXX doesn't belong here, move to node_age 2058138568Ssam */ 2059138568Ssam if (ni->ni_rxfrag[0] != NULL && 2060138568Ssam ticks > ni->ni_rxfragstamp + hz) { 2061138568Ssam m_freem(ni->ni_rxfrag[0]); 2062138568Ssam ni->ni_rxfrag[0] = NULL; 2063138568Ssam } 2064184277Ssam if (ni->ni_inact > 0) { 2065172062Ssam ni->ni_inact--; 2066184277Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, 2067184277Ssam "%s: inact %u inact_reload %u nrates %u", 2068184277Ssam __func__, ni->ni_inact, ni->ni_inact_reload, 2069184277Ssam ni->ni_rates.rs_nrates); 2070184277Ssam } 2071140498Ssam /* 2072140498Ssam * Special case ourself; we may be idle for extended periods 2073140498Ssam * of time and regardless reclaiming our state is wrong. 2074178354Ssam * XXX run ic_node_age 2075140498Ssam */ 2076178354Ssam if (ni == vap->iv_bss) 2077140498Ssam continue; 2078178354Ssam if (ni->ni_associd != 0 || 2079178354Ssam (vap->iv_opmode == IEEE80211_M_IBSS || 2080178354Ssam vap->iv_opmode == IEEE80211_M_AHDEMO)) { 2081119150Ssam /* 2082178354Ssam * Age/drain resources held by the station. 2083138568Ssam */ 2084178354Ssam ic->ic_node_age(ni); 2085138568Ssam /* 2086138568Ssam * Probe the station before time it out. We 2087138568Ssam * send a null data frame which may not be 2088138568Ssam * universally supported by drivers (need it 2089138568Ssam * for ps-poll support so it should be...). 2090170530Ssam * 2091170530Ssam * XXX don't probe the station unless we've 2092170530Ssam * received a frame from them (and have 2093170530Ssam * some idea of the rates they are capable 2094170530Ssam * of); this will get fixed more properly 2095170530Ssam * soon with better handling of the rate set. 2096138568Ssam */ 2097178354Ssam if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 2098172062Ssam (0 < ni->ni_inact && 2099178354Ssam ni->ni_inact <= vap->iv_inact_probe) && 2100170530Ssam ni->ni_rates.rs_nrates != 0) { 2101178354Ssam IEEE80211_NOTE(vap, 2102148320Ssam IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 2103148320Ssam ni, "%s", 2104148320Ssam "probe station due to inactivity"); 2105148582Ssam /* 2106148582Ssam * Grab a reference before unlocking the table 2107148582Ssam * so the node cannot be reclaimed before we 2108148582Ssam * send the frame. ieee80211_send_nulldata 2109148582Ssam * understands we've done this and reclaims the 2110148582Ssam * ref for us as needed. 2111148582Ssam */ 2112148582Ssam ieee80211_ref_node(ni); 2113138568Ssam IEEE80211_NODE_UNLOCK(nt); 2114148301Ssam ieee80211_send_nulldata(ni); 2115138568Ssam /* XXX stat? */ 2116138568Ssam goto restart; 2117138568Ssam } 2118138568Ssam } 2119178354Ssam if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 2120172062Ssam ni->ni_inact <= 0) { 2121178354Ssam IEEE80211_NOTE(vap, 2122148320Ssam IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 2123148320Ssam "station timed out due to inactivity " 2124148320Ssam "(refcnt %u)", ieee80211_node_refcnt(ni)); 2125138568Ssam /* 2126138568Ssam * Send a deauthenticate frame and drop the station. 2127138568Ssam * This is somewhat complicated due to reference counts 2128138568Ssam * and locking. At this point a station will typically 2129138568Ssam * have a reference count of 1. ieee80211_node_leave 2130138568Ssam * will do a "free" of the node which will drop the 2131138568Ssam * reference count. But in the meantime a reference 2132138568Ssam * wil be held by the deauth frame. The actual reclaim 2133138568Ssam * of the node will happen either after the tx is 2134138568Ssam * completed or by ieee80211_node_leave. 2135120483Ssam * 2136138568Ssam * Separately we must drop the node lock before sending 2137170530Ssam * in case the driver takes a lock, as this can result 2138170530Ssam * in a LOR between the node lock and the driver lock. 2139119150Ssam */ 2140172229Ssam ieee80211_ref_node(ni); 2141138568Ssam IEEE80211_NODE_UNLOCK(nt); 2142138568Ssam if (ni->ni_associd != 0) { 2143178354Ssam IEEE80211_SEND_MGMT(ni, 2144138568Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 2145138568Ssam IEEE80211_REASON_AUTH_EXPIRE); 2146138568Ssam } 2147178354Ssam ieee80211_node_leave(ni); 2148172229Ssam ieee80211_free_node(ni); 2149178354Ssam vap->iv_stats.is_node_timeout++; 2150120483Ssam goto restart; 2151120483Ssam } 2152116742Ssam } 2153138568Ssam IEEE80211_NODE_UNLOCK(nt); 2154138568Ssam 2155178354Ssam IEEE80211_NODE_ITERATE_UNLOCK(nt); 2156170530Ssam} 2157138568Ssam 2158178354Ssam/* 2159178354Ssam * Aggressively reclaim resources. This should be used 2160178354Ssam * only in a critical situation to reclaim mbuf resources. 2161178354Ssam */ 2162170530Ssamvoid 2163178354Ssamieee80211_drain(struct ieee80211com *ic) 2164178354Ssam{ 2165178354Ssam struct ieee80211_node_table *nt = &ic->ic_sta; 2166178354Ssam struct ieee80211vap *vap; 2167178354Ssam struct ieee80211_node *ni; 2168178354Ssam 2169178354Ssam IEEE80211_NODE_LOCK(nt); 2170178354Ssam TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2171178354Ssam /* 2172178354Ssam * Ignore entries for which have yet to receive an 2173178354Ssam * authentication frame. These are transient and 2174178354Ssam * will be reclaimed when the last reference to them 2175178354Ssam * goes away (when frame xmits complete). 2176178354Ssam */ 2177178354Ssam vap = ni->ni_vap; 2178178354Ssam /* 2179178354Ssam * Only process stations when in RUN state. This 2180178354Ssam * insures, for example, that we don't timeout an 2181178354Ssam * inactive station during CAC. Note that CSA state 2182178354Ssam * is actually handled in ieee80211_node_timeout as 2183178354Ssam * it applies to more than timeout processing. 2184178354Ssam */ 2185178354Ssam if (vap->iv_state != IEEE80211_S_RUN) 2186178354Ssam continue; 2187178354Ssam /* XXX can vap be NULL? */ 2188178354Ssam if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 2189178354Ssam vap->iv_opmode == IEEE80211_M_STA) && 2190178354Ssam (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 2191178354Ssam continue; 2192178354Ssam /* 2193178354Ssam * Free fragments. 2194178354Ssam * XXX doesn't belong here, move to node_drain 2195178354Ssam */ 2196178354Ssam if (ni->ni_rxfrag[0] != NULL) { 2197178354Ssam m_freem(ni->ni_rxfrag[0]); 2198178354Ssam ni->ni_rxfrag[0] = NULL; 2199178354Ssam } 2200178354Ssam /* 2201178354Ssam * Drain resources held by the station. 2202178354Ssam */ 2203178354Ssam ic->ic_node_drain(ni); 2204178354Ssam } 2205178354Ssam IEEE80211_NODE_UNLOCK(nt); 2206178354Ssam} 2207178354Ssam 2208178354Ssam/* 2209178354Ssam * Per-ieee80211com inactivity timer callback. 2210178354Ssam */ 2211178354Ssamvoid 2212170530Ssamieee80211_node_timeout(void *arg) 2213170530Ssam{ 2214170530Ssam struct ieee80211com *ic = arg; 2215170530Ssam 2216178354Ssam /* 2217178354Ssam * Defer timeout processing if a channel switch is pending. 2218178354Ssam * We typically need to be mute so not doing things that 2219178354Ssam * might generate frames is good to handle in one place. 2220178354Ssam * Supressing the station timeout processing may extend the 2221178354Ssam * lifetime of inactive stations (by not decrementing their 2222178354Ssam * idle counters) but this should be ok unless the CSA is 2223178354Ssam * active for an unusually long time. 2224178354Ssam */ 2225178354Ssam if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) { 2226178354Ssam ieee80211_scan_timeout(ic); 2227178354Ssam ieee80211_timeout_stations(ic); 2228195379Ssam ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT); 2229170530Ssam 2230178354Ssam IEEE80211_LOCK(ic); 2231178354Ssam ieee80211_erp_timeout(ic); 2232178354Ssam ieee80211_ht_timeout(ic); 2233178354Ssam IEEE80211_UNLOCK(ic); 2234178354Ssam } 2235170530Ssam callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 2236170530Ssam ieee80211_node_timeout, ic); 2237116742Ssam} 2238116742Ssam 2239239312Sadrian/* 2240239312Sadrian * Iterate over the node table and return an array of ref'ed nodes. 2241239312Sadrian * 2242239312Sadrian * This is separated out from calling the actual node function so that 2243239312Sadrian * no LORs will occur. 2244239312Sadrian * 2245239312Sadrian * If there are too many nodes (ie, the number of nodes doesn't fit 2246239312Sadrian * within 'max_aid' entries) then the node references will be freed 2247239312Sadrian * and an error will be returned. 2248239312Sadrian * 2249239312Sadrian * The responsibility of allocating and freeing "ni_arr" is up to 2250239312Sadrian * the caller. 2251239312Sadrian */ 2252239312Sadrianint 2253239312Sadrianieee80211_iterate_nt(struct ieee80211_node_table *nt, 2254239312Sadrian struct ieee80211_node **ni_arr, uint16_t max_aid) 2255116742Ssam{ 2256239312Sadrian u_int gen; 2257239312Sadrian int i, j, ret; 2258116742Ssam struct ieee80211_node *ni; 2259116742Ssam 2260178354Ssam IEEE80211_NODE_ITERATE_LOCK(nt); 2261239312Sadrian IEEE80211_NODE_LOCK(nt); 2262239312Sadrian 2263154532Ssam gen = ++nt->nt_scangen; 2264239312Sadrian i = ret = 0; 2265239312Sadrian 2266239312Sadrian /* 2267239312Sadrian * We simply assume here that since the node 2268239312Sadrian * scan generation doesn't change (as 2269239312Sadrian * we are holding both the node table and 2270239312Sadrian * node table iteration locks), we can simply 2271239312Sadrian * assign it to the node here. 2272239312Sadrian */ 2273138568Ssam TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2274239312Sadrian if (i >= max_aid) { 2275239312Sadrian ret = E2BIG; 2276283529Sglebius ic_printf(nt->nt_ic, "Node array overflow: max=%u", 2277283529Sglebius max_aid); 2278239312Sadrian break; 2279138568Ssam } 2280239312Sadrian ni_arr[i] = ieee80211_ref_node(ni); 2281239312Sadrian ni_arr[i]->ni_scangen = gen; 2282239312Sadrian i++; 2283138568Ssam } 2284239312Sadrian 2285239312Sadrian /* 2286239312Sadrian * It's safe to unlock here. 2287239312Sadrian * 2288239312Sadrian * If we're successful, the list is returned. 2289239312Sadrian * If we're unsuccessful, the list is ignored 2290239312Sadrian * and we remove our references. 2291239312Sadrian * 2292239312Sadrian * This avoids any potential LOR with 2293239312Sadrian * ieee80211_free_node(). 2294239312Sadrian */ 2295138568Ssam IEEE80211_NODE_UNLOCK(nt); 2296239312Sadrian IEEE80211_NODE_ITERATE_UNLOCK(nt); 2297138568Ssam 2298239312Sadrian /* 2299239312Sadrian * If ret is non-zero, we hit some kind of error. 2300239312Sadrian * Rather than walking some nodes, we'll walk none 2301239312Sadrian * of them. 2302239312Sadrian */ 2303239312Sadrian if (ret) { 2304239312Sadrian for (j = 0; j < i; j++) { 2305239312Sadrian /* ieee80211_free_node() locks by itself */ 2306239312Sadrian ieee80211_free_node(ni_arr[j]); 2307239312Sadrian } 2308239312Sadrian } 2309239312Sadrian 2310239312Sadrian return (ret); 2311116742Ssam} 2312138568Ssam 2313239312Sadrian/* 2314239312Sadrian * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes() 2315239312Sadrian * reference in the source. 2316239312Sadrian * 2317239312Sadrian * Note that this fetches 'max_aid' from the first VAP, rather than finding 2318239312Sadrian * the largest max_aid from all VAPs. 2319239312Sadrian */ 2320138568Ssamvoid 2321239312Sadrianieee80211_iterate_nodes(struct ieee80211_node_table *nt, 2322239312Sadrian ieee80211_iter_func *f, void *arg) 2323239312Sadrian{ 2324239312Sadrian struct ieee80211_node **ni_arr; 2325239319Sadrian size_t size; 2326239312Sadrian int i; 2327239312Sadrian uint16_t max_aid; 2328240574Sadrian struct ieee80211vap *vap; 2329239312Sadrian 2330240574Sadrian /* Overdoing it default */ 2331240574Sadrian max_aid = IEEE80211_AID_MAX; 2332240574Sadrian 2333240574Sadrian /* Handle the case of there being no vaps just yet */ 2334240574Sadrian vap = TAILQ_FIRST(&nt->nt_ic->ic_vaps); 2335240574Sadrian if (vap != NULL) 2336240574Sadrian max_aid = vap->iv_max_aid; 2337240574Sadrian 2338239312Sadrian size = max_aid * sizeof(struct ieee80211_node *); 2339283538Sadrian ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE, 2340283538Sadrian IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 2341239312Sadrian if (ni_arr == NULL) 2342239312Sadrian return; 2343239312Sadrian 2344239312Sadrian /* 2345239312Sadrian * If this fails, the node table won't have any 2346239312Sadrian * valid entries - ieee80211_iterate_nt() frees 2347239312Sadrian * the references to them. So don't try walking 2348239312Sadrian * the table; just skip to the end and free the 2349239312Sadrian * temporary memory. 2350239312Sadrian */ 2351239319Sadrian if (ieee80211_iterate_nt(nt, ni_arr, max_aid) != 0) 2352239312Sadrian goto done; 2353239312Sadrian 2354239312Sadrian for (i = 0; i < max_aid; i++) { 2355239312Sadrian if (ni_arr[i] == NULL) /* end of the list */ 2356239312Sadrian break; 2357239312Sadrian (*f)(arg, ni_arr[i]); 2358239312Sadrian /* ieee80211_free_node() locks by itself */ 2359239312Sadrian ieee80211_free_node(ni_arr[i]); 2360239312Sadrian } 2361239312Sadrian 2362239312Sadriandone: 2363283538Sadrian IEEE80211_FREE(ni_arr, M_80211_NODE); 2364239312Sadrian} 2365239312Sadrian 2366239312Sadrianvoid 2367138568Ssamieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 2368138568Ssam{ 2369138568Ssam printf("0x%p: mac %s refcnt %d\n", ni, 2370138568Ssam ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); 2371138568Ssam printf("\tscangen %u authmode %u flags 0x%x\n", 2372138568Ssam ni->ni_scangen, ni->ni_authmode, ni->ni_flags); 2373138568Ssam printf("\tassocid 0x%x txpower %u vlan %u\n", 2374138568Ssam ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 2375138568Ssam printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 2376167439Ssam ni->ni_txseqs[IEEE80211_NONQOS_TID], 2377167439Ssam ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT, 2378167439Ssam ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK, 2379138568Ssam ni->ni_rxfragstamp); 2380192468Ssam printf("\trssi %d noise %d intval %u capinfo 0x%x\n", 2381192468Ssam node_getrssi(ni), ni->ni_noise, 2382170530Ssam ni->ni_intval, ni->ni_capinfo); 2383138568Ssam printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n", 2384138568Ssam ether_sprintf(ni->ni_bssid), 2385138568Ssam ni->ni_esslen, ni->ni_essid, 2386138568Ssam ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 2387184277Ssam printf("\tinact %u inact_reload %u txrate %u\n", 2388184277Ssam ni->ni_inact, ni->ni_inact_reload, ni->ni_txrate); 2389170530Ssam printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n", 2390170530Ssam ni->ni_htcap, ni->ni_htparam, 2391170530Ssam ni->ni_htctlchan, ni->ni_ht2ndchan); 2392170530Ssam printf("\thtopmode %x htstbc %x chw %u\n", 2393170530Ssam ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw); 2394138568Ssam} 2395138568Ssam 2396138568Ssamvoid 2397138568Ssamieee80211_dump_nodes(struct ieee80211_node_table *nt) 2398138568Ssam{ 2399138568Ssam ieee80211_iterate_nodes(nt, 2400138568Ssam (ieee80211_iter_func *) ieee80211_dump_node, nt); 2401138568Ssam} 2402138568Ssam 2403179642Ssamstatic void 2404179642Ssamieee80211_notify_erp_locked(struct ieee80211com *ic) 2405172211Ssam{ 2406178354Ssam struct ieee80211vap *vap; 2407178354Ssam 2408178354Ssam IEEE80211_LOCK_ASSERT(ic); 2409178354Ssam 2410178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 2411178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2412178354Ssam ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP); 2413172211Ssam} 2414172211Ssam 2415179642Ssamvoid 2416179642Ssamieee80211_notify_erp(struct ieee80211com *ic) 2417179642Ssam{ 2418179642Ssam IEEE80211_LOCK(ic); 2419179642Ssam ieee80211_notify_erp_locked(ic); 2420179642Ssam IEEE80211_UNLOCK(ic); 2421179642Ssam} 2422179642Ssam 2423138568Ssam/* 2424138568Ssam * Handle a station joining an 11g network. 2425138568Ssam */ 2426138568Ssamstatic void 2427178354Ssamieee80211_node_join_11g(struct ieee80211_node *ni) 2428138568Ssam{ 2429178354Ssam struct ieee80211com *ic = ni->ni_ic; 2430138568Ssam 2431173273Ssam IEEE80211_LOCK_ASSERT(ic); 2432173273Ssam 2433138568Ssam /* 2434138568Ssam * Station isn't capable of short slot time. Bump 2435138568Ssam * the count of long slot time stations and disable 2436138568Ssam * use of short slot time. Note that the actual switch 2437138568Ssam * over to long slot time use may not occur until the 2438138568Ssam * next beacon transmission (per sec. 7.3.1.4 of 11g). 2439138568Ssam */ 2440138568Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2441138568Ssam ic->ic_longslotsta++; 2442178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2443172211Ssam "station needs long slot time, count %d", 2444172211Ssam ic->ic_longslotsta); 2445138568Ssam /* XXX vap's w/ conflicting needs won't work */ 2446170530Ssam if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) { 2447170530Ssam /* 2448170530Ssam * Don't force slot time when switched to turbo 2449170530Ssam * mode as non-ERP stations won't be present; this 2450170530Ssam * need only be done when on the normal G channel. 2451170530Ssam */ 2452170530Ssam ieee80211_set_shortslottime(ic, 0); 2453170530Ssam } 2454138568Ssam } 2455138568Ssam /* 2456138568Ssam * If the new station is not an ERP station 2457138568Ssam * then bump the counter and enable protection 2458138568Ssam * if configured. 2459138568Ssam */ 2460178354Ssam if (!ieee80211_iserp_rateset(&ni->ni_rates)) { 2461138568Ssam ic->ic_nonerpsta++; 2462178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2463172211Ssam "station is !ERP, %d non-ERP stations associated", 2464172211Ssam ic->ic_nonerpsta); 2465138568Ssam /* 2466138568Ssam * If station does not support short preamble 2467138568Ssam * then we must enable use of Barker preamble. 2468138568Ssam */ 2469138568Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 2470178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2471172211Ssam "%s", "station needs long preamble"); 2472138568Ssam ic->ic_flags |= IEEE80211_F_USEBARKER; 2473138568Ssam ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 2474138568Ssam } 2475172211Ssam /* 2476178354Ssam * If protection is configured and this is the first 2477178354Ssam * indication we should use protection, enable it. 2478172211Ssam */ 2479172211Ssam if (ic->ic_protmode != IEEE80211_PROT_NONE && 2480172211Ssam ic->ic_nonerpsta == 1 && 2481172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 2482178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2483172211Ssam "%s: enable use of protection\n", __func__); 2484172211Ssam ic->ic_flags |= IEEE80211_F_USEPROT; 2485179642Ssam ieee80211_notify_erp_locked(ic); 2486172211Ssam } 2487138568Ssam } else 2488138568Ssam ni->ni_flags |= IEEE80211_NODE_ERP; 2489138568Ssam} 2490138568Ssam 2491138568Ssamvoid 2492178354Ssamieee80211_node_join(struct ieee80211_node *ni, int resp) 2493138568Ssam{ 2494178354Ssam struct ieee80211com *ic = ni->ni_ic; 2495178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2496138568Ssam int newassoc; 2497138568Ssam 2498138568Ssam if (ni->ni_associd == 0) { 2499170530Ssam uint16_t aid; 2500138568Ssam 2501178354Ssam KASSERT(vap->iv_aid_bitmap != NULL, ("no aid bitmap")); 2502138568Ssam /* 2503138568Ssam * It would be good to search the bitmap 2504138568Ssam * more efficiently, but this will do for now. 2505138568Ssam */ 2506178354Ssam for (aid = 1; aid < vap->iv_max_aid; aid++) { 2507178354Ssam if (!IEEE80211_AID_ISSET(vap, aid)) 2508138568Ssam break; 2509138568Ssam } 2510178354Ssam if (aid >= vap->iv_max_aid) { 2511179640Ssam IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_TOOMANY); 2512178354Ssam ieee80211_node_leave(ni); 2513138568Ssam return; 2514138568Ssam } 2515138568Ssam ni->ni_associd = aid | 0xc000; 2516173273Ssam ni->ni_jointime = time_uptime; 2517178354Ssam IEEE80211_LOCK(ic); 2518178354Ssam IEEE80211_AID_SET(vap, ni->ni_associd); 2519178354Ssam vap->iv_sta_assoc++; 2520138568Ssam ic->ic_sta_assoc++; 2521173273Ssam 2522173273Ssam if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 2523173273Ssam ieee80211_ht_node_join(ni); 2524170530Ssam if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 2525170530Ssam IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 2526178354Ssam ieee80211_node_join_11g(ni); 2527173273Ssam IEEE80211_UNLOCK(ic); 2528173273Ssam 2529173273Ssam newassoc = 1; 2530138568Ssam } else 2531138568Ssam newassoc = 0; 2532138568Ssam 2533178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 2534183256Ssam "station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s", 2535139523Ssam IEEE80211_NODE_AID(ni), 2536139523Ssam ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2537139523Ssam ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2538139523Ssam ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2539170530Ssam ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "", 2540170530Ssam ni->ni_flags & IEEE80211_NODE_HT ? 2541182834Ssam (ni->ni_chw == 40 ? ", HT40" : ", HT20") : "", 2542173273Ssam ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "", 2543183255Ssam ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" : 2544183255Ssam ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "", 2545183256Ssam ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "", 2546178354Ssam IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ? 2547170530Ssam ", fast-frames" : "", 2548178354Ssam IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ? 2549170530Ssam ", turbo" : "" 2550139523Ssam ); 2551138568Ssam 2552193966Ssam ieee80211_node_setuptxparms(ni); 2553214894Sbschmidt ieee80211_ratectl_node_init(ni); 2554138568Ssam /* give driver a chance to setup state like ni_txrate */ 2555139524Ssam if (ic->ic_newassoc != NULL) 2556148307Ssam ic->ic_newassoc(ni, newassoc); 2557178354Ssam IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_SUCCESS); 2558138568Ssam /* tell the authenticator about new station */ 2559178354Ssam if (vap->iv_auth->ia_node_join != NULL) 2560178354Ssam vap->iv_auth->ia_node_join(ni); 2561178354Ssam ieee80211_notify_node_join(ni, 2562173866Ssam resp == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 2563138568Ssam} 2564138568Ssam 2565172211Ssamstatic void 2566172211Ssamdisable_protection(struct ieee80211com *ic) 2567172211Ssam{ 2568172211Ssam KASSERT(ic->ic_nonerpsta == 0 && 2569172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0, 2570172211Ssam ("%d non ERP stations, flags 0x%x", ic->ic_nonerpsta, 2571172211Ssam ic->ic_flags_ext)); 2572172211Ssam 2573172211Ssam ic->ic_flags &= ~IEEE80211_F_USEPROT; 2574172211Ssam /* XXX verify mode? */ 2575172211Ssam if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2576172211Ssam ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 2577172211Ssam ic->ic_flags &= ~IEEE80211_F_USEBARKER; 2578172211Ssam } 2579179642Ssam ieee80211_notify_erp_locked(ic); 2580172211Ssam} 2581172211Ssam 2582138568Ssam/* 2583138568Ssam * Handle a station leaving an 11g network. 2584138568Ssam */ 2585138568Ssamstatic void 2586178354Ssamieee80211_node_leave_11g(struct ieee80211_node *ni) 2587138568Ssam{ 2588178354Ssam struct ieee80211com *ic = ni->ni_ic; 2589138568Ssam 2590173273Ssam IEEE80211_LOCK_ASSERT(ic); 2591173273Ssam 2592170530Ssam KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan), 2593178354Ssam ("not in 11g, bss %u:0x%x", ic->ic_bsschan->ic_freq, 2594178354Ssam ic->ic_bsschan->ic_flags)); 2595138568Ssam 2596138568Ssam /* 2597138568Ssam * If a long slot station do the slot time bookkeeping. 2598138568Ssam */ 2599138568Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2600138568Ssam KASSERT(ic->ic_longslotsta > 0, 2601138568Ssam ("bogus long slot station count %d", ic->ic_longslotsta)); 2602138568Ssam ic->ic_longslotsta--; 2603178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2604172211Ssam "long slot time station leaves, count now %d", 2605172211Ssam ic->ic_longslotsta); 2606138568Ssam if (ic->ic_longslotsta == 0) { 2607138568Ssam /* 2608138568Ssam * Re-enable use of short slot time if supported 2609138568Ssam * and not operating in IBSS mode (per spec). 2610138568Ssam */ 2611138568Ssam if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2612138568Ssam ic->ic_opmode != IEEE80211_M_IBSS) { 2613178354Ssam IEEE80211_DPRINTF(ni->ni_vap, 2614178354Ssam IEEE80211_MSG_ASSOC, 2615138568Ssam "%s: re-enable use of short slot time\n", 2616138568Ssam __func__); 2617138568Ssam ieee80211_set_shortslottime(ic, 1); 2618138568Ssam } 2619138568Ssam } 2620138568Ssam } 2621138568Ssam /* 2622138568Ssam * If a non-ERP station do the protection-related bookkeeping. 2623138568Ssam */ 2624138568Ssam if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2625138568Ssam KASSERT(ic->ic_nonerpsta > 0, 2626138568Ssam ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2627138568Ssam ic->ic_nonerpsta--; 2628178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2629172211Ssam "non-ERP station leaves, count now %d%s", ic->ic_nonerpsta, 2630172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) ? 2631172211Ssam " (non-ERP sta present)" : ""); 2632172211Ssam if (ic->ic_nonerpsta == 0 && 2633172211Ssam (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 2634178354Ssam IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2635138568Ssam "%s: disable use of protection\n", __func__); 2636172211Ssam disable_protection(ic); 2637138568Ssam } 2638138568Ssam } 2639138568Ssam} 2640138568Ssam 2641138568Ssam/* 2642172211Ssam * Time out presence of an overlapping bss with non-ERP 2643172211Ssam * stations. When operating in hostap mode we listen for 2644172211Ssam * beacons from other stations and if we identify a non-ERP 2645172211Ssam * station is present we enable protection. To identify 2646172211Ssam * when all non-ERP stations are gone we time out this 2647172211Ssam * condition. 2648172211Ssam */ 2649172211Ssamstatic void 2650172211Ssamieee80211_erp_timeout(struct ieee80211com *ic) 2651172211Ssam{ 2652172211Ssam 2653172211Ssam IEEE80211_LOCK_ASSERT(ic); 2654172211Ssam 2655172211Ssam if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) && 2656297405Sadrian ieee80211_time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) { 2657178354Ssam#if 0 2658178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2659178354Ssam "%s", "age out non-ERP sta present on channel"); 2660178354Ssam#endif 2661172211Ssam ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR; 2662172211Ssam if (ic->ic_nonerpsta == 0) 2663172211Ssam disable_protection(ic); 2664172211Ssam } 2665172211Ssam} 2666172211Ssam 2667172211Ssam/* 2668138568Ssam * Handle bookkeeping for station deauthentication/disassociation 2669138568Ssam * when operating as an ap. 2670138568Ssam */ 2671138568Ssamvoid 2672178354Ssamieee80211_node_leave(struct ieee80211_node *ni) 2673138568Ssam{ 2674178354Ssam struct ieee80211com *ic = ni->ni_ic; 2675178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2676140499Ssam struct ieee80211_node_table *nt = ni->ni_table; 2677138568Ssam 2678178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 2679172211Ssam "station with aid %d leaves", IEEE80211_NODE_AID(ni)); 2680138568Ssam 2681178354Ssam KASSERT(vap->iv_opmode != IEEE80211_M_STA, 2682178354Ssam ("unexpected operating mode %u", vap->iv_opmode)); 2683138568Ssam /* 2684138568Ssam * If node wasn't previously associated all 2685138568Ssam * we need to do is reclaim the reference. 2686138568Ssam */ 2687138568Ssam /* XXX ibss mode bypasses 11g and notification */ 2688138568Ssam if (ni->ni_associd == 0) 2689138568Ssam goto done; 2690138568Ssam /* 2691138568Ssam * Tell the authenticator the station is leaving. 2692138568Ssam * Note that we must do this before yanking the 2693138568Ssam * association id as the authenticator uses the 2694138568Ssam * associd to locate it's state block. 2695138568Ssam */ 2696178354Ssam if (vap->iv_auth->ia_node_leave != NULL) 2697178354Ssam vap->iv_auth->ia_node_leave(ni); 2698173273Ssam 2699173273Ssam IEEE80211_LOCK(ic); 2700178354Ssam IEEE80211_AID_CLR(vap, ni->ni_associd); 2701178354Ssam vap->iv_sta_assoc--; 2702138568Ssam ic->ic_sta_assoc--; 2703138568Ssam 2704173273Ssam if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 2705173273Ssam ieee80211_ht_node_leave(ni); 2706170530Ssam if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 2707170530Ssam IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 2708178354Ssam ieee80211_node_leave_11g(ni); 2709173273Ssam IEEE80211_UNLOCK(ic); 2710138568Ssam /* 2711138568Ssam * Cleanup station state. In particular clear various 2712138568Ssam * state that might otherwise be reused if the node 2713138568Ssam * is reused before the reference count goes to zero 2714138568Ssam * (and memory is reclaimed). 2715138568Ssam */ 2716178354Ssam ieee80211_sta_leave(ni); 2717138568Ssamdone: 2718140499Ssam /* 2719140499Ssam * Remove the node from any table it's recorded in and 2720140499Ssam * drop the caller's reference. Removal from the table 2721140499Ssam * is important to insure the node is not reprocessed 2722140499Ssam * for inactivity. 2723140499Ssam */ 2724140499Ssam if (nt != NULL) { 2725140499Ssam IEEE80211_NODE_LOCK(nt); 2726140499Ssam node_reclaim(nt, ni); 2727140499Ssam IEEE80211_NODE_UNLOCK(nt); 2728140499Ssam } else 2729140499Ssam ieee80211_free_node(ni); 2730138568Ssam} 2731138568Ssam 2732178354Ssamstruct rssiinfo { 2733178354Ssam struct ieee80211vap *vap; 2734178354Ssam int rssi_samples; 2735178354Ssam uint32_t rssi_total; 2736178354Ssam}; 2737178354Ssam 2738178354Ssamstatic void 2739178354Ssamget_hostap_rssi(void *arg, struct ieee80211_node *ni) 2740178354Ssam{ 2741178354Ssam struct rssiinfo *info = arg; 2742178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2743178354Ssam int8_t rssi; 2744178354Ssam 2745178354Ssam if (info->vap != vap) 2746178354Ssam return; 2747178354Ssam /* only associated stations */ 2748178354Ssam if (ni->ni_associd == 0) 2749178354Ssam return; 2750178354Ssam rssi = vap->iv_ic->ic_node_getrssi(ni); 2751178354Ssam if (rssi != 0) { 2752178354Ssam info->rssi_samples++; 2753178354Ssam info->rssi_total += rssi; 2754178354Ssam } 2755178354Ssam} 2756178354Ssam 2757178354Ssamstatic void 2758178354Ssamget_adhoc_rssi(void *arg, struct ieee80211_node *ni) 2759178354Ssam{ 2760178354Ssam struct rssiinfo *info = arg; 2761178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2762178354Ssam int8_t rssi; 2763178354Ssam 2764178354Ssam if (info->vap != vap) 2765178354Ssam return; 2766178354Ssam /* only neighbors */ 2767178354Ssam /* XXX check bssid */ 2768178354Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 2769178354Ssam return; 2770178354Ssam rssi = vap->iv_ic->ic_node_getrssi(ni); 2771178354Ssam if (rssi != 0) { 2772178354Ssam info->rssi_samples++; 2773178354Ssam info->rssi_total += rssi; 2774178354Ssam } 2775178354Ssam} 2776178354Ssam 2777195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 2778195618Srpaulostatic void 2779195618Srpauloget_mesh_rssi(void *arg, struct ieee80211_node *ni) 2780195618Srpaulo{ 2781195618Srpaulo struct rssiinfo *info = arg; 2782195618Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2783195618Srpaulo int8_t rssi; 2784195618Srpaulo 2785195618Srpaulo if (info->vap != vap) 2786195618Srpaulo return; 2787195618Srpaulo /* only neighbors that peered successfully */ 2788195618Srpaulo if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 2789195618Srpaulo return; 2790195618Srpaulo rssi = vap->iv_ic->ic_node_getrssi(ni); 2791195618Srpaulo if (rssi != 0) { 2792195618Srpaulo info->rssi_samples++; 2793195618Srpaulo info->rssi_total += rssi; 2794195618Srpaulo } 2795195618Srpaulo} 2796195618Srpaulo#endif /* IEEE80211_SUPPORT_MESH */ 2797195618Srpaulo 2798170530Ssamint8_t 2799178354Ssamieee80211_getrssi(struct ieee80211vap *vap) 2800138568Ssam{ 2801138568Ssam#define NZ(x) ((x) == 0 ? 1 : (x)) 2802178354Ssam struct ieee80211com *ic = vap->iv_ic; 2803178354Ssam struct rssiinfo info; 2804138568Ssam 2805178354Ssam info.rssi_total = 0; 2806178354Ssam info.rssi_samples = 0; 2807178354Ssam info.vap = vap; 2808178354Ssam switch (vap->iv_opmode) { 2809138568Ssam case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2810138568Ssam case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2811178354Ssam ieee80211_iterate_nodes(&ic->ic_sta, get_adhoc_rssi, &info); 2812178354Ssam break; 2813138568Ssam case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2814178354Ssam ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info); 2815138568Ssam break; 2816195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 2817195618Srpaulo case IEEE80211_M_MBSS: /* average of all mesh neighbors */ 2818195618Srpaulo ieee80211_iterate_nodes(&ic->ic_sta, get_mesh_rssi, &info); 2819195618Srpaulo break; 2820195618Srpaulo#endif 2821138568Ssam case IEEE80211_M_MONITOR: /* XXX */ 2822138568Ssam case IEEE80211_M_STA: /* use stats from associated ap */ 2823138568Ssam default: 2824178354Ssam if (vap->iv_bss != NULL) 2825178354Ssam info.rssi_total = ic->ic_node_getrssi(vap->iv_bss); 2826178354Ssam info.rssi_samples = 1; 2827138568Ssam break; 2828138568Ssam } 2829178354Ssam return info.rssi_total / NZ(info.rssi_samples); 2830138568Ssam#undef NZ 2831138568Ssam} 2832138568Ssam 2833170530Ssamvoid 2834178354Ssamieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise) 2835138568Ssam{ 2836138568Ssam 2837178354Ssam if (vap->iv_bss == NULL) /* NB: shouldn't happen */ 2838170530Ssam return; 2839178354Ssam vap->iv_ic->ic_node_getsignal(vap->iv_bss, rssi, noise); 2840170530Ssam /* for non-station mode return avg'd rssi accounting */ 2841178354Ssam if (vap->iv_opmode != IEEE80211_M_STA) 2842178354Ssam *rssi = ieee80211_getrssi(vap); 2843138568Ssam} 2844