ieee80211_node.c revision 179220
1331766Sken/*- 2331766Sken * Copyright (c) 2001 Atsushi Onoe 3331766Sken * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 4331766Sken * All rights reserved. 5331766Sken * 6331766Sken * Redistribution and use in source and binary forms, with or without 7331766Sken * modification, are permitted provided that the following conditions 8331766Sken * are met: 9331766Sken * 1. Redistributions of source code must retain the above copyright 10331766Sken * notice, this list of conditions and the following disclaimer. 11331766Sken * 2. Redistributions in binary form must reproduce the above copyright 12331766Sken * notice, this list of conditions and the following disclaimer in the 13331766Sken * documentation and/or other materials provided with the distribution. 14331766Sken * 15331766Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16331766Sken * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17331766Sken * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18331766Sken * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19331766Sken * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20331766Sken * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21331766Sken * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22331766Sken * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23331766Sken * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24331766Sken * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25331766Sken */ 26331766Sken 27331766Sken#include <sys/cdefs.h> 28331766Sken__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_node.c 179220 2008-05-22 22:22:10Z sam $"); 29331766Sken 30331766Sken#include "opt_wlan.h" 31331766Sken 32331766Sken#include <sys/param.h> 33331766Sken#include <sys/systm.h> 34331766Sken#include <sys/mbuf.h> 35331766Sken#include <sys/malloc.h> 36331766Sken#include <sys/kernel.h> 37331766Sken 38331766Sken#include <sys/socket.h> 39331766Sken 40331766Sken#include <net/if.h> 41331766Sken#include <net/if_media.h> 42331766Sken#include <net/ethernet.h> 43331766Sken 44331766Sken#include <net80211/ieee80211_var.h> 45331766Sken#include <net80211/ieee80211_input.h> 46331766Sken#include <net80211/ieee80211_wds.h> 47331766Sken 48331766Sken#include <net/bpf.h> 49331766Sken 50331766Sken/* 51331766Sken * Association id's are managed with a bit vector. 52331766Sken */ 53331766Sken#define IEEE80211_AID_SET(_vap, b) \ 54331766Sken ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] |= \ 55331766Sken (1 << (IEEE80211_AID(b) % 32))) 56331766Sken#define IEEE80211_AID_CLR(_vap, b) \ 57331766Sken ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] &= \ 58331766Sken ~(1 << (IEEE80211_AID(b) % 32))) 59331766Sken#define IEEE80211_AID_ISSET(_vap, b) \ 60331766Sken ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32))) 61331766Sken 62331766Sken#ifdef IEEE80211_DEBUG_REFCNT 63331766Sken#define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line 64331766Sken#else 65331766Sken#define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__ 66331766Sken#endif 67331766Sken 68331766Skenstatic int ieee80211_sta_join1(struct ieee80211_node *); 69331766Sken 70331766Skenstatic struct ieee80211_node *node_alloc(struct ieee80211_node_table *); 71331766Skenstatic void node_cleanup(struct ieee80211_node *); 72331766Skenstatic void node_free(struct ieee80211_node *); 73331766Skenstatic void node_age(struct ieee80211_node *); 74331766Skenstatic int8_t node_getrssi(const struct ieee80211_node *); 75331766Skenstatic void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *); 76331766Skenstatic void node_getmimoinfo(const struct ieee80211_node *, 77331766Sken struct ieee80211_mimo_info *); 78331766Sken 79331766Skenstatic void _ieee80211_free_node(struct ieee80211_node *); 80331766Sken 81331766Skenstatic void ieee80211_node_table_init(struct ieee80211com *ic, 82331766Sken struct ieee80211_node_table *nt, const char *name, 83331766Sken int inact, int keymaxix); 84331766Skenstatic void ieee80211_node_table_reset(struct ieee80211_node_table *, 85331766Sken struct ieee80211vap *); 86331766Skenstatic void ieee80211_node_reclaim(struct ieee80211_node *); 87331766Skenstatic void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 88331766Skenstatic void ieee80211_erp_timeout(struct ieee80211com *); 89331766Sken 90331766SkenMALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 91331766SkenMALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie"); 92331766Sken 93331766Skenvoid 94331766Skenieee80211_node_attach(struct ieee80211com *ic) 95331766Sken{ 96331766Sken ieee80211_node_table_init(ic, &ic->ic_sta, "station", 97331766Sken IEEE80211_INACT_INIT, ic->ic_max_keyix); 98331766Sken callout_init(&ic->ic_inact, CALLOUT_MPSAFE); 99331766Sken callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 100331766Sken ieee80211_node_timeout, ic); 101331766Sken 102331766Sken ic->ic_node_alloc = node_alloc; 103331766Sken ic->ic_node_free = node_free; 104331766Sken ic->ic_node_cleanup = node_cleanup; 105331766Sken ic->ic_node_age = node_age; 106331766Sken ic->ic_node_drain = node_age; /* NB: same as age */ 107331766Sken ic->ic_node_getrssi = node_getrssi; 108331766Sken ic->ic_node_getsignal = node_getsignal; 109331766Sken ic->ic_node_getmimoinfo = node_getmimoinfo; 110331766Sken 111331766Sken /* 112331766Sken * Set flags to be propagated to all vap's; 113331766Sken * these define default behaviour/configuration. 114331766Sken */ 115331766Sken ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */ 116331766Sken} 117331766Sken 118331766Skenvoid 119331766Skenieee80211_node_detach(struct ieee80211com *ic) 120331766Sken{ 121331766Sken 122331766Sken callout_drain(&ic->ic_inact); 123331766Sken ieee80211_node_table_cleanup(&ic->ic_sta); 124331766Sken} 125331766Sken 126331766Skenvoid 127331766Skenieee80211_node_vattach(struct ieee80211vap *vap) 128331766Sken{ 129331766Sken /* NB: driver can override */ 130331766Sken vap->iv_max_aid = IEEE80211_AID_DEF; 131331766Sken 132331766Sken /* default station inactivity timer setings */ 133331766Sken vap->iv_inact_init = IEEE80211_INACT_INIT; 134331766Sken vap->iv_inact_auth = IEEE80211_INACT_AUTH; 135331766Sken vap->iv_inact_run = IEEE80211_INACT_RUN; 136331766Sken vap->iv_inact_probe = IEEE80211_INACT_PROBE; 137331766Sken} 138331766Sken 139331766Skenvoid 140331766Skenieee80211_node_latevattach(struct ieee80211vap *vap) 141331766Sken{ 142331766Sken if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 143331766Sken /* XXX should we allow max aid to be zero? */ 144331766Sken if (vap->iv_max_aid < IEEE80211_AID_MIN) { 145331766Sken vap->iv_max_aid = IEEE80211_AID_MIN; 146331766Sken if_printf(vap->iv_ifp, 147331766Sken "WARNING: max aid too small, changed to %d\n", 148331766Sken vap->iv_max_aid); 149331766Sken } 150331766Sken MALLOC(vap->iv_aid_bitmap, uint32_t *, 151331766Sken howmany(vap->iv_max_aid, 32) * sizeof(uint32_t), 152331766Sken M_80211_NODE, M_NOWAIT | M_ZERO); 153331766Sken if (vap->iv_aid_bitmap == NULL) { 154331766Sken /* XXX no way to recover */ 155331766Sken printf("%s: no memory for AID bitmap, max aid %d!\n", 156331766Sken __func__, vap->iv_max_aid); 157331766Sken vap->iv_max_aid = 0; 158331766Sken } 159331766Sken } 160331766Sken 161331766Sken ieee80211_reset_bss(vap); 162331766Sken 163331766Sken vap->iv_auth = ieee80211_authenticator_get(vap->iv_bss->ni_authmode); 164331766Sken} 165331766Sken 166331766Skenvoid 167331766Skenieee80211_node_vdetach(struct ieee80211vap *vap) 168331766Sken{ 169331766Sken struct ieee80211com *ic = vap->iv_ic; 170331766Sken 171331766Sken ieee80211_node_table_reset(&ic->ic_sta, vap); 172331766Sken if (vap->iv_bss != NULL) { 173331766Sken ieee80211_free_node(vap->iv_bss); 174331766Sken vap->iv_bss = NULL; 175331766Sken } 176331766Sken if (vap->iv_aid_bitmap != NULL) { 177331766Sken FREE(vap->iv_aid_bitmap, M_80211_NODE); 178331766Sken vap->iv_aid_bitmap = NULL; 179331766Sken } 180331766Sken} 181331766Sken 182331766Sken/* 183331766Sken * Port authorize/unauthorize interfaces for use by an authenticator. 184331766Sken */ 185331766Sken 186331766Skenvoid 187331766Skenieee80211_node_authorize(struct ieee80211_node *ni) 188331766Sken{ 189331766Sken ni->ni_flags |= IEEE80211_NODE_AUTH; 190331766Sken ni->ni_inact_reload = ni->ni_vap->iv_inact_run; 191331766Sken ni->ni_inact = ni->ni_inact_reload; 192331766Sken} 193331766Sken 194331766Skenvoid 195331766Skenieee80211_node_unauthorize(struct ieee80211_node *ni) 196331766Sken{ 197331766Sken ni->ni_flags &= ~IEEE80211_NODE_AUTH; 198331766Sken ni->ni_inact_reload = ni->ni_vap->iv_inact_auth; 199331766Sken if (ni->ni_inact > ni->ni_inact_reload) 200331766Sken ni->ni_inact = ni->ni_inact_reload; 201331766Sken} 202331766Sken 203331766Sken/* 204331766Sken * Set/change the channel. The rate set is also updated as 205331766Sken * to insure a consistent view by drivers. 206331766Sken * XXX should be private but hostap needs it to deal with CSA 207331766Sken */ 208331766Skenvoid 209331766Skenieee80211_node_set_chan(struct ieee80211_node *ni, 210331766Sken struct ieee80211_channel *chan) 211331766Sken{ 212331766Sken struct ieee80211com *ic = ni->ni_ic; 213331766Sken 214331766Sken KASSERT(chan != IEEE80211_CHAN_ANYC, ("no channel")); 215331766Sken 216331766Sken ni->ni_chan = chan; 217331766Sken if (IEEE80211_IS_CHAN_HT(chan)) { 218331766Sken /* 219331766Sken * XXX Gotta be careful here; the rate set returned by 220331766Sken * ieee80211_get_suprates is actually any HT rate 221331766Sken * set so blindly copying it will be bad. We must 222331766Sken * install the legacy rate est in ni_rates and the 223331766Sken * HT rate set in ni_htrates. 224331766Sken */ 225331766Sken ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); 226331766Sken } 227331766Sken ni->ni_rates = *ieee80211_get_suprates(ic, chan); 228331766Sken} 229331766Sken 230331766Skenstatic __inline void 231331766Skencopy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 232331766Sken{ 233331766Sken /* propagate useful state */ 234331766Sken nbss->ni_authmode = obss->ni_authmode; 235331766Sken nbss->ni_txpower = obss->ni_txpower; 236331766Sken nbss->ni_vlan = obss->ni_vlan; 237331766Sken /* XXX statistics? */ 238331766Sken /* XXX legacy WDS bssid? */ 239331766Sken} 240331766Sken 241331766Skenvoid 242331766Skenieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan) 243331766Sken{ 244331766Sken struct ieee80211com *ic = vap->iv_ic; 245331766Sken struct ieee80211_node *ni; 246331766Sken 247331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, 248331766Sken "%s: creating ibss on channel %u\n", __func__, 249331766Sken ieee80211_chan2ieee(ic, chan)); 250331766Sken 251331766Sken ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 252331766Sken if (ni == NULL) { 253331766Sken /* XXX recovery? */ 254331766Sken return; 255331766Sken } 256331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 257331766Sken ni->ni_esslen = vap->iv_des_ssid[0].len; 258331766Sken memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 259331766Sken if (vap->iv_bss != NULL) 260331766Sken copy_bss(ni, vap->iv_bss); 261331766Sken ni->ni_intval = ic->ic_bintval; 262331766Sken if (vap->iv_flags & IEEE80211_F_PRIVACY) 263331766Sken ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 264331766Sken if (ic->ic_phytype == IEEE80211_T_FH) { 265331766Sken ni->ni_fhdwell = 200; /* XXX */ 266331766Sken ni->ni_fhindex = 1; 267331766Sken } 268331766Sken if (vap->iv_opmode == IEEE80211_M_IBSS) { 269331766Sken vap->iv_flags |= IEEE80211_F_SIBSS; 270331766Sken ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 271331766Sken if (vap->iv_flags & IEEE80211_F_DESBSSID) 272331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 273331766Sken else { 274331766Sken get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN); 275331766Sken /* clear group bit, add local bit */ 276331766Sken ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02; 277331766Sken } 278331766Sken } else if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 279331766Sken if (vap->iv_flags & IEEE80211_F_DESBSSID) 280331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid); 281331766Sken else 282331766Sken memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 283331766Sken } 284331766Sken /* 285331766Sken * Fix the channel and related attributes. 286331766Sken */ 287331766Sken /* clear DFS CAC state on previous channel */ 288331766Sken if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && 289331766Sken ic->ic_bsschan->ic_freq != chan->ic_freq && 290331766Sken IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) 291331766Sken ieee80211_dfs_cac_clear(ic, ic->ic_bsschan); 292331766Sken ic->ic_bsschan = chan; 293331766Sken ieee80211_node_set_chan(ni, chan); 294331766Sken ic->ic_curmode = ieee80211_chan2mode(chan); 295331766Sken /* 296331766Sken * Do mode-specific setup. 297331766Sken */ 298331766Sken if (IEEE80211_IS_CHAN_FULL(chan)) { 299331766Sken if (IEEE80211_IS_CHAN_ANYG(chan)) { 300331766Sken /* 301331766Sken * Use a mixed 11b/11g basic rate set. 302331766Sken */ 303331766Sken ieee80211_setbasicrates(&ni->ni_rates, 304331766Sken IEEE80211_MODE_11G); 305331766Sken if (vap->iv_flags & IEEE80211_F_PUREG) { 306331766Sken /* 307331766Sken * Also mark OFDM rates basic so 11b 308331766Sken * stations do not join (WiFi compliance). 309331766Sken */ 310331766Sken ieee80211_addbasicrates(&ni->ni_rates, 311331766Sken IEEE80211_MODE_11A); 312331766Sken } 313331766Sken } else if (IEEE80211_IS_CHAN_B(chan)) { 314331766Sken /* 315331766Sken * Force pure 11b rate set. 316331766Sken */ 317331766Sken ieee80211_setbasicrates(&ni->ni_rates, 318331766Sken IEEE80211_MODE_11B); 319331766Sken } 320331766Sken } 321331766Sken 322331766Sken (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); 323331766Sken} 324331766Sken 325331766Sken/* 326331766Sken * Reset bss state on transition to the INIT state. 327331766Sken * Clear any stations from the table (they have been 328331766Sken * deauth'd) and reset the bss node (clears key, rate 329331766Sken * etc. state). 330331766Sken */ 331331766Skenvoid 332331766Skenieee80211_reset_bss(struct ieee80211vap *vap) 333331766Sken{ 334331766Sken struct ieee80211com *ic = vap->iv_ic; 335331766Sken struct ieee80211_node *ni, *obss; 336331766Sken 337331766Sken ieee80211_node_table_reset(&ic->ic_sta, vap); 338331766Sken /* XXX multi-bss: wrong */ 339331766Sken ieee80211_reset_erp(ic); 340331766Sken 341331766Sken ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); 342331766Sken KASSERT(ni != NULL, ("unable to setup inital BSS node")); 343331766Sken obss = vap->iv_bss; 344331766Sken vap->iv_bss = ieee80211_ref_node(ni); 345331766Sken if (obss != NULL) { 346331766Sken copy_bss(ni, obss); 347331766Sken ni->ni_intval = ic->ic_bintval; 348331766Sken ieee80211_free_node(obss); 349331766Sken } else 350331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); 351331766Sken} 352331766Sken 353331766Skenstatic int 354331766Skenmatch_ssid(const struct ieee80211_node *ni, 355331766Sken int nssid, const struct ieee80211_scan_ssid ssids[]) 356331766Sken{ 357331766Sken int i; 358331766Sken 359331766Sken for (i = 0; i < nssid; i++) { 360331766Sken if (ni->ni_esslen == ssids[i].len && 361331766Sken memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0) 362331766Sken return 1; 363331766Sken } 364331766Sken return 0; 365331766Sken} 366331766Sken 367331766Sken/* 368331766Sken * Test a node for suitability/compatibility. 369331766Sken */ 370331766Skenstatic int 371331766Skencheck_bss(struct ieee80211vap *vap, struct ieee80211_node *ni) 372331766Sken{ 373331766Sken struct ieee80211com *ic = ni->ni_ic; 374331766Sken uint8_t rate; 375331766Sken 376331766Sken if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 377331766Sken return 0; 378331766Sken if (vap->iv_opmode == IEEE80211_M_IBSS) { 379331766Sken if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 380331766Sken return 0; 381331766Sken } else { 382331766Sken if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 383331766Sken return 0; 384331766Sken } 385331766Sken if (vap->iv_flags & IEEE80211_F_PRIVACY) { 386331766Sken if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 387331766Sken return 0; 388331766Sken } else { 389331766Sken /* XXX does this mean privacy is supported or required? */ 390331766Sken if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 391331766Sken return 0; 392331766Sken } 393331766Sken rate = ieee80211_fix_rate(ni, &ni->ni_rates, 394331766Sken IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 395331766Sken if (rate & IEEE80211_RATE_BASIC) 396331766Sken return 0; 397331766Sken if (vap->iv_des_nssid != 0 && 398331766Sken !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 399331766Sken return 0; 400331766Sken if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 401331766Sken !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 402331766Sken return 0; 403331766Sken return 1; 404331766Sken} 405331766Sken 406331766Sken#ifdef IEEE80211_DEBUG 407331766Sken/* 408331766Sken * Display node suitability/compatibility. 409331766Sken */ 410331766Skenstatic void 411331766Skencheck_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni) 412331766Sken{ 413331766Sken struct ieee80211com *ic = ni->ni_ic; 414331766Sken uint8_t rate; 415331766Sken int fail; 416331766Sken 417331766Sken fail = 0; 418331766Sken if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 419331766Sken fail |= 0x01; 420331766Sken if (vap->iv_opmode == IEEE80211_M_IBSS) { 421331766Sken if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 422331766Sken fail |= 0x02; 423331766Sken } else { 424331766Sken if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 425331766Sken fail |= 0x02; 426331766Sken } 427331766Sken if (vap->iv_flags & IEEE80211_F_PRIVACY) { 428331766Sken if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 429331766Sken fail |= 0x04; 430331766Sken } else { 431331766Sken /* XXX does this mean privacy is supported or required? */ 432331766Sken if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 433331766Sken fail |= 0x04; 434331766Sken } 435331766Sken rate = ieee80211_fix_rate(ni, &ni->ni_rates, 436331766Sken IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 437331766Sken if (rate & IEEE80211_RATE_BASIC) 438331766Sken fail |= 0x08; 439331766Sken if (vap->iv_des_nssid != 0 && 440331766Sken !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) 441331766Sken fail |= 0x10; 442331766Sken if ((vap->iv_flags & IEEE80211_F_DESBSSID) && 443331766Sken !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) 444331766Sken fail |= 0x20; 445331766Sken 446331766Sken printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); 447331766Sken printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); 448331766Sken printf(" %3d%c", 449331766Sken ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); 450331766Sken printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 451331766Sken fail & 0x08 ? '!' : ' '); 452331766Sken printf(" %4s%c", 453331766Sken (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 454331766Sken (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 455331766Sken "????", 456331766Sken fail & 0x02 ? '!' : ' '); 457331766Sken printf(" %3s%c ", 458331766Sken (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no", 459331766Sken fail & 0x04 ? '!' : ' '); 460331766Sken ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 461331766Sken printf("%s\n", fail & 0x10 ? "!" : ""); 462331766Sken} 463331766Sken#endif /* IEEE80211_DEBUG */ 464331766Sken 465331766Sken/* 466331766Sken * Handle 802.11 ad hoc network merge. The 467331766Sken * convention, set by the Wireless Ethernet Compatibility Alliance 468331766Sken * (WECA), is that an 802.11 station will change its BSSID to match 469331766Sken * the "oldest" 802.11 ad hoc network, on the same channel, that 470331766Sken * has the station's desired SSID. The "oldest" 802.11 network 471331766Sken * sends beacons with the greatest TSF timestamp. 472331766Sken * 473331766Sken * The caller is assumed to validate TSF's before attempting a merge. 474331766Sken * 475331766Sken * Return !0 if the BSSID changed, 0 otherwise. 476331766Sken */ 477331766Skenint 478331766Skenieee80211_ibss_merge(struct ieee80211_node *ni) 479331766Sken{ 480331766Sken struct ieee80211vap *vap = ni->ni_vap; 481331766Sken#ifdef IEEE80211_DEBUG 482331766Sken struct ieee80211com *ic = ni->ni_ic; 483331766Sken#endif 484331766Sken 485331766Sken if (ni == vap->iv_bss || 486331766Sken IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { 487331766Sken /* unchanged, nothing to do */ 488331766Sken return 0; 489331766Sken } 490331766Sken if (!check_bss(vap, ni)) { 491331766Sken /* capabilities mismatch */ 492331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 493331766Sken "%s: merge failed, capabilities mismatch\n", __func__); 494331766Sken#ifdef IEEE80211_DEBUG 495331766Sken if (ieee80211_msg_assoc(vap)) 496331766Sken check_bss_debug(vap, ni); 497331766Sken#endif 498331766Sken vap->iv_stats.is_ibss_capmismatch++; 499331766Sken return 0; 500331766Sken } 501331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, 502331766Sken "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__, 503331766Sken ether_sprintf(ni->ni_bssid), 504331766Sken ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 505331766Sken ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 506331766Sken ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 507331766Sken ); 508331766Sken return ieee80211_sta_join1(ieee80211_ref_node(ni)); 509331766Sken} 510331766Sken 511331766Sken/* 512331766Sken * Calculate HT channel promotion flags for all vaps. 513331766Sken * This assumes ni_chan have been setup for each vap. 514331766Sken */ 515331766Skenstatic int 516331766Skengethtadjustflags(struct ieee80211com *ic) 517331766Sken{ 518331766Sken struct ieee80211vap *vap; 519331766Sken int flags; 520331766Sken 521331766Sken flags = 0; 522331766Sken /* XXX locking */ 523331766Sken TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 524331766Sken if (vap->iv_state < IEEE80211_S_RUN) 525331766Sken continue; 526331766Sken switch (vap->iv_opmode) { 527331766Sken case IEEE80211_M_WDS: 528331766Sken case IEEE80211_M_STA: 529331766Sken case IEEE80211_M_AHDEMO: 530331766Sken case IEEE80211_M_HOSTAP: 531331766Sken case IEEE80211_M_IBSS: 532331766Sken flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan); 533331766Sken break; 534331766Sken default: 535331766Sken break; 536331766Sken } 537331766Sken } 538331766Sken return flags; 539331766Sken} 540331766Sken 541331766Sken/* 542331766Sken * Check if the current channel needs to change based on whether 543331766Sken * any vap's are using HT20/HT40. This is used sync the state of 544331766Sken * ic_curchan after a channel width change on a running vap. 545331766Sken */ 546331766Skenvoid 547331766Skenieee80211_sync_curchan(struct ieee80211com *ic) 548331766Sken{ 549331766Sken struct ieee80211_channel *c; 550331766Sken 551331766Sken c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic)); 552331766Sken if (c != ic->ic_curchan) { 553331766Sken ic->ic_curchan = c; 554331766Sken ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 555331766Sken ic->ic_set_channel(ic); 556331766Sken } 557331766Sken} 558331766Sken 559331766Sken/* 560331766Sken * Change the current channel. The request channel may be 561331766Sken * promoted if other vap's are operating with HT20/HT40. 562331766Sken */ 563331766Skenvoid 564331766Skenieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c) 565331766Sken{ 566331766Sken if (ic->ic_htcaps & IEEE80211_HTC_HT) { 567331766Sken int flags = gethtadjustflags(ic); 568331766Sken /* 569331766Sken * Check for channel promotion required to support the 570331766Sken * set of running vap's. This assumes we are called 571331766Sken * after ni_chan is setup for each vap. 572331766Sken */ 573331766Sken /* NB: this assumes IEEE80211_FEXT_USEHT40 > IEEE80211_FEXT_HT */ 574331766Sken if (flags > ieee80211_htchanflags(c)) 575331766Sken c = ieee80211_ht_adjust_channel(ic, c, flags); 576331766Sken } 577331766Sken ic->ic_bsschan = ic->ic_curchan = c; 578331766Sken ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); 579331766Sken ic->ic_set_channel(ic); 580331766Sken} 581331766Sken 582331766Sken/* 583331766Sken * Join the specified IBSS/BSS network. The node is assumed to 584331766Sken * be passed in with a held reference. 585331766Sken */ 586331766Skenstatic int 587331766Skenieee80211_sta_join1(struct ieee80211_node *selbs) 588331766Sken{ 589331766Sken struct ieee80211vap *vap = selbs->ni_vap; 590331766Sken struct ieee80211com *ic = selbs->ni_ic; 591331766Sken struct ieee80211_node *obss; 592331766Sken int canreassoc; 593331766Sken 594331766Sken /* 595331766Sken * Committed to selbs, setup state. 596331766Sken */ 597331766Sken obss = vap->iv_bss; 598331766Sken /* 599331766Sken * Check if old+new node have the same address in which 600331766Sken * case we can reassociate when operating in sta mode. 601331766Sken */ 602331766Sken canreassoc = (obss != NULL && 603331766Sken vap->iv_state == IEEE80211_S_RUN && 604331766Sken IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr)); 605331766Sken vap->iv_bss = selbs; /* NB: caller assumed to bump refcnt */ 606331766Sken if (obss != NULL) { 607331766Sken copy_bss(selbs, obss); 608331766Sken ieee80211_node_reclaim(obss); 609331766Sken obss = NULL; /* NB: guard against later use */ 610331766Sken } 611331766Sken 612331766Sken /* 613331766Sken * Delete unusable rates; we've already checked 614331766Sken * that the negotiated rate set is acceptable. 615331766Sken */ 616331766Sken ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates, 617331766Sken IEEE80211_F_DODEL | IEEE80211_F_JOIN); 618331766Sken 619331766Sken ieee80211_setcurchan(ic, selbs->ni_chan); 620331766Sken /* 621331766Sken * Set the erp state (mostly the slot time) to deal with 622331766Sken * the auto-select case; this should be redundant if the 623331766Sken * mode is locked. 624331766Sken */ 625331766Sken ieee80211_reset_erp(ic); 626331766Sken ieee80211_wme_initparams(vap); 627331766Sken 628331766Sken if (vap->iv_opmode == IEEE80211_M_STA) { 629331766Sken if (canreassoc) { 630331766Sken /* Reassociate */ 631331766Sken ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1); 632331766Sken } else { 633331766Sken /* 634331766Sken * Act as if we received a DEAUTH frame in case we 635331766Sken * are invoked from the RUN state. This will cause 636331766Sken * us to try to re-authenticate if we are operating 637331766Sken * as a station. 638331766Sken */ 639331766Sken ieee80211_new_state(vap, IEEE80211_S_AUTH, 640331766Sken IEEE80211_FC0_SUBTYPE_DEAUTH); 641331766Sken } 642331766Sken } else 643331766Sken ieee80211_new_state(vap, IEEE80211_S_RUN, -1); 644331766Sken return 1; 645331766Sken} 646331766Sken 647331766Skenint 648331766Skenieee80211_sta_join(struct ieee80211vap *vap, 649331766Sken const struct ieee80211_scan_entry *se) 650331766Sken{ 651331766Sken struct ieee80211com *ic = vap->iv_ic; 652331766Sken struct ieee80211_node *ni; 653331766Sken 654331766Sken ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr); 655331766Sken if (ni == NULL) { 656331766Sken /* XXX msg */ 657331766Sken return 0; 658331766Sken } 659331766Sken /* 660331766Sken * Expand scan state into node's format. 661331766Sken * XXX may not need all this stuff 662331766Sken */ 663331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid); 664331766Sken ni->ni_esslen = se->se_ssid[1]; 665331766Sken memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen); 666331766Sken ni->ni_rstamp = se->se_rstamp; 667331766Sken ni->ni_tstamp.tsf = se->se_tstamp.tsf; 668331766Sken ni->ni_intval = se->se_intval; 669331766Sken ni->ni_capinfo = se->se_capinfo; 670331766Sken ni->ni_chan = se->se_chan; 671331766Sken ni->ni_timoff = se->se_timoff; 672331766Sken ni->ni_fhdwell = se->se_fhdwell; 673331766Sken ni->ni_fhindex = se->se_fhindex; 674331766Sken ni->ni_erp = se->se_erp; 675331766Sken IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi); 676331766Sken ni->ni_noise = se->se_noise; 677331766Sken 678331766Sken if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) { 679331766Sken ieee80211_ies_expand(&ni->ni_ies); 680331766Sken if (ni->ni_ies.ath_ie != NULL) 681331766Sken ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 682331766Sken if (ni->ni_ies.htcap_ie != NULL) 683331766Sken ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie); 684331766Sken if (ni->ni_ies.htinfo_ie != NULL) 685331766Sken ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie); 686331766Sken } 687331766Sken 688331766Sken vap->iv_dtim_period = se->se_dtimperiod; 689331766Sken vap->iv_dtim_count = 0; 690331766Sken 691331766Sken /* NB: must be after ni_chan is setup */ 692331766Sken ieee80211_setup_rates(ni, se->se_rates, se->se_xrates, 693331766Sken IEEE80211_F_DOSORT); 694331766Sken 695331766Sken return ieee80211_sta_join1(ieee80211_ref_node(ni)); 696331766Sken} 697331766Sken 698331766Sken/* 699331766Sken * Leave the specified IBSS/BSS network. The node is assumed to 700331766Sken * be passed in with a held reference. 701331766Sken */ 702331766Skenvoid 703331766Skenieee80211_sta_leave(struct ieee80211_node *ni) 704331766Sken{ 705331766Sken struct ieee80211com *ic = ni->ni_ic; 706331766Sken 707331766Sken ic->ic_node_cleanup(ni); 708331766Sken ieee80211_notify_node_leave(ni); 709331766Sken} 710331766Sken 711331766Sken/* 712331766Sken * Send a deauthenticate frame and drop the station. 713331766Sken */ 714331766Skenvoid 715331766Skenieee80211_node_deauth(struct ieee80211_node *ni, int reason) 716331766Sken{ 717331766Sken /* NB: bump the refcnt to be sure temporay nodes are not reclaimed */ 718331766Sken ieee80211_ref_node(ni); 719331766Sken if (ni->ni_associd != 0) 720331766Sken IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); 721331766Sken ieee80211_node_leave(ni); 722331766Sken ieee80211_free_node(ni); 723331766Sken} 724331766Sken 725331766Skenstatic struct ieee80211_node * 726331766Skennode_alloc(struct ieee80211_node_table *nt) 727331766Sken{ 728331766Sken struct ieee80211_node *ni; 729331766Sken 730331766Sken MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node), 731331766Sken M_80211_NODE, M_NOWAIT | M_ZERO); 732331766Sken return ni; 733331766Sken} 734331766Sken 735331766Sken/* 736331766Sken * Initialize an ie blob with the specified data. If previous 737331766Sken * data exists re-use the data block. As a side effect we clear 738331766Sken * all references to specific ie's; the caller is required to 739331766Sken * recalculate them. 740331766Sken */ 741331766Skenint 742331766Skenieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len) 743331766Sken{ 744331766Sken /* NB: assumes data+len are the last fields */ 745331766Sken memset(ies, 0, offsetof(struct ieee80211_ies, data)); 746331766Sken if (ies->data != NULL && ies->len != len) { 747331766Sken /* data size changed */ 748331766Sken FREE(ies->data, M_80211_NODE_IE); 749331766Sken ies->data = NULL; 750331766Sken } 751331766Sken if (ies->data == NULL) { 752331766Sken MALLOC(ies->data, uint8_t *, len, M_80211_NODE_IE, M_NOWAIT); 753331766Sken if (ies->data == NULL) { 754331766Sken ies->len = 0; 755331766Sken /* NB: pointers have already been zero'd above */ 756331766Sken return 0; 757331766Sken } 758331766Sken } 759331766Sken memcpy(ies->data, data, len); 760331766Sken ies->len = len; 761331766Sken return 1; 762331766Sken} 763331766Sken 764331766Sken/* 765331766Sken * Reclaim storage for an ie blob. 766331766Sken */ 767331766Skenvoid 768331766Skenieee80211_ies_cleanup(struct ieee80211_ies *ies) 769331766Sken{ 770331766Sken if (ies->data != NULL) 771331766Sken FREE(ies->data, M_80211_NODE_IE); 772331766Sken} 773331766Sken 774331766Sken/* 775331766Sken * Expand an ie blob data contents and to fillin individual 776331766Sken * ie pointers. The data blob is assumed to be well-formed; 777331766Sken * we don't do any validity checking of ie lengths. 778331766Sken */ 779331766Skenvoid 780331766Skenieee80211_ies_expand(struct ieee80211_ies *ies) 781331766Sken{ 782331766Sken uint8_t *ie; 783331766Sken int ielen; 784335291Sdim 785331766Sken ie = ies->data; 786331766Sken ielen = ies->len; 787331766Sken while (ielen > 0) { 788331766Sken switch (ie[0]) { 789331766Sken case IEEE80211_ELEMID_VENDOR: 790331766Sken if (iswpaoui(ie)) 791331766Sken ies->wpa_ie = ie; 792331766Sken else if (iswmeoui(ie)) 793331766Sken ies->wme_ie = ie; 794331766Sken else if (isatherosoui(ie)) 795331766Sken ies->ath_ie = ie; 796331766Sken break; 797331766Sken case IEEE80211_ELEMID_RSN: 798331766Sken ies->rsn_ie = ie; 799331766Sken break; 800331766Sken case IEEE80211_ELEMID_HTCAP: 801331766Sken ies->htcap_ie = ie; 802331766Sken break; 803331766Sken } 804331766Sken ielen -= 2 + ie[1]; 805331766Sken ie += 2 + ie[1]; 806331766Sken } 807331766Sken} 808335291Sdim 809331766Sken/* 810331766Sken * Reclaim any resources in a node and reset any critical 811331766Sken * state. Typically nodes are free'd immediately after, 812331766Sken * but in some cases the storage may be reused so we need 813331766Sken * to insure consistent state (should probably fix that). 814331766Sken */ 815331766Skenstatic void 816331766Skennode_cleanup(struct ieee80211_node *ni) 817331766Sken{ 818331766Sken#define N(a) (sizeof(a)/sizeof(a[0])) 819331766Sken struct ieee80211vap *vap = ni->ni_vap; 820331766Sken int i; 821331766Sken 822331766Sken /* NB: preserve ni_table */ 823331766Sken if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 824331766Sken if (vap->iv_opmode != IEEE80211_M_STA) 825331766Sken vap->iv_ps_sta--; 826331766Sken ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 827331766Sken IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 828331766Sken "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); 829331766Sken } 830331766Sken /* 831331766Sken * Cleanup any HT-related state. 832331766Sken */ 833331766Sken if (ni->ni_flags & IEEE80211_NODE_HT) 834331766Sken ieee80211_ht_node_cleanup(ni); 835331766Sken /* 836331766Sken * Clear AREF flag that marks the authorization refcnt bump 837331766Sken * has happened. This is probably not needed as the node 838331766Sken * should always be removed from the table so not found but 839331766Sken * do it just in case. 840331766Sken */ 841331766Sken ni->ni_flags &= ~IEEE80211_NODE_AREF; 842331766Sken 843331766Sken /* 844331766Sken * Drain power save queue and, if needed, clear TIM. 845331766Sken */ 846331766Sken if (ieee80211_node_saveq_drain(ni) != 0 && vap->iv_set_tim != NULL) 847331766Sken vap->iv_set_tim(ni, 0); 848331766Sken 849331766Sken ni->ni_associd = 0; 850331766Sken if (ni->ni_challenge != NULL) { 851331766Sken FREE(ni->ni_challenge, M_80211_NODE); 852331766Sken ni->ni_challenge = NULL; 853331766Sken } 854331766Sken /* 855331766Sken * Preserve SSID, WPA, and WME ie's so the bss node is 856331766Sken * reusable during a re-auth/re-assoc state transition. 857331766Sken * If we remove these data they will not be recreated 858331766Sken * because they come from a probe-response or beacon frame 859331766Sken * which cannot be expected prior to the association-response. 860331766Sken * This should not be an issue when operating in other modes 861331766Sken * as stations leaving always go through a full state transition 862331766Sken * which will rebuild this state. 863331766Sken * 864331766Sken * XXX does this leave us open to inheriting old state? 865331766Sken */ 866331766Sken for (i = 0; i < N(ni->ni_rxfrag); i++) 867331766Sken if (ni->ni_rxfrag[i] != NULL) { 868331766Sken m_freem(ni->ni_rxfrag[i]); 869331766Sken ni->ni_rxfrag[i] = NULL; 870331766Sken } 871331766Sken /* 872331766Sken * Must be careful here to remove any key map entry w/o a LOR. 873331766Sken */ 874331766Sken ieee80211_node_delucastkey(ni); 875331766Sken#undef N 876331766Sken} 877331766Sken 878331766Skenstatic void 879331766Skennode_free(struct ieee80211_node *ni) 880331766Sken{ 881331766Sken struct ieee80211com *ic = ni->ni_ic; 882331766Sken 883331766Sken ic->ic_node_cleanup(ni); 884331766Sken ieee80211_ies_cleanup(&ni->ni_ies); 885331766Sken IEEE80211_NODE_SAVEQ_DESTROY(ni); 886331766Sken IEEE80211_NODE_WDSQ_DESTROY(ni); 887331766Sken FREE(ni, M_80211_NODE); 888331766Sken} 889331766Sken 890331766Skenstatic void 891331766Skennode_age(struct ieee80211_node *ni) 892331766Sken{ 893331766Sken struct ieee80211vap *vap = ni->ni_vap; 894331766Sken#if 0 895331766Sken IEEE80211_NODE_LOCK_ASSERT(&ic->ic_sta); 896331766Sken#endif 897331766Sken /* 898331766Sken * Age frames on the power save queue. 899331766Sken */ 900331766Sken if (ieee80211_node_saveq_age(ni) != 0 && 901331766Sken IEEE80211_NODE_SAVEQ_QLEN(ni) == 0 && 902331766Sken vap->iv_set_tim != NULL) 903331766Sken vap->iv_set_tim(ni, 0); 904331766Sken /* 905331766Sken * Age frames on the wds pending queue. 906331766Sken */ 907331766Sken if (IEEE80211_NODE_WDSQ_QLEN(ni) != 0) 908331766Sken ieee80211_node_wdsq_age(ni); 909331766Sken /* 910331766Sken * Age out HT resources (e.g. frames on the 911331766Sken * A-MPDU reorder queues). 912331766Sken */ 913331766Sken if (ni->ni_associd != 0 && (ni->ni_flags & IEEE80211_NODE_HT)) 914331766Sken ieee80211_ht_node_age(ni); 915331766Sken} 916331766Sken 917331766Skenstatic int8_t 918331766Skennode_getrssi(const struct ieee80211_node *ni) 919331766Sken{ 920331766Sken uint32_t avgrssi = ni->ni_avgrssi; 921331766Sken int32_t rssi; 922331766Sken 923331766Sken if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) 924331766Sken return 0; 925331766Sken rssi = IEEE80211_RSSI_GET(avgrssi); 926331766Sken return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 927331766Sken} 928331766Sken 929331766Skenstatic void 930331766Skennode_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise) 931331766Sken{ 932331766Sken *rssi = node_getrssi(ni); 933331766Sken *noise = ni->ni_noise; 934331766Sken} 935331766Sken 936331766Skenstatic void 937331766Skennode_getmimoinfo(const struct ieee80211_node *ni, 938331766Sken struct ieee80211_mimo_info *info) 939331766Sken{ 940331766Sken /* XXX zero data? */ 941331766Sken} 942331766Sken 943331766Skenstruct ieee80211_node * 944331766Skenieee80211_alloc_node(struct ieee80211_node_table *nt, 945331766Sken struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) 946331766Sken{ 947331766Sken struct ieee80211com *ic = nt->nt_ic; 948331766Sken struct ieee80211_node *ni; 949331766Sken int hash; 950331766Sken 951331766Sken ni = ic->ic_node_alloc(nt); 952331766Sken if (ni == NULL) { 953331766Sken vap->iv_stats.is_rx_nodealloc++; 954331766Sken return NULL; 955331766Sken } 956331766Sken 957331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 958331766Sken "%s %p<%s> in %s table\n", __func__, ni, 959331766Sken ether_sprintf(macaddr), nt->nt_name); 960331766Sken 961331766Sken IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 962331766Sken hash = IEEE80211_NODE_HASH(macaddr); 963331766Sken ieee80211_node_initref(ni); /* mark referenced */ 964331766Sken ni->ni_chan = IEEE80211_CHAN_ANYC; 965331766Sken ni->ni_authmode = IEEE80211_AUTH_OPEN; 966331766Sken ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 967331766Sken ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 968331766Sken ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER; 969331766Sken ni->ni_inact_reload = nt->nt_inact_init; 970331766Sken ni->ni_inact = ni->ni_inact_reload; 971331766Sken ni->ni_ath_defkeyix = 0x7fff; 972331766Sken IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 973331766Sken IEEE80211_NODE_WDSQ_INIT(ni, "unknown"); 974331766Sken 975331766Sken IEEE80211_NODE_LOCK(nt); 976331766Sken TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 977331766Sken LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 978331766Sken ni->ni_table = nt; 979331766Sken ni->ni_vap = vap; 980331766Sken ni->ni_ic = ic; 981331766Sken IEEE80211_NODE_UNLOCK(nt); 982331766Sken 983331766Sken return ni; 984331766Sken} 985331766Sken 986331766Sken/* 987331766Sken * Craft a temporary node suitable for sending a management frame 988331766Sken * to the specified station. We craft only as much state as we 989331766Sken * need to do the work since the node will be immediately reclaimed 990331766Sken * once the send completes. 991331766Sken */ 992331766Skenstruct ieee80211_node * 993331766Skenieee80211_tmp_node(struct ieee80211vap *vap, 994331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 995331766Sken{ 996331766Sken struct ieee80211com *ic = vap->iv_ic; 997331766Sken struct ieee80211_node *ni; 998331766Sken 999331766Sken ni = ic->ic_node_alloc(&ic->ic_sta); 1000331766Sken if (ni != NULL) { 1001331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1002331766Sken "%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr)); 1003331766Sken 1004331766Sken ni->ni_table = NULL; /* NB: pedantic */ 1005331766Sken ni->ni_ic = ic; /* NB: needed to set channel */ 1006331766Sken ni->ni_vap = vap; 1007331766Sken 1008331766Sken IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1009331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); 1010331766Sken ieee80211_node_initref(ni); /* mark referenced */ 1011331766Sken /* NB: required by ieee80211_fix_rate */ 1012331766Sken ieee80211_node_set_chan(ni, vap->iv_bss->ni_chan); 1013331766Sken ni->ni_txpower = vap->iv_bss->ni_txpower; 1014331766Sken ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, 1015331766Sken IEEE80211_KEYIX_NONE); 1016331766Sken /* XXX optimize away */ 1017331766Sken IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 1018331766Sken IEEE80211_NODE_WDSQ_INIT(ni, "unknown"); 1019331766Sken } else { 1020331766Sken /* XXX msg */ 1021331766Sken vap->iv_stats.is_rx_nodealloc++; 1022331766Sken } 1023331766Sken return ni; 1024331766Sken} 1025331766Sken 1026331766Skenstruct ieee80211_node * 1027331766Skenieee80211_dup_bss(struct ieee80211vap *vap, 1028331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1029331766Sken{ 1030331766Sken struct ieee80211com *ic = vap->iv_ic; 1031331766Sken struct ieee80211_node *ni; 1032331766Sken 1033331766Sken ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr); 1034331766Sken if (ni != NULL) { 1035331766Sken /* 1036331766Sken * Inherit from iv_bss. 1037331766Sken */ 1038331766Sken ni->ni_authmode = vap->iv_bss->ni_authmode; 1039331766Sken ni->ni_txpower = vap->iv_bss->ni_txpower; 1040331766Sken ni->ni_vlan = vap->iv_bss->ni_vlan; /* XXX?? */ 1041331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); 1042331766Sken ieee80211_node_set_chan(ni, vap->iv_bss->ni_chan); 1043331766Sken } 1044331766Sken return ni; 1045331766Sken} 1046331766Sken 1047331766Sken/* 1048331766Sken * Create a bss node for a legacy WDS vap. The far end does 1049331766Sken * not associate so we just create create a new node and 1050331766Sken * simulate an association. The caller is responsible for 1051331766Sken * installing the node as the bss node and handling any further 1052331766Sken * setup work like authorizing the port. 1053331766Sken */ 1054331766Skenstruct ieee80211_node * 1055331766Skenieee80211_node_create_wds(struct ieee80211vap *vap, 1056331766Sken const uint8_t bssid[IEEE80211_ADDR_LEN], struct ieee80211_channel *chan) 1057331766Sken{ 1058331766Sken struct ieee80211com *ic = vap->iv_ic; 1059331766Sken struct ieee80211_node *ni; 1060331766Sken 1061331766Sken /* XXX check if node already in sta table? */ 1062331766Sken ni = ieee80211_alloc_node(&ic->ic_sta, vap, bssid); 1063331766Sken if (ni != NULL) { 1064331766Sken ni->ni_wdsvap = vap; 1065331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, bssid); 1066331766Sken /* 1067331766Sken * Inherit any manually configured settings. 1068331766Sken */ 1069331766Sken ni->ni_authmode = vap->iv_bss->ni_authmode; 1070331766Sken ni->ni_txpower = vap->iv_bss->ni_txpower; 1071331766Sken ni->ni_vlan = vap->iv_bss->ni_vlan; 1072331766Sken ieee80211_node_set_chan(ni, chan); 1073331766Sken /* NB: propagate ssid so available to WPA supplicant */ 1074331766Sken ni->ni_esslen = vap->iv_des_ssid[0].len; 1075331766Sken memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen); 1076331766Sken /* NB: no associd for peer */ 1077331766Sken /* 1078331766Sken * There are no management frames to use to 1079331766Sken * discover neighbor capabilities, so blindly 1080331766Sken * propagate the local configuration. 1081331766Sken */ 1082331766Sken if (vap->iv_flags & IEEE80211_F_WME) 1083331766Sken ni->ni_flags |= IEEE80211_NODE_QOS; 1084331766Sken if (vap->iv_flags & IEEE80211_F_FF) 1085331766Sken ni->ni_flags |= IEEE80211_NODE_FF; 1086331766Sken if ((ic->ic_htcaps & IEEE80211_HTC_HT) && 1087331766Sken (vap->iv_flags_ext & IEEE80211_FEXT_HT)) { 1088331766Sken /* 1089331766Sken * Device is HT-capable and HT is enabled for 1090331766Sken * the vap; setup HT operation. On return 1091331766Sken * ni_chan will be adjusted to an HT channel. 1092331766Sken */ 1093331766Sken ieee80211_ht_wds_init(ni); 1094331766Sken } else { 1095331766Sken struct ieee80211_channel *c = ni->ni_chan; 1096331766Sken /* 1097331766Sken * Force a legacy channel to be used. 1098331766Sken */ 1099331766Sken c = ieee80211_find_channel(ic, 1100331766Sken c->ic_freq, c->ic_flags &~ IEEE80211_CHAN_HT); 1101331766Sken KASSERT(c != NULL, ("no legacy channel, %u/%x", 1102331766Sken ni->ni_chan->ic_freq, ni->ni_chan->ic_flags)); 1103331766Sken ni->ni_chan = c; 1104331766Sken } 1105331766Sken } 1106331766Sken return ni; 1107331766Sken} 1108331766Sken 1109331766Skenstruct ieee80211_node * 1110331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1111331766Skenieee80211_find_node_locked_debug(struct ieee80211_node_table *nt, 1112331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1113331766Sken#else 1114331766Skenieee80211_find_node_locked(struct ieee80211_node_table *nt, 1115331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1116331766Sken#endif 1117331766Sken{ 1118331766Sken struct ieee80211_node *ni; 1119331766Sken int hash; 1120331766Sken 1121331766Sken IEEE80211_NODE_LOCK_ASSERT(nt); 1122331766Sken 1123331766Sken hash = IEEE80211_NODE_HASH(macaddr); 1124331766Sken LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1125331766Sken if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1126331766Sken ieee80211_ref_node(ni); /* mark referenced */ 1127331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1128331766Sken IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1129331766Sken "%s (%s:%u) %p<%s> refcnt %d\n", __func__, 1130331766Sken func, line, 1131331766Sken ni, ether_sprintf(ni->ni_macaddr), 1132331766Sken ieee80211_node_refcnt(ni)); 1133331766Sken#endif 1134331766Sken return ni; 1135331766Sken } 1136331766Sken } 1137331766Sken return NULL; 1138331766Sken} 1139331766Sken 1140331766Skenstruct ieee80211_node * 1141331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1142331766Skenieee80211_find_node_debug(struct ieee80211_node_table *nt, 1143331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1144331766Sken#else 1145331766Skenieee80211_find_node(struct ieee80211_node_table *nt, 1146331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1147331766Sken#endif 1148331766Sken{ 1149331766Sken struct ieee80211_node *ni; 1150331766Sken 1151331766Sken IEEE80211_NODE_LOCK(nt); 1152331766Sken ni = ieee80211_find_node_locked(nt, macaddr); 1153331766Sken IEEE80211_NODE_UNLOCK(nt); 1154331766Sken return ni; 1155331766Sken} 1156331766Sken 1157331766Skenstruct ieee80211_node * 1158331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1159331766Skenieee80211_find_vap_node_locked_debug(struct ieee80211_node_table *nt, 1160331766Sken const struct ieee80211vap *vap, 1161331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1162331766Sken#else 1163331766Skenieee80211_find_vap_node_locked(struct ieee80211_node_table *nt, 1164331766Sken const struct ieee80211vap *vap, 1165331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1166331766Sken#endif 1167331766Sken{ 1168331766Sken struct ieee80211_node *ni; 1169331766Sken int hash; 1170331766Sken 1171331766Sken IEEE80211_NODE_LOCK_ASSERT(nt); 1172331766Sken 1173331766Sken hash = IEEE80211_NODE_HASH(macaddr); 1174331766Sken LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1175331766Sken if (ni->ni_vap == vap && 1176331766Sken IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1177331766Sken ieee80211_ref_node(ni); /* mark referenced */ 1178331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1179331766Sken IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1180331766Sken "%s (%s:%u) %p<%s> refcnt %d\n", __func__, 1181331766Sken func, line, 1182331766Sken ni, ether_sprintf(ni->ni_macaddr), 1183331766Sken ieee80211_node_refcnt(ni)); 1184331766Sken#endif 1185331766Sken return ni; 1186331766Sken } 1187331766Sken } 1188331766Sken return NULL; 1189331766Sken} 1190331766Sken 1191331766Skenstruct ieee80211_node * 1192331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1193331766Skenieee80211_find_vap_node_debug(struct ieee80211_node_table *nt, 1194331766Sken const struct ieee80211vap *vap, 1195331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line) 1196331766Sken#else 1197331766Skenieee80211_find_vap_node(struct ieee80211_node_table *nt, 1198331766Sken const struct ieee80211vap *vap, 1199331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1200331766Sken#endif 1201331766Sken{ 1202331766Sken struct ieee80211_node *ni; 1203331766Sken 1204331766Sken IEEE80211_NODE_LOCK(nt); 1205331766Sken ni = ieee80211_find_vap_node_locked(nt, vap, macaddr); 1206331766Sken IEEE80211_NODE_UNLOCK(nt); 1207331766Sken return ni; 1208331766Sken} 1209331766Sken 1210331766Sken/* 1211331766Sken * Fake up a node; this handles node discovery in adhoc mode. 1212331766Sken * Note that for the driver's benefit we we treat this like 1213331766Sken * an association so the driver has an opportunity to setup 1214331766Sken * it's private state. 1215331766Sken */ 1216331766Skenstruct ieee80211_node * 1217331766Skenieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, 1218331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1219331766Sken{ 1220331766Sken struct ieee80211_node *ni; 1221331766Sken 1222331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1223331766Sken "%s: mac<%s>\n", __func__, ether_sprintf(macaddr)); 1224331766Sken ni = ieee80211_dup_bss(vap, macaddr); 1225331766Sken if (ni != NULL) { 1226331766Sken struct ieee80211com *ic = vap->iv_ic; 1227331766Sken 1228331766Sken /* XXX no rate negotiation; just dup */ 1229331766Sken ni->ni_rates = vap->iv_bss->ni_rates; 1230331766Sken if (vap->iv_opmode == IEEE80211_M_AHDEMO) { 1231331766Sken /* 1232331766Sken * In adhoc demo mode there are no management 1233331766Sken * frames to use to discover neighbor capabilities, 1234331766Sken * so blindly propagate the local configuration 1235331766Sken * so we can do interesting things (e.g. use 1236331766Sken * WME to disable ACK's). 1237331766Sken */ 1238331766Sken if (vap->iv_flags & IEEE80211_F_WME) 1239331766Sken ni->ni_flags |= IEEE80211_NODE_QOS; 1240331766Sken if (vap->iv_flags & IEEE80211_F_FF) 1241331766Sken ni->ni_flags |= IEEE80211_NODE_FF; 1242331766Sken } 1243331766Sken if (ic->ic_newassoc != NULL) 1244331766Sken ic->ic_newassoc(ni, 1); 1245331766Sken /* XXX not right for 802.1x/WPA */ 1246331766Sken ieee80211_node_authorize(ni); 1247331766Sken } 1248331766Sken return ni; 1249331766Sken} 1250331766Sken 1251331766Skenvoid 1252331766Skenieee80211_init_neighbor(struct ieee80211_node *ni, 1253331766Sken const struct ieee80211_frame *wh, 1254331766Sken const struct ieee80211_scanparams *sp) 1255331766Sken{ 1256331766Sken ni->ni_esslen = sp->ssid[1]; 1257331766Sken memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1258331766Sken IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1259331766Sken memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1260331766Sken ni->ni_intval = sp->bintval; 1261331766Sken ni->ni_capinfo = sp->capinfo; 1262331766Sken ni->ni_chan = ni->ni_ic->ic_curchan; 1263331766Sken ni->ni_fhdwell = sp->fhdwell; 1264331766Sken ni->ni_fhindex = sp->fhindex; 1265331766Sken ni->ni_erp = sp->erp; 1266331766Sken ni->ni_timoff = sp->timoff; 1267331766Sken 1268331766Sken if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) { 1269331766Sken ieee80211_ies_expand(&ni->ni_ies); 1270331766Sken if (ni->ni_ies.ath_ie != NULL) 1271331766Sken ieee80211_parse_ath(ni, ni->ni_ies.ath_ie); 1272331766Sken } 1273331766Sken 1274331766Sken /* NB: must be after ni_chan is setup */ 1275331766Sken ieee80211_setup_rates(ni, sp->rates, sp->xrates, 1276331766Sken IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | 1277331766Sken IEEE80211_F_DONEGO | IEEE80211_F_DODEL); 1278331766Sken} 1279331766Sken 1280331766Sken/* 1281331766Sken * Do node discovery in adhoc mode on receipt of a beacon 1282331766Sken * or probe response frame. Note that for the driver's 1283331766Sken * benefit we we treat this like an association so the 1284331766Sken * driver has an opportunity to setup it's private state. 1285331766Sken */ 1286331766Skenstruct ieee80211_node * 1287331766Skenieee80211_add_neighbor(struct ieee80211vap *vap, 1288331766Sken const struct ieee80211_frame *wh, 1289331766Sken const struct ieee80211_scanparams *sp) 1290331766Sken{ 1291331766Sken struct ieee80211_node *ni; 1292331766Sken 1293331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1294331766Sken "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2)); 1295331766Sken ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */ 1296331766Sken if (ni != NULL) { 1297331766Sken struct ieee80211com *ic = vap->iv_ic; 1298331766Sken 1299331766Sken ieee80211_init_neighbor(ni, wh, sp); 1300331766Sken if (ic->ic_newassoc != NULL) 1301331766Sken ic->ic_newassoc(ni, 1); 1302331766Sken /* XXX not right for 802.1x/WPA */ 1303331766Sken ieee80211_node_authorize(ni); 1304331766Sken } 1305331766Sken return ni; 1306331766Sken} 1307331766Sken 1308331766Sken#define IS_CTL(wh) \ 1309331766Sken ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 1310331766Sken#define IS_PSPOLL(wh) \ 1311331766Sken ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) 1312331766Sken#define IS_BAR(wh) \ 1313331766Sken ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_BAR) 1314331766Sken#define IS_PROBEREQ(wh) \ 1315331766Sken ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) \ 1316331766Sken == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ)) 1317331766Sken#define IS_BCAST_PROBEREQ(wh) \ 1318331766Sken (IS_PROBEREQ(wh) && IEEE80211_IS_MULTICAST( \ 1319331766Sken ((const struct ieee80211_frame *)(wh))->i_addr3)) 1320331766Sken 1321331766Skenstatic __inline struct ieee80211_node * 1322331766Sken_find_rxnode(struct ieee80211_node_table *nt, 1323331766Sken const struct ieee80211_frame_min *wh) 1324331766Sken{ 1325331766Sken /* XXX 4-address frames? */ 1326331766Sken if (IS_CTL(wh) && !IS_PSPOLL(wh) && !IS_BAR(wh) /*&& !IS_RTS(ah)*/) 1327331766Sken return ieee80211_find_node_locked(nt, wh->i_addr1); 1328331766Sken if (IS_BCAST_PROBEREQ(wh)) 1329331766Sken return NULL; /* spam bcast probe req to all vap's */ 1330331766Sken return ieee80211_find_node_locked(nt, wh->i_addr2); 1331331766Sken} 1332331766Sken 1333331766Sken/* 1334331766Sken * Locate the node for sender, track state, and then pass the 1335331766Sken * (referenced) node up to the 802.11 layer for its use. Note 1336331766Sken * we can return NULL if the sender is not in the table. 1337331766Sken */ 1338331766Skenstruct ieee80211_node * 1339331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1340331766Skenieee80211_find_rxnode_debug(struct ieee80211com *ic, 1341331766Sken const struct ieee80211_frame_min *wh, const char *func, int line) 1342331766Sken#else 1343331766Skenieee80211_find_rxnode(struct ieee80211com *ic, 1344331766Sken const struct ieee80211_frame_min *wh) 1345331766Sken#endif 1346331766Sken{ 1347331766Sken struct ieee80211_node_table *nt; 1348331766Sken struct ieee80211_node *ni; 1349331766Sken 1350331766Sken nt = &ic->ic_sta; 1351331766Sken IEEE80211_NODE_LOCK(nt); 1352331766Sken ni = _find_rxnode(nt, wh); 1353331766Sken IEEE80211_NODE_UNLOCK(nt); 1354331766Sken 1355331766Sken return ni; 1356331766Sken} 1357331766Sken 1358331766Sken/* 1359331766Sken * Like ieee80211_find_rxnode but use the supplied h/w 1360331766Sken * key index as a hint to locate the node in the key 1361331766Sken * mapping table. If an entry is present at the key 1362331766Sken * index we return it; otherwise do a normal lookup and 1363331766Sken * update the mapping table if the station has a unicast 1364331766Sken * key assigned to it. 1365331766Sken */ 1366331766Skenstruct ieee80211_node * 1367331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1368331766Skenieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1369331766Sken const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1370331766Sken const char *func, int line) 1371331766Sken#else 1372331766Skenieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1373331766Sken const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1374331766Sken#endif 1375331766Sken{ 1376331766Sken struct ieee80211_node_table *nt; 1377331766Sken struct ieee80211_node *ni; 1378331766Sken 1379331766Sken nt = &ic->ic_sta; 1380331766Sken IEEE80211_NODE_LOCK(nt); 1381331766Sken if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1382331766Sken ni = nt->nt_keyixmap[keyix]; 1383331766Sken else 1384331766Sken ni = NULL; 1385331766Sken if (ni == NULL) { 1386331766Sken ni = _find_rxnode(nt, wh); 1387331766Sken if (ni != NULL && nt->nt_keyixmap != NULL) { 1388331766Sken /* 1389331766Sken * If the station has a unicast key cache slot 1390331766Sken * assigned update the key->node mapping table. 1391331766Sken */ 1392331766Sken keyix = ni->ni_ucastkey.wk_rxkeyix; 1393331766Sken /* XXX can keyixmap[keyix] != NULL? */ 1394331766Sken if (keyix < nt->nt_keyixmax && 1395331766Sken nt->nt_keyixmap[keyix] == NULL) { 1396331766Sken IEEE80211_DPRINTF(ni->ni_vap, 1397331766Sken IEEE80211_MSG_NODE, 1398331766Sken "%s: add key map entry %p<%s> refcnt %d\n", 1399331766Sken __func__, ni, ether_sprintf(ni->ni_macaddr), 1400331766Sken ieee80211_node_refcnt(ni)+1); 1401331766Sken nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1402331766Sken } 1403331766Sken } 1404331766Sken } else { 1405331766Sken if (IS_BCAST_PROBEREQ(wh)) 1406331766Sken ni = NULL; /* spam bcast probe req to all vap's */ 1407331766Sken else 1408331766Sken ieee80211_ref_node(ni); 1409331766Sken } 1410331766Sken IEEE80211_NODE_UNLOCK(nt); 1411331766Sken 1412331766Sken return ni; 1413331766Sken} 1414331766Sken#undef IS_BCAST_PROBEREQ 1415331766Sken#undef IS_PROBEREQ 1416331766Sken#undef IS_BAR 1417331766Sken#undef IS_PSPOLL 1418331766Sken#undef IS_CTL 1419331766Sken 1420331766Sken/* 1421331766Sken * Return a reference to the appropriate node for sending 1422331766Sken * a data frame. This handles node discovery in adhoc networks. 1423331766Sken */ 1424331766Skenstruct ieee80211_node * 1425331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1426331766Skenieee80211_find_txnode_debug(struct ieee80211vap *vap, 1427331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN], 1428331766Sken const char *func, int line) 1429331766Sken#else 1430331766Skenieee80211_find_txnode(struct ieee80211vap *vap, 1431331766Sken const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1432331766Sken#endif 1433331766Sken{ 1434331766Sken struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta; 1435331766Sken struct ieee80211_node *ni; 1436331766Sken 1437331766Sken /* 1438331766Sken * The destination address should be in the node table 1439331766Sken * unless this is a multicast/broadcast frame. We can 1440331766Sken * also optimize station mode operation, all frames go 1441331766Sken * to the bss node. 1442331766Sken */ 1443331766Sken /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ 1444331766Sken IEEE80211_NODE_LOCK(nt); 1445331766Sken if (vap->iv_opmode == IEEE80211_M_STA || 1446331766Sken vap->iv_opmode == IEEE80211_M_WDS || 1447331766Sken IEEE80211_IS_MULTICAST(macaddr)) 1448331766Sken ni = ieee80211_ref_node(vap->iv_bss); 1449331766Sken else { 1450331766Sken ni = ieee80211_find_node_locked(nt, macaddr); 1451331766Sken if (vap->iv_opmode == IEEE80211_M_HOSTAP && 1452331766Sken (ni != NULL && ni->ni_associd == 0)) { 1453331766Sken /* 1454331766Sken * Station is not associated; don't permit the 1455331766Sken * data frame to be sent by returning NULL. This 1456331766Sken * is kinda a kludge but the least intrusive way 1457331766Sken * to add this check into all drivers. 1458331766Sken */ 1459331766Sken ieee80211_unref_node(&ni); /* NB: null's ni */ 1460331766Sken } 1461331766Sken } 1462331766Sken IEEE80211_NODE_UNLOCK(nt); 1463331766Sken 1464331766Sken if (ni == NULL) { 1465331766Sken if (vap->iv_opmode == IEEE80211_M_IBSS || 1466331766Sken vap->iv_opmode == IEEE80211_M_AHDEMO) { 1467331766Sken /* 1468331766Sken * In adhoc mode cons up a node for the destination. 1469331766Sken * Note that we need an additional reference for the 1470331766Sken * caller to be consistent with 1471331766Sken * ieee80211_find_node_locked. 1472331766Sken */ 1473331766Sken ni = ieee80211_fakeup_adhoc_node(vap, macaddr); 1474331766Sken if (ni != NULL) 1475331766Sken (void) ieee80211_ref_node(ni); 1476331766Sken } else { 1477331766Sken IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, macaddr, 1478331766Sken "no node, discard frame (%s)", __func__); 1479331766Sken vap->iv_stats.is_tx_nonode++; 1480331766Sken } 1481331766Sken } 1482331766Sken return ni; 1483331766Sken} 1484331766Sken 1485331766Skenstatic void 1486331766Sken_ieee80211_free_node(struct ieee80211_node *ni) 1487331766Sken{ 1488331766Sken struct ieee80211vap *vap = ni->ni_vap; 1489331766Sken struct ieee80211_node_table *nt = ni->ni_table; 1490331766Sken 1491331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1492331766Sken "%s %p<%s> in %s table\n", __func__, ni, 1493331766Sken ether_sprintf(ni->ni_macaddr), 1494331766Sken nt != NULL ? nt->nt_name : "<gone>"); 1495331766Sken 1496331766Sken if (vap->iv_aid_bitmap != NULL) 1497331766Sken IEEE80211_AID_CLR(vap, ni->ni_associd); 1498331766Sken if (nt != NULL) { 1499331766Sken TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1500331766Sken LIST_REMOVE(ni, ni_hash); 1501331766Sken } 1502331766Sken vap->iv_ic->ic_node_free(ni); 1503331766Sken} 1504331766Sken 1505331766Skenvoid 1506331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1507331766Skenieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1508331766Sken#else 1509331766Skenieee80211_free_node(struct ieee80211_node *ni) 1510331766Sken#endif 1511331766Sken{ 1512331766Sken struct ieee80211_node_table *nt = ni->ni_table; 1513331766Sken 1514331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1515331766Sken IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1516331766Sken "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni, 1517331766Sken ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1); 1518331766Sken#endif 1519331766Sken if (nt != NULL) { 1520331766Sken IEEE80211_NODE_LOCK(nt); 1521331766Sken if (ieee80211_node_dectestref(ni)) { 1522331766Sken /* 1523331766Sken * Last reference, reclaim state. 1524331766Sken */ 1525331766Sken _ieee80211_free_node(ni); 1526331766Sken } else if (ieee80211_node_refcnt(ni) == 1 && 1527331766Sken nt->nt_keyixmap != NULL) { 1528331766Sken ieee80211_keyix keyix; 1529331766Sken /* 1530331766Sken * Check for a last reference in the key mapping table. 1531331766Sken */ 1532331766Sken keyix = ni->ni_ucastkey.wk_rxkeyix; 1533331766Sken if (keyix < nt->nt_keyixmax && 1534331766Sken nt->nt_keyixmap[keyix] == ni) { 1535331766Sken IEEE80211_DPRINTF(ni->ni_vap, 1536331766Sken IEEE80211_MSG_NODE, 1537331766Sken "%s: %p<%s> clear key map entry", __func__, 1538331766Sken ni, ether_sprintf(ni->ni_macaddr)); 1539331766Sken nt->nt_keyixmap[keyix] = NULL; 1540331766Sken ieee80211_node_decref(ni); /* XXX needed? */ 1541331766Sken _ieee80211_free_node(ni); 1542331766Sken } 1543331766Sken } 1544331766Sken IEEE80211_NODE_UNLOCK(nt); 1545331766Sken } else { 1546331766Sken if (ieee80211_node_dectestref(ni)) 1547331766Sken _ieee80211_free_node(ni); 1548331766Sken } 1549331766Sken} 1550331766Sken 1551331766Sken/* 1552331766Sken * Reclaim a unicast key and clear any key cache state. 1553331766Sken */ 1554331766Skenint 1555331766Skenieee80211_node_delucastkey(struct ieee80211_node *ni) 1556331766Sken{ 1557331766Sken struct ieee80211vap *vap = ni->ni_vap; 1558331766Sken /* XXX is ni_table safe? */ 1559331766Sken struct ieee80211_node_table *nt = &ni->ni_ic->ic_sta; 1560331766Sken struct ieee80211_node *nikey; 1561331766Sken ieee80211_keyix keyix; 1562331766Sken int isowned, status; 1563331766Sken 1564331766Sken /* 1565331766Sken * NB: We must beware of LOR here; deleting the key 1566331766Sken * can cause the crypto layer to block traffic updates 1567331766Sken * which can generate a LOR against the node table lock; 1568331766Sken * grab it here and stash the key index for our use below. 1569331766Sken * 1570331766Sken * Must also beware of recursion on the node table lock. 1571331766Sken * When called from node_cleanup we may already have 1572331766Sken * the node table lock held. Unfortunately there's no 1573331766Sken * way to separate out this path so we must do this 1574331766Sken * conditionally. 1575331766Sken */ 1576331766Sken isowned = IEEE80211_NODE_IS_LOCKED(nt); 1577331766Sken if (!isowned) 1578331766Sken IEEE80211_NODE_LOCK(nt); 1579331766Sken keyix = ni->ni_ucastkey.wk_rxkeyix; 1580331766Sken status = ieee80211_crypto_delkey(vap, &ni->ni_ucastkey); 1581331766Sken if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1582331766Sken nikey = nt->nt_keyixmap[keyix]; 1583331766Sken nt->nt_keyixmap[keyix] = NULL;; 1584331766Sken } else 1585331766Sken nikey = NULL; 1586331766Sken if (!isowned) 1587331766Sken IEEE80211_NODE_UNLOCK(nt); 1588331766Sken 1589331766Sken if (nikey != NULL) { 1590331766Sken KASSERT(nikey == ni, 1591331766Sken ("key map out of sync, ni %p nikey %p", ni, nikey)); 1592331766Sken IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1593331766Sken "%s: delete key map entry %p<%s> refcnt %d\n", 1594331766Sken __func__, ni, ether_sprintf(ni->ni_macaddr), 1595331766Sken ieee80211_node_refcnt(ni)-1); 1596331766Sken ieee80211_free_node(ni); 1597331766Sken } 1598331766Sken return status; 1599331766Sken} 1600331766Sken 1601331766Sken/* 1602331766Sken * Reclaim a node. If this is the last reference count then 1603331766Sken * do the normal free work. Otherwise remove it from the node 1604331766Sken * table and mark it gone by clearing the back-reference. 1605331766Sken */ 1606331766Skenstatic void 1607331766Skennode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1608331766Sken{ 1609331766Sken ieee80211_keyix keyix; 1610331766Sken 1611331766Sken IEEE80211_NODE_LOCK_ASSERT(nt); 1612331766Sken 1613331766Sken IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1614331766Sken "%s: remove %p<%s> from %s table, refcnt %d\n", 1615331766Sken __func__, ni, ether_sprintf(ni->ni_macaddr), 1616331766Sken nt->nt_name, ieee80211_node_refcnt(ni)-1); 1617331766Sken /* 1618331766Sken * Clear any entry in the unicast key mapping table. 1619331766Sken * We need to do it here so rx lookups don't find it 1620331766Sken * in the mapping table even if it's not in the hash 1621331766Sken * table. We cannot depend on the mapping table entry 1622331766Sken * being cleared because the node may not be free'd. 1623331766Sken */ 1624331766Sken keyix = ni->ni_ucastkey.wk_rxkeyix; 1625331766Sken if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1626331766Sken nt->nt_keyixmap[keyix] == ni) { 1627331766Sken IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1628331766Sken "%s: %p<%s> clear key map entry\n", 1629331766Sken __func__, ni, ether_sprintf(ni->ni_macaddr)); 1630331766Sken nt->nt_keyixmap[keyix] = NULL; 1631331766Sken ieee80211_node_decref(ni); /* NB: don't need free */ 1632331766Sken } 1633331766Sken if (!ieee80211_node_dectestref(ni)) { 1634331766Sken /* 1635331766Sken * Other references are present, just remove the 1636331766Sken * node from the table so it cannot be found. When 1637331766Sken * the references are dropped storage will be 1638331766Sken * reclaimed. 1639331766Sken */ 1640331766Sken TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1641331766Sken LIST_REMOVE(ni, ni_hash); 1642331766Sken ni->ni_table = NULL; /* clear reference */ 1643331766Sken } else 1644331766Sken _ieee80211_free_node(ni); 1645331766Sken} 1646331766Sken 1647331766Sken/* 1648331766Sken * Reclaim a (bss) node. Decrement the refcnt and reclaim 1649331766Sken * the node if the only other reference to it is in the sta 1650331766Sken * table. This is effectively ieee80211_free_node followed 1651331766Sken * by node_reclaim when the refcnt is 1 (after the free). 1652331766Sken */ 1653331766Skenstatic void 1654331766Skenieee80211_node_reclaim(struct ieee80211_node *ni) 1655331766Sken{ 1656331766Sken struct ieee80211_node_table *nt = ni->ni_table; 1657331766Sken 1658331766Sken KASSERT(nt != NULL, ("reclaim node not in table")); 1659331766Sken 1660331766Sken#ifdef IEEE80211_DEBUG_REFCNT 1661331766Sken IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, 1662331766Sken "%s %p<%s> refcnt %d\n", __func__, ni, 1663331766Sken ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1); 1664331766Sken#endif 1665331766Sken IEEE80211_NODE_LOCK(nt); 1666331766Sken if (ieee80211_node_dectestref(ni)) { 1667331766Sken /* 1668331766Sken * Last reference, reclaim state. 1669331766Sken */ 1670331766Sken _ieee80211_free_node(ni); 1671331766Sken nt = NULL; 1672331766Sken } else if (ieee80211_node_refcnt(ni) == 1 && 1673331766Sken nt->nt_keyixmap != NULL) { 1674331766Sken ieee80211_keyix keyix; 1675331766Sken /* 1676331766Sken * Check for a last reference in the key mapping table. 1677331766Sken */ 1678331766Sken keyix = ni->ni_ucastkey.wk_rxkeyix; 1679331766Sken if (keyix < nt->nt_keyixmax && 1680331766Sken nt->nt_keyixmap[keyix] == ni) { 1681331766Sken IEEE80211_DPRINTF(ni->ni_vap, 1682331766Sken IEEE80211_MSG_NODE, 1683331766Sken "%s: %p<%s> clear key map entry", __func__, 1684331766Sken ni, ether_sprintf(ni->ni_macaddr)); 1685331766Sken nt->nt_keyixmap[keyix] = NULL; 1686331766Sken ieee80211_node_decref(ni); /* XXX needed? */ 1687331766Sken _ieee80211_free_node(ni); 1688331766Sken nt = NULL; 1689331766Sken } 1690331766Sken } 1691331766Sken if (nt != NULL && ieee80211_node_refcnt(ni) == 1) { 1692331766Sken /* 1693331766Sken * Last reference is in the sta table; complete 1694331766Sken * the reclaim. This handles bss nodes being 1695331766Sken * recycled: the node has two references, one for 1696331766Sken * iv_bss and one for the table. After dropping 1697331766Sken * the iv_bss ref above we need to reclaim the sta 1698331766Sken * table reference. 1699331766Sken */ 1700331766Sken ieee80211_node_decref(ni); /* NB: be pendantic */ 1701331766Sken _ieee80211_free_node(ni); 1702331766Sken } 1703331766Sken IEEE80211_NODE_UNLOCK(nt); 1704331766Sken} 1705331766Sken 1706331766Sken/* 1707331766Sken * Node table support. 1708331766Sken */ 1709331766Sken 1710331766Skenstatic void 1711331766Skenieee80211_node_table_init(struct ieee80211com *ic, 1712331766Sken struct ieee80211_node_table *nt, 1713331766Sken const char *name, int inact, int keyixmax) 1714331766Sken{ 1715331766Sken struct ifnet *ifp = ic->ic_ifp; 1716331766Sken 1717331766Sken nt->nt_ic = ic; 1718331766Sken IEEE80211_NODE_LOCK_INIT(nt, ifp->if_xname); 1719331766Sken IEEE80211_NODE_ITERATE_LOCK_INIT(nt, ifp->if_xname); 1720331766Sken TAILQ_INIT(&nt->nt_node); 1721331766Sken nt->nt_name = name; 1722331766Sken nt->nt_scangen = 1; 1723331766Sken nt->nt_inact_init = inact; 1724331766Sken nt->nt_keyixmax = keyixmax; 1725331766Sken if (nt->nt_keyixmax > 0) { 1726331766Sken MALLOC(nt->nt_keyixmap, struct ieee80211_node **, 1727331766Sken keyixmax * sizeof(struct ieee80211_node *), 1728331766Sken M_80211_NODE, M_NOWAIT | M_ZERO); 1729331766Sken if (nt->nt_keyixmap == NULL) 1730331766Sken if_printf(ic->ic_ifp, 1731331766Sken "Cannot allocate key index map with %u entries\n", 1732331766Sken keyixmax); 1733331766Sken } else 1734331766Sken nt->nt_keyixmap = NULL; 1735331766Sken} 1736331766Sken 1737331766Skenstatic void 1738331766Skenieee80211_node_table_reset(struct ieee80211_node_table *nt, 1739331766Sken struct ieee80211vap *match) 1740331766Sken{ 1741331766Sken struct ieee80211_node *ni, *next; 1742331766Sken 1743331766Sken IEEE80211_NODE_LOCK(nt); 1744331766Sken TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) { 1745331766Sken if (match != NULL && ni->ni_vap != match) 1746331766Sken continue; 1747331766Sken /* XXX can this happen? if so need's work */ 1748331766Sken if (ni->ni_associd != 0) { 1749331766Sken struct ieee80211vap *vap = ni->ni_vap; 1750331766Sken 1751331766Sken if (vap->iv_auth->ia_node_leave != NULL) 1752331766Sken vap->iv_auth->ia_node_leave(ni); 1753331766Sken if (vap->iv_aid_bitmap != NULL) 1754331766Sken IEEE80211_AID_CLR(vap, ni->ni_associd); 1755331766Sken } 1756331766Sken ni->ni_wdsvap = NULL; /* clear reference */ 1757331766Sken node_reclaim(nt, ni); 1758331766Sken } 1759331766Sken if (match != NULL && match->iv_opmode == IEEE80211_M_WDS) { 1760331766Sken /* 1761331766Sken * Make a separate pass to clear references to this vap 1762331766Sken * held by DWDS entries. They will not be matched above 1763331766Sken * because ni_vap will point to the ap vap but we still 1764331766Sken * need to clear ni_wdsvap when the WDS vap is destroyed 1765331766Sken * and/or reset. 1766331766Sken */ 1767331766Sken TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) 1768331766Sken if (ni->ni_wdsvap == match) 1769331766Sken ni->ni_wdsvap = NULL; 1770331766Sken } 1771331766Sken IEEE80211_NODE_UNLOCK(nt); 1772331766Sken} 1773331766Sken 1774331766Skenstatic void 1775331766Skenieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 1776331766Sken{ 1777331766Sken ieee80211_node_table_reset(nt, NULL); 1778331766Sken if (nt->nt_keyixmap != NULL) { 1779331766Sken#ifdef DIAGNOSTIC 1780331766Sken /* XXX verify all entries are NULL */ 1781331766Sken int i; 1782331766Sken for (i = 0; i < nt->nt_keyixmax; i++) 1783331766Sken if (nt->nt_keyixmap[i] != NULL) 1784331766Sken printf("%s: %s[%u] still active\n", __func__, 1785331766Sken nt->nt_name, i); 1786331766Sken#endif 1787331766Sken FREE(nt->nt_keyixmap, M_80211_NODE); 1788331766Sken nt->nt_keyixmap = NULL; 1789331766Sken } 1790331766Sken IEEE80211_NODE_ITERATE_LOCK_DESTROY(nt); 1791331766Sken IEEE80211_NODE_LOCK_DESTROY(nt); 1792331766Sken} 1793331766Sken 1794331766Sken/* 1795331766Sken * Timeout inactive stations and do related housekeeping. 1796331766Sken * Note that we cannot hold the node lock while sending a 1797331766Sken * frame as this would lead to a LOR. Instead we use a 1798331766Sken * generation number to mark nodes that we've scanned and 1799331766Sken * drop the lock and restart a scan if we have to time out 1800331766Sken * a node. Since we are single-threaded by virtue of 1801331766Sken * controlling the inactivity timer we can be sure this will 1802331766Sken * process each node only once. 1803331766Sken */ 1804331766Skenstatic void 1805331766Skenieee80211_timeout_stations(struct ieee80211com *ic) 1806331766Sken{ 1807331766Sken struct ieee80211_node_table *nt = &ic->ic_sta; 1808331766Sken struct ieee80211vap *vap; 1809331766Sken struct ieee80211_node *ni; 1810331766Sken int gen = 0; 1811331766Sken 1812331766Sken IEEE80211_NODE_ITERATE_LOCK(nt); 1813331766Sken gen = ++nt->nt_scangen; 1814331766Skenrestart: 1815331766Sken IEEE80211_NODE_LOCK(nt); 1816331766Sken TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1817331766Sken if (ni->ni_scangen == gen) /* previously handled */ 1818331766Sken continue; 1819331766Sken ni->ni_scangen = gen; 1820331766Sken /* 1821331766Sken * Ignore entries for which have yet to receive an 1822331766Sken * authentication frame. These are transient and 1823331766Sken * will be reclaimed when the last reference to them 1824331766Sken * goes away (when frame xmits complete). 1825331766Sken */ 1826331766Sken vap = ni->ni_vap; 1827331766Sken /* 1828331766Sken * Only process stations when in RUN state. This 1829331766Sken * insures, for example, that we don't timeout an 1830331766Sken * inactive station during CAC. Note that CSA state 1831331766Sken * is actually handled in ieee80211_node_timeout as 1832331766Sken * it applies to more than timeout processing. 1833331766Sken */ 1834331766Sken if (vap->iv_state != IEEE80211_S_RUN) 1835331766Sken continue; 1836331766Sken /* XXX can vap be NULL? */ 1837331766Sken if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 1838331766Sken vap->iv_opmode == IEEE80211_M_STA) && 1839331766Sken (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1840331766Sken continue; 1841331766Sken /* 1842331766Sken * Free fragment if not needed anymore 1843331766Sken * (last fragment older than 1s). 1844331766Sken * XXX doesn't belong here, move to node_age 1845331766Sken */ 1846331766Sken if (ni->ni_rxfrag[0] != NULL && 1847331766Sken ticks > ni->ni_rxfragstamp + hz) { 1848331766Sken m_freem(ni->ni_rxfrag[0]); 1849331766Sken ni->ni_rxfrag[0] = NULL; 1850331766Sken } 1851331766Sken if (ni->ni_inact > 0) 1852331766Sken ni->ni_inact--; 1853331766Sken /* 1854331766Sken * Special case ourself; we may be idle for extended periods 1855331766Sken * of time and regardless reclaiming our state is wrong. 1856331766Sken * XXX run ic_node_age 1857331766Sken */ 1858331766Sken if (ni == vap->iv_bss) 1859331766Sken continue; 1860331766Sken if (ni->ni_associd != 0 || 1861331766Sken (vap->iv_opmode == IEEE80211_M_IBSS || 1862331766Sken vap->iv_opmode == IEEE80211_M_AHDEMO)) { 1863331766Sken /* 1864331766Sken * Age/drain resources held by the station. 1865331766Sken */ 1866331766Sken ic->ic_node_age(ni); 1867331766Sken /* 1868331766Sken * Probe the station before time it out. We 1869331766Sken * send a null data frame which may not be 1870331766Sken * universally supported by drivers (need it 1871331766Sken * for ps-poll support so it should be...). 1872331766Sken * 1873331766Sken * XXX don't probe the station unless we've 1874331766Sken * received a frame from them (and have 1875331766Sken * some idea of the rates they are capable 1876331766Sken * of); this will get fixed more properly 1877331766Sken * soon with better handling of the rate set. 1878331766Sken */ 1879331766Sken if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 1880331766Sken (0 < ni->ni_inact && 1881331766Sken ni->ni_inact <= vap->iv_inact_probe) && 1882331766Sken ni->ni_rates.rs_nrates != 0) { 1883331766Sken IEEE80211_NOTE(vap, 1884331766Sken IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 1885331766Sken ni, "%s", 1886331766Sken "probe station due to inactivity"); 1887331766Sken /* 1888331766Sken * Grab a reference before unlocking the table 1889331766Sken * so the node cannot be reclaimed before we 1890331766Sken * send the frame. ieee80211_send_nulldata 1891331766Sken * understands we've done this and reclaims the 1892331766Sken * ref for us as needed. 1893331766Sken */ 1894331766Sken ieee80211_ref_node(ni); 1895331766Sken IEEE80211_NODE_UNLOCK(nt); 1896331766Sken ieee80211_send_nulldata(ni); 1897331766Sken /* XXX stat? */ 1898331766Sken goto restart; 1899331766Sken } 1900331766Sken } 1901331766Sken if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) && 1902331766Sken ni->ni_inact <= 0) { 1903331766Sken IEEE80211_NOTE(vap, 1904331766Sken IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 1905331766Sken "station timed out due to inactivity " 1906331766Sken "(refcnt %u)", ieee80211_node_refcnt(ni)); 1907331766Sken /* 1908331766Sken * Send a deauthenticate frame and drop the station. 1909331766Sken * This is somewhat complicated due to reference counts 1910331766Sken * and locking. At this point a station will typically 1911331766Sken * have a reference count of 1. ieee80211_node_leave 1912331766Sken * will do a "free" of the node which will drop the 1913331766Sken * reference count. But in the meantime a reference 1914331766Sken * wil be held by the deauth frame. The actual reclaim 1915331766Sken * of the node will happen either after the tx is 1916331766Sken * completed or by ieee80211_node_leave. 1917331766Sken * 1918331766Sken * Separately we must drop the node lock before sending 1919331766Sken * in case the driver takes a lock, as this can result 1920331766Sken * in a LOR between the node lock and the driver lock. 1921331766Sken */ 1922331766Sken ieee80211_ref_node(ni); 1923331766Sken IEEE80211_NODE_UNLOCK(nt); 1924331766Sken if (ni->ni_associd != 0) { 1925331766Sken IEEE80211_SEND_MGMT(ni, 1926331766Sken IEEE80211_FC0_SUBTYPE_DEAUTH, 1927 IEEE80211_REASON_AUTH_EXPIRE); 1928 } 1929 ieee80211_node_leave(ni); 1930 ieee80211_free_node(ni); 1931 vap->iv_stats.is_node_timeout++; 1932 goto restart; 1933 } 1934 } 1935 IEEE80211_NODE_UNLOCK(nt); 1936 1937 IEEE80211_NODE_ITERATE_UNLOCK(nt); 1938} 1939 1940/* 1941 * Aggressively reclaim resources. This should be used 1942 * only in a critical situation to reclaim mbuf resources. 1943 */ 1944void 1945ieee80211_drain(struct ieee80211com *ic) 1946{ 1947 struct ieee80211_node_table *nt = &ic->ic_sta; 1948 struct ieee80211vap *vap; 1949 struct ieee80211_node *ni; 1950 1951 IEEE80211_NODE_LOCK(nt); 1952 TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1953 /* 1954 * Ignore entries for which have yet to receive an 1955 * authentication frame. These are transient and 1956 * will be reclaimed when the last reference to them 1957 * goes away (when frame xmits complete). 1958 */ 1959 vap = ni->ni_vap; 1960 /* 1961 * Only process stations when in RUN state. This 1962 * insures, for example, that we don't timeout an 1963 * inactive station during CAC. Note that CSA state 1964 * is actually handled in ieee80211_node_timeout as 1965 * it applies to more than timeout processing. 1966 */ 1967 if (vap->iv_state != IEEE80211_S_RUN) 1968 continue; 1969 /* XXX can vap be NULL? */ 1970 if ((vap->iv_opmode == IEEE80211_M_HOSTAP || 1971 vap->iv_opmode == IEEE80211_M_STA) && 1972 (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1973 continue; 1974 /* 1975 * Free fragments. 1976 * XXX doesn't belong here, move to node_drain 1977 */ 1978 if (ni->ni_rxfrag[0] != NULL) { 1979 m_freem(ni->ni_rxfrag[0]); 1980 ni->ni_rxfrag[0] = NULL; 1981 } 1982 /* 1983 * Drain resources held by the station. 1984 */ 1985 ic->ic_node_drain(ni); 1986 } 1987 IEEE80211_NODE_UNLOCK(nt); 1988} 1989 1990/* 1991 * Per-ieee80211com inactivity timer callback. 1992 */ 1993void 1994ieee80211_node_timeout(void *arg) 1995{ 1996 struct ieee80211com *ic = arg; 1997 1998 /* 1999 * Defer timeout processing if a channel switch is pending. 2000 * We typically need to be mute so not doing things that 2001 * might generate frames is good to handle in one place. 2002 * Supressing the station timeout processing may extend the 2003 * lifetime of inactive stations (by not decrementing their 2004 * idle counters) but this should be ok unless the CSA is 2005 * active for an unusually long time. 2006 */ 2007 if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) { 2008 ieee80211_scan_timeout(ic); 2009 ieee80211_timeout_stations(ic); 2010 2011 IEEE80211_LOCK(ic); 2012 ieee80211_erp_timeout(ic); 2013 ieee80211_ht_timeout(ic); 2014 IEEE80211_UNLOCK(ic); 2015 } 2016 callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, 2017 ieee80211_node_timeout, ic); 2018} 2019 2020void 2021ieee80211_iterate_nodes(struct ieee80211_node_table *nt, 2022 ieee80211_iter_func *f, void *arg) 2023{ 2024 struct ieee80211_node *ni; 2025 u_int gen; 2026 2027 IEEE80211_NODE_ITERATE_LOCK(nt); 2028 gen = ++nt->nt_scangen; 2029restart: 2030 IEEE80211_NODE_LOCK(nt); 2031 TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2032 if (ni->ni_scangen != gen) { 2033 ni->ni_scangen = gen; 2034 (void) ieee80211_ref_node(ni); 2035 IEEE80211_NODE_UNLOCK(nt); 2036 (*f)(arg, ni); 2037 ieee80211_free_node(ni); 2038 goto restart; 2039 } 2040 } 2041 IEEE80211_NODE_UNLOCK(nt); 2042 2043 IEEE80211_NODE_ITERATE_UNLOCK(nt); 2044} 2045 2046void 2047ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 2048{ 2049 printf("0x%p: mac %s refcnt %d\n", ni, 2050 ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); 2051 printf("\tscangen %u authmode %u flags 0x%x\n", 2052 ni->ni_scangen, ni->ni_authmode, ni->ni_flags); 2053 printf("\tassocid 0x%x txpower %u vlan %u\n", 2054 ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 2055 printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 2056 ni->ni_txseqs[IEEE80211_NONQOS_TID], 2057 ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT, 2058 ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK, 2059 ni->ni_rxfragstamp); 2060 printf("\trstamp %u rssi %d noise %d intval %u capinfo 0x%x\n", 2061 ni->ni_rstamp, node_getrssi(ni), ni->ni_noise, 2062 ni->ni_intval, ni->ni_capinfo); 2063 printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n", 2064 ether_sprintf(ni->ni_bssid), 2065 ni->ni_esslen, ni->ni_essid, 2066 ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 2067 printf("\tinact %u txrate %u\n", 2068 ni->ni_inact, ni->ni_txrate); 2069 printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n", 2070 ni->ni_htcap, ni->ni_htparam, 2071 ni->ni_htctlchan, ni->ni_ht2ndchan); 2072 printf("\thtopmode %x htstbc %x chw %u\n", 2073 ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw); 2074} 2075 2076void 2077ieee80211_dump_nodes(struct ieee80211_node_table *nt) 2078{ 2079 ieee80211_iterate_nodes(nt, 2080 (ieee80211_iter_func *) ieee80211_dump_node, nt); 2081} 2082 2083void 2084ieee80211_notify_erp(struct ieee80211com *ic) 2085{ 2086 struct ieee80211vap *vap; 2087 2088 IEEE80211_LOCK_ASSERT(ic); 2089 2090 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 2091 if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2092 ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP); 2093} 2094 2095/* 2096 * Handle a station joining an 11g network. 2097 */ 2098static void 2099ieee80211_node_join_11g(struct ieee80211_node *ni) 2100{ 2101 struct ieee80211com *ic = ni->ni_ic; 2102 2103 IEEE80211_LOCK_ASSERT(ic); 2104 2105 /* 2106 * Station isn't capable of short slot time. Bump 2107 * the count of long slot time stations and disable 2108 * use of short slot time. Note that the actual switch 2109 * over to long slot time use may not occur until the 2110 * next beacon transmission (per sec. 7.3.1.4 of 11g). 2111 */ 2112 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2113 ic->ic_longslotsta++; 2114 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2115 "station needs long slot time, count %d", 2116 ic->ic_longslotsta); 2117 /* XXX vap's w/ conflicting needs won't work */ 2118 if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) { 2119 /* 2120 * Don't force slot time when switched to turbo 2121 * mode as non-ERP stations won't be present; this 2122 * need only be done when on the normal G channel. 2123 */ 2124 ieee80211_set_shortslottime(ic, 0); 2125 } 2126 } 2127 /* 2128 * If the new station is not an ERP station 2129 * then bump the counter and enable protection 2130 * if configured. 2131 */ 2132 if (!ieee80211_iserp_rateset(&ni->ni_rates)) { 2133 ic->ic_nonerpsta++; 2134 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2135 "station is !ERP, %d non-ERP stations associated", 2136 ic->ic_nonerpsta); 2137 /* 2138 * If station does not support short preamble 2139 * then we must enable use of Barker preamble. 2140 */ 2141 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 2142 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2143 "%s", "station needs long preamble"); 2144 ic->ic_flags |= IEEE80211_F_USEBARKER; 2145 ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 2146 } 2147 /* 2148 * If protection is configured and this is the first 2149 * indication we should use protection, enable it. 2150 */ 2151 if (ic->ic_protmode != IEEE80211_PROT_NONE && 2152 ic->ic_nonerpsta == 1 && 2153 (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 2154 IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2155 "%s: enable use of protection\n", __func__); 2156 ic->ic_flags |= IEEE80211_F_USEPROT; 2157 ieee80211_notify_erp(ic); 2158 } 2159 } else 2160 ni->ni_flags |= IEEE80211_NODE_ERP; 2161} 2162 2163void 2164ieee80211_node_join(struct ieee80211_node *ni, int resp) 2165{ 2166 struct ieee80211com *ic = ni->ni_ic; 2167 struct ieee80211vap *vap = ni->ni_vap; 2168 int newassoc; 2169 2170 if (ni->ni_associd == 0) { 2171 uint16_t aid; 2172 2173 KASSERT(vap->iv_aid_bitmap != NULL, ("no aid bitmap")); 2174 /* 2175 * It would be good to search the bitmap 2176 * more efficiently, but this will do for now. 2177 */ 2178 for (aid = 1; aid < vap->iv_max_aid; aid++) { 2179 if (!IEEE80211_AID_ISSET(vap, aid)) 2180 break; 2181 } 2182 if (aid >= vap->iv_max_aid) { 2183 IEEE80211_SEND_MGMT(ni, resp, 2184 IEEE80211_REASON_ASSOC_TOOMANY); 2185 ieee80211_node_leave(ni); 2186 return; 2187 } 2188 ni->ni_associd = aid | 0xc000; 2189 ni->ni_jointime = time_uptime; 2190 IEEE80211_LOCK(ic); 2191 IEEE80211_AID_SET(vap, ni->ni_associd); 2192 vap->iv_sta_assoc++; 2193 ic->ic_sta_assoc++; 2194 2195 if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 2196 ieee80211_ht_node_join(ni); 2197 if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 2198 IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 2199 ieee80211_node_join_11g(ni); 2200 IEEE80211_UNLOCK(ic); 2201 2202 newassoc = 1; 2203 } else 2204 newassoc = 0; 2205 2206 IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 2207 "station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s", 2208 IEEE80211_NODE_AID(ni), 2209 ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2210 ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2211 ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2212 ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "", 2213 ni->ni_flags & IEEE80211_NODE_HT ? 2214 (ni->ni_chw == 20 ? ", HT20" : ", HT40") : "", 2215 ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "", 2216 IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ? 2217 ", fast-frames" : "", 2218 IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ? 2219 ", turbo" : "" 2220 ); 2221 2222 /* give driver a chance to setup state like ni_txrate */ 2223 if (ic->ic_newassoc != NULL) 2224 ic->ic_newassoc(ni, newassoc); 2225 IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_SUCCESS); 2226 /* tell the authenticator about new station */ 2227 if (vap->iv_auth->ia_node_join != NULL) 2228 vap->iv_auth->ia_node_join(ni); 2229 ieee80211_notify_node_join(ni, 2230 resp == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 2231} 2232 2233static void 2234disable_protection(struct ieee80211com *ic) 2235{ 2236 KASSERT(ic->ic_nonerpsta == 0 && 2237 (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0, 2238 ("%d non ERP stations, flags 0x%x", ic->ic_nonerpsta, 2239 ic->ic_flags_ext)); 2240 2241 ic->ic_flags &= ~IEEE80211_F_USEPROT; 2242 /* XXX verify mode? */ 2243 if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2244 ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 2245 ic->ic_flags &= ~IEEE80211_F_USEBARKER; 2246 } 2247 ieee80211_notify_erp(ic); 2248} 2249 2250/* 2251 * Handle a station leaving an 11g network. 2252 */ 2253static void 2254ieee80211_node_leave_11g(struct ieee80211_node *ni) 2255{ 2256 struct ieee80211com *ic = ni->ni_ic; 2257 2258 IEEE80211_LOCK_ASSERT(ic); 2259 2260 KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan), 2261 ("not in 11g, bss %u:0x%x", ic->ic_bsschan->ic_freq, 2262 ic->ic_bsschan->ic_flags)); 2263 2264 /* 2265 * If a long slot station do the slot time bookkeeping. 2266 */ 2267 if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2268 KASSERT(ic->ic_longslotsta > 0, 2269 ("bogus long slot station count %d", ic->ic_longslotsta)); 2270 ic->ic_longslotsta--; 2271 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2272 "long slot time station leaves, count now %d", 2273 ic->ic_longslotsta); 2274 if (ic->ic_longslotsta == 0) { 2275 /* 2276 * Re-enable use of short slot time if supported 2277 * and not operating in IBSS mode (per spec). 2278 */ 2279 if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2280 ic->ic_opmode != IEEE80211_M_IBSS) { 2281 IEEE80211_DPRINTF(ni->ni_vap, 2282 IEEE80211_MSG_ASSOC, 2283 "%s: re-enable use of short slot time\n", 2284 __func__); 2285 ieee80211_set_shortslottime(ic, 1); 2286 } 2287 } 2288 } 2289 /* 2290 * If a non-ERP station do the protection-related bookkeeping. 2291 */ 2292 if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2293 KASSERT(ic->ic_nonerpsta > 0, 2294 ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2295 ic->ic_nonerpsta--; 2296 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni, 2297 "non-ERP station leaves, count now %d%s", ic->ic_nonerpsta, 2298 (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) ? 2299 " (non-ERP sta present)" : ""); 2300 if (ic->ic_nonerpsta == 0 && 2301 (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) { 2302 IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, 2303 "%s: disable use of protection\n", __func__); 2304 disable_protection(ic); 2305 } 2306 } 2307} 2308 2309/* 2310 * Time out presence of an overlapping bss with non-ERP 2311 * stations. When operating in hostap mode we listen for 2312 * beacons from other stations and if we identify a non-ERP 2313 * station is present we enable protection. To identify 2314 * when all non-ERP stations are gone we time out this 2315 * condition. 2316 */ 2317static void 2318ieee80211_erp_timeout(struct ieee80211com *ic) 2319{ 2320 2321 IEEE80211_LOCK_ASSERT(ic); 2322 2323 if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) && 2324 time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) { 2325#if 0 2326 IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2327 "%s", "age out non-ERP sta present on channel"); 2328#endif 2329 ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR; 2330 if (ic->ic_nonerpsta == 0) 2331 disable_protection(ic); 2332 } 2333} 2334 2335/* 2336 * Handle bookkeeping for station deauthentication/disassociation 2337 * when operating as an ap. 2338 */ 2339void 2340ieee80211_node_leave(struct ieee80211_node *ni) 2341{ 2342 struct ieee80211com *ic = ni->ni_ic; 2343 struct ieee80211vap *vap = ni->ni_vap; 2344 struct ieee80211_node_table *nt = ni->ni_table; 2345 2346 IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, 2347 "station with aid %d leaves", IEEE80211_NODE_AID(ni)); 2348 2349 KASSERT(vap->iv_opmode != IEEE80211_M_STA, 2350 ("unexpected operating mode %u", vap->iv_opmode)); 2351 /* 2352 * If node wasn't previously associated all 2353 * we need to do is reclaim the reference. 2354 */ 2355 /* XXX ibss mode bypasses 11g and notification */ 2356 if (ni->ni_associd == 0) 2357 goto done; 2358 /* 2359 * Tell the authenticator the station is leaving. 2360 * Note that we must do this before yanking the 2361 * association id as the authenticator uses the 2362 * associd to locate it's state block. 2363 */ 2364 if (vap->iv_auth->ia_node_leave != NULL) 2365 vap->iv_auth->ia_node_leave(ni); 2366 2367 IEEE80211_LOCK(ic); 2368 IEEE80211_AID_CLR(vap, ni->ni_associd); 2369 ni->ni_associd = 0; 2370 vap->iv_sta_assoc--; 2371 ic->ic_sta_assoc--; 2372 2373 if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) 2374 ieee80211_ht_node_leave(ni); 2375 if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && 2376 IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) 2377 ieee80211_node_leave_11g(ni); 2378 IEEE80211_UNLOCK(ic); 2379 /* 2380 * Cleanup station state. In particular clear various 2381 * state that might otherwise be reused if the node 2382 * is reused before the reference count goes to zero 2383 * (and memory is reclaimed). 2384 */ 2385 ieee80211_sta_leave(ni); 2386done: 2387 /* 2388 * Remove the node from any table it's recorded in and 2389 * drop the caller's reference. Removal from the table 2390 * is important to insure the node is not reprocessed 2391 * for inactivity. 2392 */ 2393 if (nt != NULL) { 2394 IEEE80211_NODE_LOCK(nt); 2395 node_reclaim(nt, ni); 2396 IEEE80211_NODE_UNLOCK(nt); 2397 } else 2398 ieee80211_free_node(ni); 2399} 2400 2401struct rssiinfo { 2402 struct ieee80211vap *vap; 2403 int rssi_samples; 2404 uint32_t rssi_total; 2405}; 2406 2407static void 2408get_hostap_rssi(void *arg, struct ieee80211_node *ni) 2409{ 2410 struct rssiinfo *info = arg; 2411 struct ieee80211vap *vap = ni->ni_vap; 2412 int8_t rssi; 2413 2414 if (info->vap != vap) 2415 return; 2416 /* only associated stations */ 2417 if (ni->ni_associd == 0) 2418 return; 2419 rssi = vap->iv_ic->ic_node_getrssi(ni); 2420 if (rssi != 0) { 2421 info->rssi_samples++; 2422 info->rssi_total += rssi; 2423 } 2424} 2425 2426static void 2427get_adhoc_rssi(void *arg, struct ieee80211_node *ni) 2428{ 2429 struct rssiinfo *info = arg; 2430 struct ieee80211vap *vap = ni->ni_vap; 2431 int8_t rssi; 2432 2433 if (info->vap != vap) 2434 return; 2435 /* only neighbors */ 2436 /* XXX check bssid */ 2437 if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 2438 return; 2439 rssi = vap->iv_ic->ic_node_getrssi(ni); 2440 if (rssi != 0) { 2441 info->rssi_samples++; 2442 info->rssi_total += rssi; 2443 } 2444} 2445 2446int8_t 2447ieee80211_getrssi(struct ieee80211vap *vap) 2448{ 2449#define NZ(x) ((x) == 0 ? 1 : (x)) 2450 struct ieee80211com *ic = vap->iv_ic; 2451 struct rssiinfo info; 2452 2453 info.rssi_total = 0; 2454 info.rssi_samples = 0; 2455 info.vap = vap; 2456 switch (vap->iv_opmode) { 2457 case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2458 case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2459 ieee80211_iterate_nodes(&ic->ic_sta, get_adhoc_rssi, &info); 2460 break; 2461 case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2462 ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info); 2463 break; 2464 case IEEE80211_M_MONITOR: /* XXX */ 2465 case IEEE80211_M_STA: /* use stats from associated ap */ 2466 default: 2467 if (vap->iv_bss != NULL) 2468 info.rssi_total = ic->ic_node_getrssi(vap->iv_bss); 2469 info.rssi_samples = 1; 2470 break; 2471 } 2472 return info.rssi_total / NZ(info.rssi_samples); 2473#undef NZ 2474} 2475 2476void 2477ieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise) 2478{ 2479 2480 if (vap->iv_bss == NULL) /* NB: shouldn't happen */ 2481 return; 2482 vap->iv_ic->ic_node_getsignal(vap->iv_bss, rssi, noise); 2483 /* for non-station mode return avg'd rssi accounting */ 2484 if (vap->iv_opmode != IEEE80211_M_STA) 2485 *rssi = ieee80211_getrssi(vap); 2486} 2487