1*3147Sxc151355 /* 2*3147Sxc151355 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3*3147Sxc151355 * Use is subject to license terms. 4*3147Sxc151355 */ 5*3147Sxc151355 6*3147Sxc151355 /* 7*3147Sxc151355 * Copyright (c) 2001 Atsushi Onoe 8*3147Sxc151355 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 9*3147Sxc151355 * All rights reserved. 10*3147Sxc151355 * 11*3147Sxc151355 * Redistribution and use in source and binary forms, with or without 12*3147Sxc151355 * modification, are permitted provided that the following conditions 13*3147Sxc151355 * are met: 14*3147Sxc151355 * 1. Redistributions of source code must retain the above copyright 15*3147Sxc151355 * notice, this list of conditions and the following disclaimer. 16*3147Sxc151355 * 2. Redistributions in binary form must reproduce the above copyright 17*3147Sxc151355 * notice, this list of conditions and the following disclaimer in the 18*3147Sxc151355 * documentation and/or other materials provided with the distribution. 19*3147Sxc151355 * 3. The name of the author may not be used to endorse or promote products 20*3147Sxc151355 * derived from this software without specific prior written permission. 21*3147Sxc151355 * 22*3147Sxc151355 * Alternatively, this software may be distributed under the terms of the 23*3147Sxc151355 * GNU General Public License ("GPL") version 2 as published by the Free 24*3147Sxc151355 * Software Foundation. 25*3147Sxc151355 * 26*3147Sxc151355 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27*3147Sxc151355 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28*3147Sxc151355 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29*3147Sxc151355 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30*3147Sxc151355 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31*3147Sxc151355 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32*3147Sxc151355 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33*3147Sxc151355 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34*3147Sxc151355 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35*3147Sxc151355 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36*3147Sxc151355 */ 37*3147Sxc151355 38*3147Sxc151355 #pragma ident "%Z%%M% %I% %E% SMI" 39*3147Sxc151355 40*3147Sxc151355 /* 41*3147Sxc151355 * Node management routines 42*3147Sxc151355 */ 43*3147Sxc151355 44*3147Sxc151355 #include "net80211_impl.h" 45*3147Sxc151355 46*3147Sxc151355 static ieee80211_node_t *ieee80211_node_alloc(ieee80211com_t *); 47*3147Sxc151355 static void ieee80211_node_cleanup(ieee80211_node_t *); 48*3147Sxc151355 static void ieee80211_node_free(ieee80211_node_t *); 49*3147Sxc151355 static uint8_t ieee80211_node_getrssi(const ieee80211_node_t *); 50*3147Sxc151355 static void ieee80211_setup_node(ieee80211com_t *, ieee80211_node_table_t *, 51*3147Sxc151355 ieee80211_node_t *, const uint8_t *); 52*3147Sxc151355 static void ieee80211_node_reclaim(ieee80211_node_table_t *, 53*3147Sxc151355 ieee80211_node_t *); 54*3147Sxc151355 static void ieee80211_free_node_locked(ieee80211_node_t *); 55*3147Sxc151355 static void ieee80211_free_allnodes(ieee80211_node_table_t *); 56*3147Sxc151355 static void ieee80211_node_leave(ieee80211com_t *, ieee80211_node_t *); 57*3147Sxc151355 static void ieee80211_timeout_scan_candidates(ieee80211_node_table_t *); 58*3147Sxc151355 static void ieee80211_timeout_stations(ieee80211_node_table_t *); 59*3147Sxc151355 static void ieee80211_node_table_init(ieee80211com_t *, 60*3147Sxc151355 ieee80211_node_table_t *, const char *, int, int, 61*3147Sxc151355 void (*timeout)(ieee80211_node_table_t *)); 62*3147Sxc151355 static void ieee80211_node_table_cleanup(ieee80211_node_table_t *); 63*3147Sxc151355 64*3147Sxc151355 /* 65*3147Sxc151355 * association failures before ignored 66*3147Sxc151355 * The failure may be caused by the response frame is lost for 67*3147Sxc151355 * environmental reason. So Try associate more than once before 68*3147Sxc151355 * ignore the node 69*3147Sxc151355 */ 70*3147Sxc151355 #define IEEE80211_STA_FAILS_MAX 2 71*3147Sxc151355 72*3147Sxc151355 /* 73*3147Sxc151355 * Initialize node database management callbacks for the interface. 74*3147Sxc151355 * This function is called by ieee80211_attach(). These callback 75*3147Sxc151355 * functions may be overridden in special circumstances, as long as 76*3147Sxc151355 * as this is done after calling ieee80211_attach() and prior to any 77*3147Sxc151355 * other call which may allocate a node 78*3147Sxc151355 */ 79*3147Sxc151355 void 80*3147Sxc151355 ieee80211_node_attach(ieee80211com_t *ic) 81*3147Sxc151355 { 82*3147Sxc151355 struct ieee80211_impl *im = ic->ic_private; 83*3147Sxc151355 84*3147Sxc151355 ic->ic_node_alloc = ieee80211_node_alloc; 85*3147Sxc151355 ic->ic_node_free = ieee80211_node_free; 86*3147Sxc151355 ic->ic_node_cleanup = ieee80211_node_cleanup; 87*3147Sxc151355 ic->ic_node_getrssi = ieee80211_node_getrssi; 88*3147Sxc151355 89*3147Sxc151355 /* default station inactivity timer setings */ 90*3147Sxc151355 im->im_inact_init = IEEE80211_INACT_INIT; 91*3147Sxc151355 im->im_inact_assoc = IEEE80211_INACT_ASSOC; 92*3147Sxc151355 im->im_inact_run = IEEE80211_INACT_RUN; 93*3147Sxc151355 im->im_inact_probe = IEEE80211_INACT_PROBE; 94*3147Sxc151355 } 95*3147Sxc151355 96*3147Sxc151355 /* 97*3147Sxc151355 * Initialize node databases and the ic_bss node element. 98*3147Sxc151355 */ 99*3147Sxc151355 void 100*3147Sxc151355 ieee80211_node_lateattach(ieee80211com_t *ic) 101*3147Sxc151355 { 102*3147Sxc151355 /* 103*3147Sxc151355 * Calculate ic_tim_bitmap size in bytes 104*3147Sxc151355 * IEEE80211_AID_MAX defines maximum bits in ic_tim_bitmap 105*3147Sxc151355 */ 106*3147Sxc151355 ic->ic_tim_len = howmany(IEEE80211_AID_MAX, 8) * sizeof (uint8_t); 107*3147Sxc151355 108*3147Sxc151355 ieee80211_node_table_init(ic, &ic->ic_sta, "station", 109*3147Sxc151355 IEEE80211_INACT_INIT, IEEE80211_WEP_NKID, 110*3147Sxc151355 ieee80211_timeout_stations); 111*3147Sxc151355 ieee80211_node_table_init(ic, &ic->ic_scan, "scan", 112*3147Sxc151355 IEEE80211_INACT_SCAN, 0, ieee80211_timeout_scan_candidates); 113*3147Sxc151355 114*3147Sxc151355 ieee80211_reset_bss(ic); 115*3147Sxc151355 } 116*3147Sxc151355 117*3147Sxc151355 /* 118*3147Sxc151355 * Destroy all node databases and is usually called during device detach 119*3147Sxc151355 */ 120*3147Sxc151355 void 121*3147Sxc151355 ieee80211_node_detach(ieee80211com_t *ic) 122*3147Sxc151355 { 123*3147Sxc151355 /* Node Detach */ 124*3147Sxc151355 if (ic->ic_bss != NULL) { 125*3147Sxc151355 ieee80211_free_node(ic->ic_bss); 126*3147Sxc151355 ic->ic_bss = NULL; 127*3147Sxc151355 } 128*3147Sxc151355 ieee80211_node_table_cleanup(&ic->ic_scan); 129*3147Sxc151355 ieee80211_node_table_cleanup(&ic->ic_sta); 130*3147Sxc151355 } 131*3147Sxc151355 132*3147Sxc151355 /* 133*3147Sxc151355 * Increase a node's reference count 134*3147Sxc151355 * 135*3147Sxc151355 * Return pointer to the node 136*3147Sxc151355 */ 137*3147Sxc151355 ieee80211_node_t * 138*3147Sxc151355 ieee80211_ref_node(ieee80211_node_t *in) 139*3147Sxc151355 { 140*3147Sxc151355 ieee80211_node_incref(in); 141*3147Sxc151355 return (in); 142*3147Sxc151355 } 143*3147Sxc151355 144*3147Sxc151355 /* 145*3147Sxc151355 * Dexrease a node's reference count 146*3147Sxc151355 */ 147*3147Sxc151355 void 148*3147Sxc151355 ieee80211_unref_node(ieee80211_node_t **in) 149*3147Sxc151355 { 150*3147Sxc151355 ieee80211_node_decref(*in); 151*3147Sxc151355 *in = NULL; /* guard against use */ 152*3147Sxc151355 } 153*3147Sxc151355 154*3147Sxc151355 /* 155*3147Sxc151355 * Mark ports authorized for data traffic. This function is usually 156*3147Sxc151355 * used by 802.1x authenticator. 157*3147Sxc151355 */ 158*3147Sxc151355 void 159*3147Sxc151355 ieee80211_node_authorize(ieee80211_node_t *in) 160*3147Sxc151355 { 161*3147Sxc151355 ieee80211_impl_t *im = in->in_ic->ic_private; 162*3147Sxc151355 163*3147Sxc151355 in->in_flags |= IEEE80211_NODE_AUTH; 164*3147Sxc151355 in->in_inact_reload = im->im_inact_run; 165*3147Sxc151355 } 166*3147Sxc151355 167*3147Sxc151355 /* 168*3147Sxc151355 * Mark ports unauthorized for data traffic. This function is usually 169*3147Sxc151355 * used by 802.1x authenticator. 170*3147Sxc151355 */ 171*3147Sxc151355 void 172*3147Sxc151355 ieee80211_node_unauthorize(ieee80211_node_t *in) 173*3147Sxc151355 { 174*3147Sxc151355 in->in_flags &= ~IEEE80211_NODE_AUTH; 175*3147Sxc151355 } 176*3147Sxc151355 177*3147Sxc151355 /* 178*3147Sxc151355 * Set/change the channel. The rate set is also updated as 179*3147Sxc151355 * to insure a consistent view by drivers. 180*3147Sxc151355 */ 181*3147Sxc151355 static void 182*3147Sxc151355 ieee80211_node_setchan(ieee80211com_t *ic, ieee80211_node_t *in, 183*3147Sxc151355 struct ieee80211_channel *chan) 184*3147Sxc151355 { 185*3147Sxc151355 if (chan == IEEE80211_CHAN_ANYC) 186*3147Sxc151355 chan = ic->ic_curchan; 187*3147Sxc151355 in->in_chan = chan; 188*3147Sxc151355 in->in_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 189*3147Sxc151355 } 190*3147Sxc151355 191*3147Sxc151355 /* 192*3147Sxc151355 * Initialize the channel set to scan based on the available channels 193*3147Sxc151355 * and the current PHY mode. 194*3147Sxc151355 */ 195*3147Sxc151355 static void 196*3147Sxc151355 ieee80211_reset_scan(ieee80211com_t *ic) 197*3147Sxc151355 { 198*3147Sxc151355 ieee80211_impl_t *im = ic->ic_private; 199*3147Sxc151355 200*3147Sxc151355 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 201*3147Sxc151355 (void) memset(im->im_chan_scan, 0, sizeof (im->im_chan_scan)); 202*3147Sxc151355 ieee80211_setbit(im->im_chan_scan, 203*3147Sxc151355 ieee80211_chan2ieee(ic, ic->ic_des_chan)); 204*3147Sxc151355 } else { 205*3147Sxc151355 bcopy(ic->ic_chan_active, im->im_chan_scan, 206*3147Sxc151355 sizeof (ic->ic_chan_active)); 207*3147Sxc151355 } 208*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_reset_scan(): " 209*3147Sxc151355 "start chan %u\n", ieee80211_chan2ieee(ic, ic->ic_curchan)); 210*3147Sxc151355 } 211*3147Sxc151355 212*3147Sxc151355 /* 213*3147Sxc151355 * Begin an active scan. Initialize the node cache. The scan 214*3147Sxc151355 * begins on the next radio channel by calling ieee80211_next_scan(). 215*3147Sxc151355 * The actual scanning is not automated. The driver itself 216*3147Sxc151355 * only handles setting the radio frequency and stepping through 217*3147Sxc151355 * the channels. 218*3147Sxc151355 */ 219*3147Sxc151355 void 220*3147Sxc151355 ieee80211_begin_scan(ieee80211com_t *ic, boolean_t reset) 221*3147Sxc151355 { 222*3147Sxc151355 IEEE80211_LOCK(ic); 223*3147Sxc151355 224*3147Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP) 225*3147Sxc151355 ic->ic_flags |= IEEE80211_F_ASCAN; 226*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_SCAN, 227*3147Sxc151355 "begin %s scan in %s mode on channel %u\n", 228*3147Sxc151355 (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive", 229*3147Sxc151355 ieee80211_phymode_name[ic->ic_curmode], 230*3147Sxc151355 ieee80211_chan2ieee(ic, ic->ic_curchan)); 231*3147Sxc151355 232*3147Sxc151355 /* 233*3147Sxc151355 * Clear scan state and flush any previously seen AP's. 234*3147Sxc151355 */ 235*3147Sxc151355 ieee80211_reset_scan(ic); 236*3147Sxc151355 if (reset) 237*3147Sxc151355 ieee80211_free_allnodes(&ic->ic_scan); 238*3147Sxc151355 239*3147Sxc151355 ic->ic_flags |= IEEE80211_F_SCAN; 240*3147Sxc151355 IEEE80211_UNLOCK(ic); 241*3147Sxc151355 242*3147Sxc151355 /* Scan the next channel. */ 243*3147Sxc151355 ieee80211_next_scan(ic); 244*3147Sxc151355 } 245*3147Sxc151355 246*3147Sxc151355 /* 247*3147Sxc151355 * Switch to the next channel marked for scanning. 248*3147Sxc151355 * A driver is expected to first call ieee80211_begin_scan(), 249*3147Sxc151355 * to initialize the node cache, then set the radio channel 250*3147Sxc151355 * on the device. And then after a certain time has elapsed, 251*3147Sxc151355 * call ieee80211_next_scan() to move to the next channel. 252*3147Sxc151355 * Typically, a timeout routine is used to automate this process. 253*3147Sxc151355 */ 254*3147Sxc151355 void 255*3147Sxc151355 ieee80211_next_scan(ieee80211com_t *ic) 256*3147Sxc151355 { 257*3147Sxc151355 ieee80211_impl_t *im = ic->ic_private; 258*3147Sxc151355 struct ieee80211_channel *chan; 259*3147Sxc151355 260*3147Sxc151355 IEEE80211_LOCK(ic); 261*3147Sxc151355 /* 262*3147Sxc151355 * Insure any previous mgt frame timeouts don't fire. 263*3147Sxc151355 * This assumes the driver does the right thing in 264*3147Sxc151355 * flushing anything queued in the driver and below. 265*3147Sxc151355 */ 266*3147Sxc151355 im->im_mgt_timer = 0; 267*3147Sxc151355 268*3147Sxc151355 chan = ic->ic_curchan; 269*3147Sxc151355 do { 270*3147Sxc151355 if (++chan > &ic->ic_sup_channels[IEEE80211_CHAN_MAX]) 271*3147Sxc151355 chan = &ic->ic_sup_channels[0]; 272*3147Sxc151355 if (ieee80211_isset(im->im_chan_scan, 273*3147Sxc151355 ieee80211_chan2ieee(ic, chan))) { 274*3147Sxc151355 ieee80211_clrbit(im->im_chan_scan, 275*3147Sxc151355 ieee80211_chan2ieee(ic, chan)); 276*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_SCAN, 277*3147Sxc151355 "ieee80211_next_scan: chan %d->%d\n", 278*3147Sxc151355 ieee80211_chan2ieee(ic, ic->ic_curchan), 279*3147Sxc151355 ieee80211_chan2ieee(ic, chan)); 280*3147Sxc151355 ic->ic_curchan = chan; 281*3147Sxc151355 /* 282*3147Sxc151355 * drivers should do this as needed, 283*3147Sxc151355 * for now maintain compatibility 284*3147Sxc151355 */ 285*3147Sxc151355 ic->ic_bss->in_rates = 286*3147Sxc151355 ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 287*3147Sxc151355 IEEE80211_UNLOCK(ic); 288*3147Sxc151355 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 289*3147Sxc151355 return; 290*3147Sxc151355 } 291*3147Sxc151355 } while (chan != ic->ic_curchan); 292*3147Sxc151355 IEEE80211_UNLOCK(ic); 293*3147Sxc151355 ieee80211_end_scan(ic); 294*3147Sxc151355 } 295*3147Sxc151355 296*3147Sxc151355 /* 297*3147Sxc151355 * Copy useful state from node obss into nbss. 298*3147Sxc151355 */ 299*3147Sxc151355 static void 300*3147Sxc151355 ieee80211_copy_bss(ieee80211_node_t *nbss, const ieee80211_node_t *obss) 301*3147Sxc151355 { 302*3147Sxc151355 /* propagate useful state */ 303*3147Sxc151355 nbss->in_authmode = obss->in_authmode; 304*3147Sxc151355 nbss->in_txpower = obss->in_txpower; 305*3147Sxc151355 nbss->in_vlan = obss->in_vlan; 306*3147Sxc151355 } 307*3147Sxc151355 308*3147Sxc151355 /* 309*3147Sxc151355 * Setup the net80211 specific portion of an interface's softc, ic, 310*3147Sxc151355 * for use in IBSS mode 311*3147Sxc151355 */ 312*3147Sxc151355 void 313*3147Sxc151355 ieee80211_create_ibss(ieee80211com_t *ic, struct ieee80211_channel *chan) 314*3147Sxc151355 { 315*3147Sxc151355 ieee80211_impl_t *im = ic->ic_private; 316*3147Sxc151355 ieee80211_node_table_t *nt; 317*3147Sxc151355 ieee80211_node_t *in; 318*3147Sxc151355 319*3147Sxc151355 IEEE80211_LOCK_ASSERT(ic); 320*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_create_ibss: " 321*3147Sxc151355 "creating ibss\n"); 322*3147Sxc151355 323*3147Sxc151355 /* 324*3147Sxc151355 * Create the station/neighbor table. Note that for adhoc 325*3147Sxc151355 * mode we make the initial inactivity timer longer since 326*3147Sxc151355 * we create nodes only through discovery and they typically 327*3147Sxc151355 * are long-lived associations. 328*3147Sxc151355 */ 329*3147Sxc151355 nt = &ic->ic_sta; 330*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 331*3147Sxc151355 nt->nt_name = "neighbor"; 332*3147Sxc151355 nt->nt_inact_init = im->im_inact_run; 333*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 334*3147Sxc151355 335*3147Sxc151355 in = ieee80211_alloc_node(ic, &ic->ic_sta, ic->ic_macaddr); 336*3147Sxc151355 if (in == NULL) { 337*3147Sxc151355 ieee80211_err("ieee80211_create_ibss(): alloc node failed\n"); 338*3147Sxc151355 return; 339*3147Sxc151355 } 340*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_macaddr); 341*3147Sxc151355 in->in_esslen = ic->ic_des_esslen; 342*3147Sxc151355 (void) memcpy(in->in_essid, ic->ic_des_essid, in->in_esslen); 343*3147Sxc151355 ieee80211_copy_bss(in, ic->ic_bss); 344*3147Sxc151355 in->in_intval = ic->ic_bintval; 345*3147Sxc151355 if (ic->ic_flags & IEEE80211_F_PRIVACY) 346*3147Sxc151355 in->in_capinfo |= IEEE80211_CAPINFO_PRIVACY; 347*3147Sxc151355 if (ic->ic_phytype == IEEE80211_T_FH) { 348*3147Sxc151355 in->in_fhdwell = 200; 349*3147Sxc151355 in->in_fhindex = 1; 350*3147Sxc151355 } 351*3147Sxc151355 switch (ic->ic_opmode) { 352*3147Sxc151355 case IEEE80211_M_IBSS: 353*3147Sxc151355 ic->ic_flags |= IEEE80211_F_SIBSS; 354*3147Sxc151355 in->in_capinfo |= IEEE80211_CAPINFO_IBSS; 355*3147Sxc151355 if (ic->ic_flags & IEEE80211_F_DESBSSID) 356*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_des_bssid); 357*3147Sxc151355 else 358*3147Sxc151355 in->in_bssid[0] |= 0x02; /* local bit for IBSS */ 359*3147Sxc151355 break; 360*3147Sxc151355 case IEEE80211_M_AHDEMO: 361*3147Sxc151355 if (ic->ic_flags & IEEE80211_F_DESBSSID) 362*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_des_bssid); 363*3147Sxc151355 else 364*3147Sxc151355 (void) memset(in->in_bssid, 0, IEEE80211_ADDR_LEN); 365*3147Sxc151355 break; 366*3147Sxc151355 default: 367*3147Sxc151355 ieee80211_err("ieee80211_create_ibss(): " 368*3147Sxc151355 "wrong opmode %u to creat IBSS, abort\n", 369*3147Sxc151355 ic->ic_opmode); 370*3147Sxc151355 ieee80211_free_node(in); 371*3147Sxc151355 return; 372*3147Sxc151355 } 373*3147Sxc151355 374*3147Sxc151355 /* 375*3147Sxc151355 * Fix the channel and related attributes. 376*3147Sxc151355 */ 377*3147Sxc151355 ieee80211_node_setchan(ic, in, chan); 378*3147Sxc151355 ic->ic_curchan = chan; 379*3147Sxc151355 ic->ic_curmode = ieee80211_chan2mode(ic, chan); 380*3147Sxc151355 /* 381*3147Sxc151355 * Do mode-specific rate setup. 382*3147Sxc151355 */ 383*3147Sxc151355 ieee80211_setbasicrates(&in->in_rates, ic->ic_curmode); 384*3147Sxc151355 IEEE80211_UNLOCK(ic); 385*3147Sxc151355 ieee80211_sta_join(ic, in); 386*3147Sxc151355 IEEE80211_LOCK(ic); 387*3147Sxc151355 } 388*3147Sxc151355 389*3147Sxc151355 void 390*3147Sxc151355 ieee80211_reset_bss(ieee80211com_t *ic) 391*3147Sxc151355 { 392*3147Sxc151355 ieee80211_node_t *in; 393*3147Sxc151355 ieee80211_node_t *obss; 394*3147Sxc151355 395*3147Sxc151355 in = ieee80211_alloc_node(ic, &ic->ic_scan, ic->ic_macaddr); 396*3147Sxc151355 ASSERT(in != NULL); 397*3147Sxc151355 obss = ic->ic_bss; 398*3147Sxc151355 ic->ic_bss = ieee80211_ref_node(in); 399*3147Sxc151355 if (obss != NULL) { 400*3147Sxc151355 ieee80211_copy_bss(in, obss); 401*3147Sxc151355 in->in_intval = ic->ic_bintval; 402*3147Sxc151355 ieee80211_free_node(obss); 403*3147Sxc151355 } 404*3147Sxc151355 } 405*3147Sxc151355 406*3147Sxc151355 static int 407*3147Sxc151355 ieee80211_match_bss(ieee80211com_t *ic, ieee80211_node_t *in) 408*3147Sxc151355 { 409*3147Sxc151355 uint8_t rate; 410*3147Sxc151355 int fail; 411*3147Sxc151355 412*3147Sxc151355 fail = 0; 413*3147Sxc151355 if (ieee80211_isclr(ic->ic_chan_active, 414*3147Sxc151355 ieee80211_chan2ieee(ic, in->in_chan))) { 415*3147Sxc151355 fail |= IEEE80211_BADCHAN; 416*3147Sxc151355 } 417*3147Sxc151355 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 418*3147Sxc151355 in->in_chan != ic->ic_des_chan) { 419*3147Sxc151355 fail |= IEEE80211_BADCHAN; 420*3147Sxc151355 } 421*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS) { 422*3147Sxc151355 if (!(in->in_capinfo & IEEE80211_CAPINFO_IBSS)) 423*3147Sxc151355 fail |= IEEE80211_BADOPMODE; 424*3147Sxc151355 } else { 425*3147Sxc151355 if (!(in->in_capinfo & IEEE80211_CAPINFO_ESS)) 426*3147Sxc151355 fail |= IEEE80211_BADOPMODE; 427*3147Sxc151355 } 428*3147Sxc151355 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 429*3147Sxc151355 if (!(in->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) 430*3147Sxc151355 fail |= IEEE80211_BADPRIVACY; 431*3147Sxc151355 } else { 432*3147Sxc151355 if (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY) 433*3147Sxc151355 fail |= IEEE80211_BADPRIVACY; 434*3147Sxc151355 } 435*3147Sxc151355 rate = ieee80211_fix_rate(in, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 436*3147Sxc151355 if (rate & IEEE80211_RATE_BASIC) 437*3147Sxc151355 fail |= IEEE80211_BADRATE; 438*3147Sxc151355 if (ic->ic_des_esslen != 0 && 439*3147Sxc151355 (in->in_esslen != ic->ic_des_esslen || 440*3147Sxc151355 memcmp(in->in_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) { 441*3147Sxc151355 fail |= IEEE80211_BADESSID; 442*3147Sxc151355 } 443*3147Sxc151355 if ((ic->ic_flags & IEEE80211_F_DESBSSID) && 444*3147Sxc151355 !IEEE80211_ADDR_EQ(ic->ic_des_bssid, in->in_bssid)) { 445*3147Sxc151355 fail |= IEEE80211_BADBSSID; 446*3147Sxc151355 } 447*3147Sxc151355 if (in->in_fails >= IEEE80211_STA_FAILS_MAX) 448*3147Sxc151355 fail |= IEEE80211_NODEFAIL; 449*3147Sxc151355 450*3147Sxc151355 return (fail); 451*3147Sxc151355 } 452*3147Sxc151355 453*3147Sxc151355 #define IEEE80211_MAXRATE(_rs) \ 454*3147Sxc151355 ((_rs).ir_rates[(_rs).ir_nrates - 1] & IEEE80211_RATE_VAL) 455*3147Sxc151355 456*3147Sxc151355 /* 457*3147Sxc151355 * Compare the capabilities of node a with node b and decide which is 458*3147Sxc151355 * more desirable (return b if b is considered better than a). Note 459*3147Sxc151355 * that we assume compatibility/usability has already been checked 460*3147Sxc151355 * so we don't need to (e.g. validate whether privacy is supported). 461*3147Sxc151355 * Used to select the best scan candidate for association in a BSS. 462*3147Sxc151355 * 463*3147Sxc151355 * Return desired node 464*3147Sxc151355 */ 465*3147Sxc151355 static ieee80211_node_t * 466*3147Sxc151355 ieee80211_node_compare(ieee80211com_t *ic, ieee80211_node_t *a, 467*3147Sxc151355 ieee80211_node_t *b) 468*3147Sxc151355 { 469*3147Sxc151355 uint8_t maxa; 470*3147Sxc151355 uint8_t maxb; 471*3147Sxc151355 uint8_t rssia; 472*3147Sxc151355 uint8_t rssib; 473*3147Sxc151355 474*3147Sxc151355 /* privacy support preferred */ 475*3147Sxc151355 if ((a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) && 476*3147Sxc151355 !(b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) { 477*3147Sxc151355 return (a); 478*3147Sxc151355 } 479*3147Sxc151355 if (!(a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) && 480*3147Sxc151355 (b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) { 481*3147Sxc151355 return (b); 482*3147Sxc151355 } 483*3147Sxc151355 484*3147Sxc151355 /* compare count of previous failures */ 485*3147Sxc151355 if (b->in_fails != a->in_fails) 486*3147Sxc151355 return ((a->in_fails > b->in_fails) ? b : a); 487*3147Sxc151355 488*3147Sxc151355 rssia = ic->ic_node_getrssi(a); 489*3147Sxc151355 rssib = ic->ic_node_getrssi(b); 490*3147Sxc151355 if (ABS(rssib - rssia) < IEEE80211_RSSI_CMP_THRESHOLD) { 491*3147Sxc151355 /* best/max rate preferred if signal level close enough */ 492*3147Sxc151355 maxa = IEEE80211_MAXRATE(a->in_rates); 493*3147Sxc151355 maxb = IEEE80211_MAXRATE(b->in_rates); 494*3147Sxc151355 if (maxa != maxb) 495*3147Sxc151355 return ((maxb > maxa) ? b : a); 496*3147Sxc151355 /* for now just prefer 5Ghz band to all other bands */ 497*3147Sxc151355 if (IEEE80211_IS_CHAN_5GHZ(a->in_chan) && 498*3147Sxc151355 !IEEE80211_IS_CHAN_5GHZ(b->in_chan)) { 499*3147Sxc151355 return (a); 500*3147Sxc151355 } 501*3147Sxc151355 if (!IEEE80211_IS_CHAN_5GHZ(a->in_chan) && 502*3147Sxc151355 IEEE80211_IS_CHAN_5GHZ(b->in_chan)) { 503*3147Sxc151355 return (b); 504*3147Sxc151355 } 505*3147Sxc151355 } 506*3147Sxc151355 /* all things being equal, compare signal level */ 507*3147Sxc151355 return ((rssib > rssia) ? b : a); 508*3147Sxc151355 } 509*3147Sxc151355 510*3147Sxc151355 /* 511*3147Sxc151355 * Mark an ongoing scan stopped. 512*3147Sxc151355 */ 513*3147Sxc151355 void 514*3147Sxc151355 ieee80211_cancel_scan(ieee80211com_t *ic) 515*3147Sxc151355 { 516*3147Sxc151355 IEEE80211_LOCK(ic); 517*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_cancel_scan()" 518*3147Sxc151355 "end %s scan\n", 519*3147Sxc151355 (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); 520*3147Sxc151355 ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN); 521*3147Sxc151355 cv_broadcast(&((ieee80211_impl_t *)ic->ic_private)->im_scan_cv); 522*3147Sxc151355 IEEE80211_UNLOCK(ic); 523*3147Sxc151355 } 524*3147Sxc151355 525*3147Sxc151355 /* 526*3147Sxc151355 * Complete a scan of potential channels. It is called by 527*3147Sxc151355 * ieee80211_next_scan() when the state machine has performed 528*3147Sxc151355 * a full cycle of scaning on all available radio channels. 529*3147Sxc151355 * ieee80211_end_scan() will inspect the node cache for suitable 530*3147Sxc151355 * APs found during scaning, and associate with one, should 531*3147Sxc151355 * the parameters of the node match those of the configuration 532*3147Sxc151355 * requested from userland. 533*3147Sxc151355 */ 534*3147Sxc151355 void 535*3147Sxc151355 ieee80211_end_scan(ieee80211com_t *ic) 536*3147Sxc151355 { 537*3147Sxc151355 ieee80211_node_table_t *nt = &ic->ic_scan; 538*3147Sxc151355 ieee80211_node_t *in; 539*3147Sxc151355 ieee80211_node_t *selbs; 540*3147Sxc151355 541*3147Sxc151355 ieee80211_cancel_scan(ic); 542*3147Sxc151355 IEEE80211_LOCK(ic); 543*3147Sxc151355 544*3147Sxc151355 /* 545*3147Sxc151355 * Automatic sequencing; look for a candidate and 546*3147Sxc151355 * if found join the network. 547*3147Sxc151355 */ 548*3147Sxc151355 /* NB: unlocked read should be ok */ 549*3147Sxc151355 in = list_head(&nt->nt_node); 550*3147Sxc151355 if (in == NULL) { 551*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_end_scan: " 552*3147Sxc151355 "no scan candidate\n"); 553*3147Sxc151355 notfound: 554*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS && 555*3147Sxc151355 (ic->ic_flags & IEEE80211_F_IBSSON) && 556*3147Sxc151355 ic->ic_des_esslen != 0) { 557*3147Sxc151355 ieee80211_create_ibss(ic, ic->ic_ibss_chan); 558*3147Sxc151355 IEEE80211_UNLOCK(ic); 559*3147Sxc151355 return; 560*3147Sxc151355 } 561*3147Sxc151355 562*3147Sxc151355 /* 563*3147Sxc151355 * Reset the list of channels to scan and start again. 564*3147Sxc151355 */ 565*3147Sxc151355 ieee80211_reset_scan(ic); 566*3147Sxc151355 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 567*3147Sxc151355 IEEE80211_UNLOCK(ic); 568*3147Sxc151355 569*3147Sxc151355 ieee80211_next_scan(ic); 570*3147Sxc151355 return; 571*3147Sxc151355 } 572*3147Sxc151355 573*3147Sxc151355 if (ic->ic_flags & IEEE80211_F_SCANONLY) { /* scan only */ 574*3147Sxc151355 ic->ic_flags &= ~IEEE80211_F_SCANONLY; 575*3147Sxc151355 IEEE80211_UNLOCK(ic); 576*3147Sxc151355 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 577*3147Sxc151355 return; 578*3147Sxc151355 } 579*3147Sxc151355 580*3147Sxc151355 selbs = NULL; 581*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 582*3147Sxc151355 while (in != NULL) { 583*3147Sxc151355 if (in->in_fails >= IEEE80211_STA_FAILS_MAX) { 584*3147Sxc151355 ieee80211_node_t *tmpin = in; 585*3147Sxc151355 586*3147Sxc151355 /* 587*3147Sxc151355 * The configuration of the access points may change 588*3147Sxc151355 * during my scan. So delete the entry for the AP 589*3147Sxc151355 * and retry to associate if there is another beacon. 590*3147Sxc151355 */ 591*3147Sxc151355 in = list_next(&nt->nt_node, tmpin); 592*3147Sxc151355 ieee80211_node_reclaim(nt, tmpin); 593*3147Sxc151355 continue; 594*3147Sxc151355 } 595*3147Sxc151355 if (ieee80211_match_bss(ic, in) == 0) { 596*3147Sxc151355 if (selbs == NULL) 597*3147Sxc151355 selbs = in; 598*3147Sxc151355 else 599*3147Sxc151355 selbs = ieee80211_node_compare(ic, selbs, in); 600*3147Sxc151355 } 601*3147Sxc151355 in = list_next(&nt->nt_node, in); 602*3147Sxc151355 } 603*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 604*3147Sxc151355 if (selbs == NULL) 605*3147Sxc151355 goto notfound; 606*3147Sxc151355 IEEE80211_UNLOCK(ic); 607*3147Sxc151355 ieee80211_sta_join(ic, selbs); 608*3147Sxc151355 } 609*3147Sxc151355 610*3147Sxc151355 611*3147Sxc151355 /* 612*3147Sxc151355 * Handle 802.11 ad hoc network merge. The convention, set by the 613*3147Sxc151355 * Wireless Ethernet Compatibility Alliance (WECA), is that an 802.11 614*3147Sxc151355 * station will change its BSSID to match the "oldest" 802.11 ad hoc 615*3147Sxc151355 * network, on the same channel, that has the station's desired SSID. 616*3147Sxc151355 * The "oldest" 802.11 network sends beacons with the greatest TSF 617*3147Sxc151355 * timestamp. 618*3147Sxc151355 * The caller is assumed to validate TSF's before attempting a merge. 619*3147Sxc151355 * 620*3147Sxc151355 * Return B_TRUE if the BSSID changed, B_FALSE otherwise. 621*3147Sxc151355 */ 622*3147Sxc151355 boolean_t 623*3147Sxc151355 ieee80211_ibss_merge(ieee80211_node_t *in) 624*3147Sxc151355 { 625*3147Sxc151355 ieee80211com_t *ic = in->in_ic; 626*3147Sxc151355 627*3147Sxc151355 if (in == ic->ic_bss || 628*3147Sxc151355 IEEE80211_ADDR_EQ(in->in_bssid, ic->ic_bss->in_bssid)) { 629*3147Sxc151355 /* unchanged, nothing to do */ 630*3147Sxc151355 return (B_FALSE); 631*3147Sxc151355 } 632*3147Sxc151355 if (ieee80211_match_bss(ic, in) != 0) { /* capabilities mismatch */ 633*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_ibss_merge: " 634*3147Sxc151355 " merge failed, capabilities mismatch\n"); 635*3147Sxc151355 return (B_FALSE); 636*3147Sxc151355 } 637*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_ibss_merge: " 638*3147Sxc151355 "new bssid %s: %s preamble, %s slot time%s\n", 639*3147Sxc151355 ieee80211_macaddr_sprintf(in->in_bssid), 640*3147Sxc151355 (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long", 641*3147Sxc151355 (ic->ic_flags & IEEE80211_F_SHSLOT) ? "short" : "long", 642*3147Sxc151355 (ic->ic_flags&IEEE80211_F_USEPROT) ? ", protection" : ""); 643*3147Sxc151355 ieee80211_sta_join(ic, in); 644*3147Sxc151355 return (B_TRUE); 645*3147Sxc151355 } 646*3147Sxc151355 647*3147Sxc151355 /* 648*3147Sxc151355 * Join the specified IBSS/BSS network. The node is assumed to 649*3147Sxc151355 * be passed in with a held reference. 650*3147Sxc151355 */ 651*3147Sxc151355 void 652*3147Sxc151355 ieee80211_sta_join(ieee80211com_t *ic, ieee80211_node_t *selbs) 653*3147Sxc151355 { 654*3147Sxc151355 ieee80211_impl_t *im = ic->ic_private; 655*3147Sxc151355 ieee80211_node_t *obss; 656*3147Sxc151355 657*3147Sxc151355 IEEE80211_LOCK(ic); 658*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS) { 659*3147Sxc151355 ieee80211_node_table_t *nt; 660*3147Sxc151355 661*3147Sxc151355 /* 662*3147Sxc151355 * Delete unusable rates; we've already checked 663*3147Sxc151355 * that the negotiated rate set is acceptable. 664*3147Sxc151355 */ 665*3147Sxc151355 (void) ieee80211_fix_rate(selbs, IEEE80211_F_DODEL); 666*3147Sxc151355 /* 667*3147Sxc151355 * Fillin the neighbor table 668*3147Sxc151355 */ 669*3147Sxc151355 nt = &ic->ic_sta; 670*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 671*3147Sxc151355 nt->nt_name = "neighbor"; 672*3147Sxc151355 nt->nt_inact_init = im->im_inact_run; 673*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 674*3147Sxc151355 } 675*3147Sxc151355 676*3147Sxc151355 /* 677*3147Sxc151355 * Committed to selbs, setup state. 678*3147Sxc151355 */ 679*3147Sxc151355 obss = ic->ic_bss; 680*3147Sxc151355 ic->ic_bss = ieee80211_ref_node(selbs); /* Grab reference */ 681*3147Sxc151355 if (obss != NULL) { 682*3147Sxc151355 ieee80211_copy_bss(selbs, obss); 683*3147Sxc151355 ieee80211_free_node(obss); 684*3147Sxc151355 } 685*3147Sxc151355 ic->ic_curmode = ieee80211_chan2mode(ic, selbs->in_chan); 686*3147Sxc151355 ic->ic_curchan = selbs->in_chan; 687*3147Sxc151355 /* 688*3147Sxc151355 * Set the erp state (mostly the slot time) to deal with 689*3147Sxc151355 * the auto-select case; this should be redundant if the 690*3147Sxc151355 * mode is locked. 691*3147Sxc151355 */ 692*3147Sxc151355 ieee80211_reset_erp(ic); 693*3147Sxc151355 694*3147Sxc151355 IEEE80211_UNLOCK(ic); 695*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA) 696*3147Sxc151355 ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 697*3147Sxc151355 else 698*3147Sxc151355 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 699*3147Sxc151355 } 700*3147Sxc151355 701*3147Sxc151355 /* 702*3147Sxc151355 * Leave the specified IBSS/BSS network. The node is assumed to 703*3147Sxc151355 * be passed in with a held reference. 704*3147Sxc151355 */ 705*3147Sxc151355 void 706*3147Sxc151355 ieee80211_sta_leave(ieee80211com_t *ic, ieee80211_node_t *in) 707*3147Sxc151355 { 708*3147Sxc151355 IEEE80211_LOCK(ic); 709*3147Sxc151355 ic->ic_node_cleanup(in); 710*3147Sxc151355 ieee80211_notify_node_leave(ic, in); 711*3147Sxc151355 IEEE80211_UNLOCK(ic); 712*3147Sxc151355 } 713*3147Sxc151355 714*3147Sxc151355 /* 715*3147Sxc151355 * Allocate a node. This is the default callback function for 716*3147Sxc151355 * ic_node_alloc. This function may be overridden by the driver 717*3147Sxc151355 * to allocate device specific node structure. 718*3147Sxc151355 */ 719*3147Sxc151355 /* ARGSUSED */ 720*3147Sxc151355 static ieee80211_node_t * 721*3147Sxc151355 ieee80211_node_alloc(ieee80211com_t *ic) 722*3147Sxc151355 { 723*3147Sxc151355 return (kmem_zalloc(sizeof (ieee80211_node_t), KM_SLEEP)); 724*3147Sxc151355 } 725*3147Sxc151355 726*3147Sxc151355 /* 727*3147Sxc151355 * Cleanup a node, free any memory associated with the node. 728*3147Sxc151355 * This is the default callback function for ic_node_cleanup 729*3147Sxc151355 * and may be overridden by the driver. 730*3147Sxc151355 */ 731*3147Sxc151355 static void 732*3147Sxc151355 ieee80211_node_cleanup(ieee80211_node_t *in) 733*3147Sxc151355 { 734*3147Sxc151355 in->in_associd = 0; 735*3147Sxc151355 in->in_rssi = 0; 736*3147Sxc151355 in->in_rstamp = 0; 737*3147Sxc151355 if (in->in_challenge != NULL) { 738*3147Sxc151355 kmem_free(in->in_challenge, IEEE80211_CHALLENGE_LEN); 739*3147Sxc151355 in->in_challenge = NULL; 740*3147Sxc151355 } 741*3147Sxc151355 if (in->in_rxfrag != NULL) { 742*3147Sxc151355 freemsg(in->in_rxfrag); 743*3147Sxc151355 in->in_rxfrag = NULL; 744*3147Sxc151355 } 745*3147Sxc151355 } 746*3147Sxc151355 747*3147Sxc151355 /* 748*3147Sxc151355 * Free a node. This is the default callback function for ic_node_free 749*3147Sxc151355 * and may be overridden by the driver to free memory used by device 750*3147Sxc151355 * specific node structure 751*3147Sxc151355 */ 752*3147Sxc151355 static void 753*3147Sxc151355 ieee80211_node_free(ieee80211_node_t *in) 754*3147Sxc151355 { 755*3147Sxc151355 ieee80211com_t *ic = in->in_ic; 756*3147Sxc151355 757*3147Sxc151355 ic->ic_node_cleanup(in); 758*3147Sxc151355 kmem_free(in, sizeof (ieee80211_node_t)); 759*3147Sxc151355 } 760*3147Sxc151355 761*3147Sxc151355 /* 762*3147Sxc151355 * Get a node current RSSI value. This is the default callback function 763*3147Sxc151355 * for ic_node_getrssi and may be overridden by the driver to provide 764*3147Sxc151355 * device specific RSSI calculation algorithm. 765*3147Sxc151355 */ 766*3147Sxc151355 static uint8_t 767*3147Sxc151355 ieee80211_node_getrssi(const ieee80211_node_t *in) 768*3147Sxc151355 { 769*3147Sxc151355 return (in->in_rssi); 770*3147Sxc151355 } 771*3147Sxc151355 772*3147Sxc151355 /* Free fragment if not needed anymore */ 773*3147Sxc151355 static void 774*3147Sxc151355 node_cleanfrag(ieee80211_node_t *in) 775*3147Sxc151355 { 776*3147Sxc151355 clock_t ticks; 777*3147Sxc151355 778*3147Sxc151355 ticks = ddi_get_lbolt(); 779*3147Sxc151355 if (in->in_rxfrag != NULL && ticks > (in->in_rxfragstamp + hz)) { 780*3147Sxc151355 freemsg(in->in_rxfrag); 781*3147Sxc151355 in->in_rxfrag = NULL; 782*3147Sxc151355 } 783*3147Sxc151355 } 784*3147Sxc151355 785*3147Sxc151355 /* 786*3147Sxc151355 * Setup a node. Initialize the node with specified macaddr. Associate 787*3147Sxc151355 * with the interface softc, ic, and add it to the specified node 788*3147Sxc151355 * database. 789*3147Sxc151355 */ 790*3147Sxc151355 static void 791*3147Sxc151355 ieee80211_setup_node(ieee80211com_t *ic, ieee80211_node_table_t *nt, 792*3147Sxc151355 ieee80211_node_t *in, const uint8_t *macaddr) 793*3147Sxc151355 { 794*3147Sxc151355 int32_t hash; 795*3147Sxc151355 796*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_setup_node(): " 797*3147Sxc151355 "%p<%s> in %s table\n", in, 798*3147Sxc151355 ieee80211_macaddr_sprintf(macaddr), 799*3147Sxc151355 (nt != NULL) ? nt->nt_name : "NULL"); 800*3147Sxc151355 801*3147Sxc151355 in->in_ic = ic; 802*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_macaddr, macaddr); 803*3147Sxc151355 hash = ieee80211_node_hash(macaddr); 804*3147Sxc151355 ieee80211_node_initref(in); /* mark referenced */ 805*3147Sxc151355 in->in_authmode = IEEE80211_AUTH_OPEN; 806*3147Sxc151355 in->in_txpower = ic->ic_txpowlimit; /* max power */ 807*3147Sxc151355 in->in_chan = IEEE80211_CHAN_ANYC; 808*3147Sxc151355 in->in_inact_reload = IEEE80211_INACT_INIT; 809*3147Sxc151355 in->in_inact = in->in_inact_reload; 810*3147Sxc151355 ieee80211_crypto_resetkey(ic, &in->in_ucastkey, IEEE80211_KEYIX_NONE); 811*3147Sxc151355 812*3147Sxc151355 if (nt != NULL) { 813*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 814*3147Sxc151355 list_insert_tail(&nt->nt_node, in); 815*3147Sxc151355 list_insert_tail(&nt->nt_hash[hash], in); 816*3147Sxc151355 in->in_table = nt; 817*3147Sxc151355 in->in_inact_reload = nt->nt_inact_init; 818*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 819*3147Sxc151355 } 820*3147Sxc151355 } 821*3147Sxc151355 822*3147Sxc151355 /* 823*3147Sxc151355 * Allocates and initialize a node with specified MAC address. 824*3147Sxc151355 * Associate the node with the interface ic. If the allocation 825*3147Sxc151355 * is successful, the node structure is initialized by 826*3147Sxc151355 * ieee80211_setup_node(); otherwise, NULL is returned 827*3147Sxc151355 */ 828*3147Sxc151355 ieee80211_node_t * 829*3147Sxc151355 ieee80211_alloc_node(ieee80211com_t *ic, ieee80211_node_table_t *nt, 830*3147Sxc151355 const uint8_t *macaddr) 831*3147Sxc151355 { 832*3147Sxc151355 ieee80211_node_t *in; 833*3147Sxc151355 834*3147Sxc151355 in = ic->ic_node_alloc(ic); 835*3147Sxc151355 if (in != NULL) 836*3147Sxc151355 ieee80211_setup_node(ic, nt, in, macaddr); 837*3147Sxc151355 return (in); 838*3147Sxc151355 } 839*3147Sxc151355 840*3147Sxc151355 /* 841*3147Sxc151355 * Craft a temporary node suitable for sending a management frame 842*3147Sxc151355 * to the specified station. We craft only as much state as we 843*3147Sxc151355 * need to do the work since the node will be immediately reclaimed 844*3147Sxc151355 * once the send completes. 845*3147Sxc151355 */ 846*3147Sxc151355 ieee80211_node_t * 847*3147Sxc151355 ieee80211_tmp_node(ieee80211com_t *ic, const uint8_t *macaddr) 848*3147Sxc151355 { 849*3147Sxc151355 ieee80211_node_t *in; 850*3147Sxc151355 851*3147Sxc151355 in = ic->ic_node_alloc(ic); 852*3147Sxc151355 if (in != NULL) { 853*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_tmp_node: " 854*3147Sxc151355 "%p<%s>\n", in, ieee80211_macaddr_sprintf(macaddr)); 855*3147Sxc151355 856*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_macaddr, macaddr); 857*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_bss->in_bssid); 858*3147Sxc151355 ieee80211_node_initref(in); /* mark referenced */ 859*3147Sxc151355 in->in_txpower = ic->ic_bss->in_txpower; 860*3147Sxc151355 /* NB: required by ieee80211_fix_rate */ 861*3147Sxc151355 ieee80211_node_setchan(ic, in, ic->ic_bss->in_chan); 862*3147Sxc151355 ieee80211_crypto_resetkey(ic, &in->in_ucastkey, 863*3147Sxc151355 IEEE80211_KEYIX_NONE); 864*3147Sxc151355 865*3147Sxc151355 in->in_table = NULL; /* NB: pedantic */ 866*3147Sxc151355 in->in_ic = ic; 867*3147Sxc151355 } 868*3147Sxc151355 869*3147Sxc151355 return (in); 870*3147Sxc151355 } 871*3147Sxc151355 872*3147Sxc151355 /* 873*3147Sxc151355 * ieee80211_dup_bss() is similar to ieee80211_alloc_node(), 874*3147Sxc151355 * but is instead used to create a node database entry for 875*3147Sxc151355 * the specified BSSID. If the allocation is successful, the 876*3147Sxc151355 * node is initialized, otherwise, NULL is returned. 877*3147Sxc151355 */ 878*3147Sxc151355 ieee80211_node_t * 879*3147Sxc151355 ieee80211_dup_bss(ieee80211_node_table_t *nt, const uint8_t *macaddr) 880*3147Sxc151355 { 881*3147Sxc151355 ieee80211com_t *ic = nt->nt_ic; 882*3147Sxc151355 ieee80211_node_t *in; 883*3147Sxc151355 884*3147Sxc151355 in = ieee80211_alloc_node(ic, nt, macaddr); 885*3147Sxc151355 if (in != NULL) { 886*3147Sxc151355 /* 887*3147Sxc151355 * Inherit from ic_bss. 888*3147Sxc151355 */ 889*3147Sxc151355 ieee80211_copy_bss(in, ic->ic_bss); 890*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_bss->in_bssid); 891*3147Sxc151355 ieee80211_node_setchan(ic, in, ic->ic_bss->in_chan); 892*3147Sxc151355 } 893*3147Sxc151355 894*3147Sxc151355 return (in); 895*3147Sxc151355 } 896*3147Sxc151355 897*3147Sxc151355 /* 898*3147Sxc151355 * Iterate through the node table, searching for a node entry which 899*3147Sxc151355 * matches macaddr. If the entry is found, its reference count is 900*3147Sxc151355 * incremented, and a pointer to the node is returned; otherwise, 901*3147Sxc151355 * NULL will be returned. 902*3147Sxc151355 * The node table lock is acquired by the caller. 903*3147Sxc151355 */ 904*3147Sxc151355 static ieee80211_node_t * 905*3147Sxc151355 ieee80211_find_node_locked(ieee80211_node_table_t *nt, const uint8_t *macaddr) 906*3147Sxc151355 { 907*3147Sxc151355 ieee80211_node_t *in; 908*3147Sxc151355 int hash; 909*3147Sxc151355 910*3147Sxc151355 ASSERT(IEEE80211_NODE_IS_LOCKED(nt)); 911*3147Sxc151355 912*3147Sxc151355 hash = ieee80211_node_hash(macaddr); 913*3147Sxc151355 in = list_head(&nt->nt_hash[hash]); 914*3147Sxc151355 while (in != NULL) { 915*3147Sxc151355 if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr)) 916*3147Sxc151355 return (ieee80211_ref_node(in)); /* mark referenced */ 917*3147Sxc151355 in = list_next(&nt->nt_hash[hash], in); 918*3147Sxc151355 } 919*3147Sxc151355 return (NULL); 920*3147Sxc151355 } 921*3147Sxc151355 922*3147Sxc151355 /* 923*3147Sxc151355 * Iterate through the node table, searching for a node entry 924*3147Sxc151355 * which match specified mac address. 925*3147Sxc151355 * Return NULL if no matching node found. 926*3147Sxc151355 */ 927*3147Sxc151355 ieee80211_node_t * 928*3147Sxc151355 ieee80211_find_node(ieee80211_node_table_t *nt, const uint8_t *macaddr) 929*3147Sxc151355 { 930*3147Sxc151355 ieee80211_node_t *in; 931*3147Sxc151355 932*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 933*3147Sxc151355 in = ieee80211_find_node_locked(nt, macaddr); 934*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 935*3147Sxc151355 return (in); 936*3147Sxc151355 } 937*3147Sxc151355 938*3147Sxc151355 /* 939*3147Sxc151355 * Fake up a node; this handles node discovery in adhoc mode. 940*3147Sxc151355 * Note that for the driver's benefit we treat this like an 941*3147Sxc151355 * association so the driver has an opportunity to setup it's 942*3147Sxc151355 * private state. 943*3147Sxc151355 */ 944*3147Sxc151355 ieee80211_node_t * 945*3147Sxc151355 ieee80211_fakeup_adhoc_node(ieee80211_node_table_t *nt, const uint8_t *macaddr) 946*3147Sxc151355 { 947*3147Sxc151355 ieee80211com_t *ic = nt->nt_ic; 948*3147Sxc151355 ieee80211_node_t *in; 949*3147Sxc151355 950*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_fakeup_adhoc_node: " 951*3147Sxc151355 "mac<%s>\n", ieee80211_macaddr_sprintf(macaddr)); 952*3147Sxc151355 in = ieee80211_dup_bss(nt, macaddr); 953*3147Sxc151355 if (in != NULL) { 954*3147Sxc151355 /* no rate negotiation; just dup */ 955*3147Sxc151355 in->in_rates = ic->ic_bss->in_rates; 956*3147Sxc151355 if (ic->ic_node_newassoc != NULL) 957*3147Sxc151355 ic->ic_node_newassoc(in, 1); 958*3147Sxc151355 ieee80211_node_authorize(in); 959*3147Sxc151355 } 960*3147Sxc151355 return (in); 961*3147Sxc151355 } 962*3147Sxc151355 963*3147Sxc151355 /* 964*3147Sxc151355 * Process a beacon or probe response frame. 965*3147Sxc151355 */ 966*3147Sxc151355 void 967*3147Sxc151355 ieee80211_add_scan(ieee80211com_t *ic, const struct ieee80211_scanparams *sp, 968*3147Sxc151355 const struct ieee80211_frame *wh, int subtype, int rssi, int rstamp) 969*3147Sxc151355 { 970*3147Sxc151355 ieee80211_node_table_t *nt = &ic->ic_scan; 971*3147Sxc151355 ieee80211_node_t *in; 972*3147Sxc151355 boolean_t newnode = B_FALSE; 973*3147Sxc151355 974*3147Sxc151355 in = ieee80211_find_node(nt, wh->i_addr2); 975*3147Sxc151355 if (in == NULL) { 976*3147Sxc151355 /* 977*3147Sxc151355 * Create a new entry. 978*3147Sxc151355 */ 979*3147Sxc151355 in = ieee80211_alloc_node(ic, nt, wh->i_addr2); 980*3147Sxc151355 if (in == NULL) { 981*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_add_scan: " 982*3147Sxc151355 "alloc node failed\n"); 983*3147Sxc151355 return; 984*3147Sxc151355 } 985*3147Sxc151355 /* 986*3147Sxc151355 * inherit from ic_bss. 987*3147Sxc151355 */ 988*3147Sxc151355 ieee80211_copy_bss(in, ic->ic_bss); 989*3147Sxc151355 ieee80211_node_setchan(ic, in, ic->ic_curchan); 990*3147Sxc151355 newnode = B_TRUE; 991*3147Sxc151355 } 992*3147Sxc151355 993*3147Sxc151355 /* ap beaconing multiple ssid w/ same bssid */ 994*3147Sxc151355 995*3147Sxc151355 /* 996*3147Sxc151355 * sp->ssid[0] - element ID 997*3147Sxc151355 * sp->ssid[1] - length 998*3147Sxc151355 * sp->ssid[2]... - ssid 999*3147Sxc151355 */ 1000*3147Sxc151355 if (sp->ssid[1] != 0 && 1001*3147Sxc151355 subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP || 1002*3147Sxc151355 in->in_esslen == 0) { 1003*3147Sxc151355 in->in_esslen = sp->ssid[1]; 1004*3147Sxc151355 bzero(in->in_essid, sizeof (in->in_essid)); 1005*3147Sxc151355 bcopy(sp->ssid + 2, in->in_essid, sp->ssid[1]); 1006*3147Sxc151355 } 1007*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, wh->i_addr3); 1008*3147Sxc151355 in->in_rssi = (uint8_t)rssi; 1009*3147Sxc151355 in->in_rstamp = rstamp; 1010*3147Sxc151355 bcopy(sp->tstamp, in->in_tstamp.data, sizeof (in->in_tstamp)); 1011*3147Sxc151355 in->in_intval = sp->bintval; 1012*3147Sxc151355 in->in_capinfo = sp->capinfo; 1013*3147Sxc151355 in->in_chan = &ic->ic_sup_channels[sp->chan]; 1014*3147Sxc151355 in->in_phytype = sp->phytype; 1015*3147Sxc151355 in->in_fhdwell = sp->fhdwell; 1016*3147Sxc151355 in->in_fhindex = sp->fhindex; 1017*3147Sxc151355 in->in_erp = sp->erp; 1018*3147Sxc151355 if (sp->tim != NULL) { 1019*3147Sxc151355 struct ieee80211_tim_ie *ie; 1020*3147Sxc151355 1021*3147Sxc151355 ie = (struct ieee80211_tim_ie *)sp->tim; 1022*3147Sxc151355 in->in_dtim_count = ie->tim_count; 1023*3147Sxc151355 in->in_dtim_period = ie->tim_period; 1024*3147Sxc151355 } 1025*3147Sxc151355 /* 1026*3147Sxc151355 * Record the byte offset from the mac header to 1027*3147Sxc151355 * the start of the TIM information element for 1028*3147Sxc151355 * use by hardware and/or to speedup software 1029*3147Sxc151355 * processing of beacon frames. 1030*3147Sxc151355 */ 1031*3147Sxc151355 in->in_tim_off = sp->timoff; 1032*3147Sxc151355 1033*3147Sxc151355 /* NB: must be after in_chan is setup */ 1034*3147Sxc151355 (void) ieee80211_setup_rates(in, sp->rates, sp->xrates, 1035*3147Sxc151355 IEEE80211_F_DOSORT); 1036*3147Sxc151355 1037*3147Sxc151355 if (!newnode) 1038*3147Sxc151355 ieee80211_free_node(in); 1039*3147Sxc151355 } 1040*3147Sxc151355 1041*3147Sxc151355 /* 1042*3147Sxc151355 * Initialize/update an ad-hoc node with contents from a received 1043*3147Sxc151355 * beacon frame. 1044*3147Sxc151355 */ 1045*3147Sxc151355 void 1046*3147Sxc151355 ieee80211_init_neighbor(ieee80211_node_t *in, const struct ieee80211_frame *wh, 1047*3147Sxc151355 const struct ieee80211_scanparams *sp) 1048*3147Sxc151355 { 1049*3147Sxc151355 in->in_esslen = sp->ssid[1]; 1050*3147Sxc151355 (void) memcpy(in->in_essid, sp->ssid + 2, sp->ssid[1]); 1051*3147Sxc151355 IEEE80211_ADDR_COPY(in->in_bssid, wh->i_addr3); 1052*3147Sxc151355 (void) memcpy(in->in_tstamp.data, sp->tstamp, sizeof (in->in_tstamp)); 1053*3147Sxc151355 in->in_intval = sp->bintval; 1054*3147Sxc151355 in->in_capinfo = sp->capinfo; 1055*3147Sxc151355 in->in_chan = in->in_ic->ic_curchan; 1056*3147Sxc151355 in->in_fhdwell = sp->fhdwell; 1057*3147Sxc151355 in->in_fhindex = sp->fhindex; 1058*3147Sxc151355 in->in_erp = sp->erp; 1059*3147Sxc151355 in->in_tim_off = sp->timoff; 1060*3147Sxc151355 1061*3147Sxc151355 /* NB: must be after in_chan is setup */ 1062*3147Sxc151355 (void) ieee80211_setup_rates(in, sp->rates, sp->xrates, 1063*3147Sxc151355 IEEE80211_F_DOSORT); 1064*3147Sxc151355 } 1065*3147Sxc151355 1066*3147Sxc151355 /* 1067*3147Sxc151355 * Do node discovery in adhoc mode on receipt of a beacon 1068*3147Sxc151355 * or probe response frame. Note that for the driver's 1069*3147Sxc151355 * benefit we we treat this like an association so the 1070*3147Sxc151355 * driver has an opportuinty to setup it's private state. 1071*3147Sxc151355 */ 1072*3147Sxc151355 ieee80211_node_t * 1073*3147Sxc151355 ieee80211_add_neighbor(ieee80211com_t *ic, const struct ieee80211_frame *wh, 1074*3147Sxc151355 const struct ieee80211_scanparams *sp) 1075*3147Sxc151355 { 1076*3147Sxc151355 ieee80211_node_t *in; 1077*3147Sxc151355 1078*3147Sxc151355 in = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2); 1079*3147Sxc151355 if (in != NULL) { 1080*3147Sxc151355 ieee80211_init_neighbor(in, wh, sp); 1081*3147Sxc151355 if (ic->ic_node_newassoc != NULL) 1082*3147Sxc151355 ic->ic_node_newassoc(in, 1); 1083*3147Sxc151355 } 1084*3147Sxc151355 return (in); 1085*3147Sxc151355 } 1086*3147Sxc151355 1087*3147Sxc151355 #define IEEE80211_IS_CTL(wh) \ 1088*3147Sxc151355 ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 1089*3147Sxc151355 1090*3147Sxc151355 /* 1091*3147Sxc151355 * Locate the node for sender, track state, and then pass the 1092*3147Sxc151355 * (referenced) node up to the 802.11 layer for its use. We 1093*3147Sxc151355 * are required to pass some node so we fall back to ic_bss 1094*3147Sxc151355 * when this frame is from an unknown sender. The 802.11 layer 1095*3147Sxc151355 * knows this means the sender wasn't in the node table and 1096*3147Sxc151355 * acts accordingly. 1097*3147Sxc151355 */ 1098*3147Sxc151355 ieee80211_node_t * 1099*3147Sxc151355 ieee80211_find_rxnode(ieee80211com_t *ic, const struct ieee80211_frame *wh) 1100*3147Sxc151355 { 1101*3147Sxc151355 ieee80211_node_table_t *nt; 1102*3147Sxc151355 ieee80211_node_t *in; 1103*3147Sxc151355 1104*3147Sxc151355 /* may want scanned nodes in the neighbor table for adhoc */ 1105*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA || 1106*3147Sxc151355 (ic->ic_flags & IEEE80211_F_SCAN)) { 1107*3147Sxc151355 nt = &ic->ic_scan; 1108*3147Sxc151355 } else { 1109*3147Sxc151355 nt = &ic->ic_sta; 1110*3147Sxc151355 } 1111*3147Sxc151355 1112*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1113*3147Sxc151355 if (IEEE80211_IS_CTL(wh)) 1114*3147Sxc151355 in = ieee80211_find_node_locked(nt, wh->i_addr1); 1115*3147Sxc151355 else 1116*3147Sxc151355 in = ieee80211_find_node_locked(nt, wh->i_addr2); 1117*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1118*3147Sxc151355 1119*3147Sxc151355 if (in == NULL) 1120*3147Sxc151355 in = ieee80211_ref_node(ic->ic_bss); 1121*3147Sxc151355 1122*3147Sxc151355 return (in); 1123*3147Sxc151355 } 1124*3147Sxc151355 1125*3147Sxc151355 /* 1126*3147Sxc151355 * Return a reference to the appropriate node for sending 1127*3147Sxc151355 * a data frame. This handles node discovery in adhoc networks. 1128*3147Sxc151355 */ 1129*3147Sxc151355 ieee80211_node_t * 1130*3147Sxc151355 ieee80211_find_txnode(ieee80211com_t *ic, const uint8_t *daddr) 1131*3147Sxc151355 { 1132*3147Sxc151355 ieee80211_node_table_t *nt = &ic->ic_sta; 1133*3147Sxc151355 ieee80211_node_t *in; 1134*3147Sxc151355 1135*3147Sxc151355 /* 1136*3147Sxc151355 * The destination address should be in the node table 1137*3147Sxc151355 * unless this is a multicast/broadcast frame. We can 1138*3147Sxc151355 * also optimize station mode operation, all frames go 1139*3147Sxc151355 * to the bss node. 1140*3147Sxc151355 */ 1141*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1142*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(daddr)) 1143*3147Sxc151355 in = ieee80211_ref_node(ic->ic_bss); 1144*3147Sxc151355 else 1145*3147Sxc151355 in = ieee80211_find_node_locked(nt, daddr); 1146*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1147*3147Sxc151355 1148*3147Sxc151355 if (in == NULL) { 1149*3147Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS) { 1150*3147Sxc151355 /* 1151*3147Sxc151355 * In adhoc mode cons up a node for the destination. 1152*3147Sxc151355 * Note that we need an additional reference for the 1153*3147Sxc151355 * caller to be consistent with 1154*3147Sxc151355 * ieee80211_find_node_locked 1155*3147Sxc151355 * can't hold lock across ieee80211_dup_bss 'cuz of 1156*3147Sxc151355 * recursive locking 1157*3147Sxc151355 */ 1158*3147Sxc151355 in = ieee80211_fakeup_adhoc_node(nt, daddr); 1159*3147Sxc151355 if (in != NULL) 1160*3147Sxc151355 (void) ieee80211_ref_node(in); 1161*3147Sxc151355 } else { 1162*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_OUTPUT, 1163*3147Sxc151355 "ieee80211_find_txnode: " 1164*3147Sxc151355 "[%s] no node, discard frame\n", 1165*3147Sxc151355 ieee80211_macaddr_sprintf(daddr)); 1166*3147Sxc151355 } 1167*3147Sxc151355 } 1168*3147Sxc151355 return (in); 1169*3147Sxc151355 } 1170*3147Sxc151355 1171*3147Sxc151355 /* 1172*3147Sxc151355 * Remove a node from the node database entries and free memory 1173*3147Sxc151355 * associated with the node. The node table lock is acquired by 1174*3147Sxc151355 * the caller. 1175*3147Sxc151355 */ 1176*3147Sxc151355 static void 1177*3147Sxc151355 ieee80211_free_node_locked(ieee80211_node_t *in) 1178*3147Sxc151355 { 1179*3147Sxc151355 ieee80211com_t *ic = in->in_ic; 1180*3147Sxc151355 ieee80211_node_table_t *nt = in->in_table; 1181*3147Sxc151355 int32_t hash; 1182*3147Sxc151355 1183*3147Sxc151355 if (nt != NULL) { 1184*3147Sxc151355 hash = ieee80211_node_hash(in->in_macaddr); 1185*3147Sxc151355 list_remove(&nt->nt_hash[hash], in); 1186*3147Sxc151355 list_remove(&nt->nt_node, in); 1187*3147Sxc151355 } 1188*3147Sxc151355 ic->ic_node_free(in); 1189*3147Sxc151355 } 1190*3147Sxc151355 1191*3147Sxc151355 /* 1192*3147Sxc151355 * Remove a node from the node database entries and free any 1193*3147Sxc151355 * memory associated with the node. 1194*3147Sxc151355 * This method can be overridden in ieee80211_attach() 1195*3147Sxc151355 */ 1196*3147Sxc151355 void 1197*3147Sxc151355 ieee80211_free_node(ieee80211_node_t *in) 1198*3147Sxc151355 { 1199*3147Sxc151355 ieee80211_node_table_t *nt = in->in_table; 1200*3147Sxc151355 1201*3147Sxc151355 if (nt != NULL) 1202*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1203*3147Sxc151355 if (ieee80211_node_decref_nv(in) == 0) 1204*3147Sxc151355 ieee80211_free_node_locked(in); 1205*3147Sxc151355 if (nt != NULL) 1206*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1207*3147Sxc151355 } 1208*3147Sxc151355 1209*3147Sxc151355 /* 1210*3147Sxc151355 * Reclaim a node. If this is the last reference count then 1211*3147Sxc151355 * do the normal free work. Otherwise remove it from the node 1212*3147Sxc151355 * table and mark it gone by clearing the back-reference. 1213*3147Sxc151355 */ 1214*3147Sxc151355 static void 1215*3147Sxc151355 ieee80211_node_reclaim(ieee80211_node_table_t *nt, ieee80211_node_t *in) 1216*3147Sxc151355 { 1217*3147Sxc151355 int32_t hash; 1218*3147Sxc151355 1219*3147Sxc151355 IEEE80211_NODE_LOCK_ASSERT(nt); 1220*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "node_reclaim: " 1221*3147Sxc151355 " remove %p<%s> from %s table, refcnt %d\n", 1222*3147Sxc151355 in, ieee80211_macaddr_sprintf(in->in_macaddr), nt->nt_name, 1223*3147Sxc151355 ieee80211_node_refcnt(in)); 1224*3147Sxc151355 1225*3147Sxc151355 if (ieee80211_node_decref_nv(in) != 0) { 1226*3147Sxc151355 /* 1227*3147Sxc151355 * Clear any entry in the unicast key mapping table. 1228*3147Sxc151355 * We need to do it here so rx lookups don't find it 1229*3147Sxc151355 * in the mapping table even if it's not in the hash 1230*3147Sxc151355 * table. We cannot depend on the mapping table entry 1231*3147Sxc151355 * being cleared because the node may not be free'd. 1232*3147Sxc151355 */ 1233*3147Sxc151355 hash = ieee80211_node_hash(in->in_macaddr); 1234*3147Sxc151355 list_remove(&nt->nt_hash[hash], in); 1235*3147Sxc151355 list_remove(&nt->nt_node, in); 1236*3147Sxc151355 in->in_table = NULL; 1237*3147Sxc151355 } else { 1238*3147Sxc151355 ieee80211_free_node_locked(in); 1239*3147Sxc151355 } 1240*3147Sxc151355 } 1241*3147Sxc151355 1242*3147Sxc151355 /* 1243*3147Sxc151355 * Iterate through the node list and reclaim all node in the node table. 1244*3147Sxc151355 * The node table lock is acquired by the caller 1245*3147Sxc151355 */ 1246*3147Sxc151355 static void 1247*3147Sxc151355 ieee80211_free_allnodes_locked(ieee80211_node_table_t *nt) 1248*3147Sxc151355 { 1249*3147Sxc151355 ieee80211_node_t *in; 1250*3147Sxc151355 1251*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_free_allnodes_locked(): " 1252*3147Sxc151355 "free all nodes in %s table\n", nt->nt_name); 1253*3147Sxc151355 1254*3147Sxc151355 in = list_head(&nt->nt_node); 1255*3147Sxc151355 while (in != NULL) { 1256*3147Sxc151355 ieee80211_node_reclaim(nt, in); 1257*3147Sxc151355 in = list_head(&nt->nt_node); 1258*3147Sxc151355 } 1259*3147Sxc151355 ieee80211_reset_erp(nt->nt_ic); 1260*3147Sxc151355 } 1261*3147Sxc151355 1262*3147Sxc151355 /* 1263*3147Sxc151355 * Iterate through the node list, calling ieee80211_node_reclaim() for 1264*3147Sxc151355 * all nodes associated with the interface. 1265*3147Sxc151355 */ 1266*3147Sxc151355 static void 1267*3147Sxc151355 ieee80211_free_allnodes(ieee80211_node_table_t *nt) 1268*3147Sxc151355 { 1269*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1270*3147Sxc151355 ieee80211_free_allnodes_locked(nt); 1271*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1272*3147Sxc151355 } 1273*3147Sxc151355 1274*3147Sxc151355 /* 1275*3147Sxc151355 * Timeout entries in the scan cache. This is the timeout callback 1276*3147Sxc151355 * function of node table ic_scan which is called when the inactivity 1277*3147Sxc151355 * timer expires. 1278*3147Sxc151355 */ 1279*3147Sxc151355 static void 1280*3147Sxc151355 ieee80211_timeout_scan_candidates(ieee80211_node_table_t *nt) 1281*3147Sxc151355 { 1282*3147Sxc151355 ieee80211com_t *ic = nt->nt_ic; 1283*3147Sxc151355 ieee80211_node_t *in; 1284*3147Sxc151355 1285*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1286*3147Sxc151355 in = ic->ic_bss; 1287*3147Sxc151355 node_cleanfrag(in); /* Free fragment if not needed */ 1288*3147Sxc151355 nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1289*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1290*3147Sxc151355 } 1291*3147Sxc151355 1292*3147Sxc151355 /* 1293*3147Sxc151355 * Timeout inactive stations and do related housekeeping. 1294*3147Sxc151355 * Note that we cannot hold the node lock while sending a 1295*3147Sxc151355 * frame as this would lead to a LOR. Instead we use a 1296*3147Sxc151355 * generation number to mark nodes that we've scanned and 1297*3147Sxc151355 * drop the lock and restart a scan if we have to time out 1298*3147Sxc151355 * a node. Since we are single-threaded by virtue of 1299*3147Sxc151355 * controlling the inactivity timer we can be sure this will 1300*3147Sxc151355 * process each node only once. 1301*3147Sxc151355 */ 1302*3147Sxc151355 static void 1303*3147Sxc151355 ieee80211_timeout_stations(ieee80211_node_table_t *nt) 1304*3147Sxc151355 { 1305*3147Sxc151355 ieee80211com_t *ic = nt->nt_ic; 1306*3147Sxc151355 ieee80211_impl_t *im = ic->ic_private; 1307*3147Sxc151355 ieee80211_node_t *in = NULL; 1308*3147Sxc151355 uint32_t gen; 1309*3147Sxc151355 boolean_t isadhoc; 1310*3147Sxc151355 1311*3147Sxc151355 IEEE80211_LOCK_ASSERT(ic); 1312*3147Sxc151355 isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS || 1313*3147Sxc151355 ic->ic_opmode == IEEE80211_M_AHDEMO); 1314*3147Sxc151355 IEEE80211_SCAN_LOCK(nt); 1315*3147Sxc151355 gen = ++nt->nt_scangen; 1316*3147Sxc151355 restart: 1317*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1318*3147Sxc151355 for (in = list_head(&nt->nt_node); in != NULL; 1319*3147Sxc151355 in = list_next(&nt->nt_node, in)) { 1320*3147Sxc151355 if (in->in_scangen == gen) /* previously handled */ 1321*3147Sxc151355 continue; 1322*3147Sxc151355 in->in_scangen = gen; 1323*3147Sxc151355 node_cleanfrag(in); /* free fragment if not needed */ 1324*3147Sxc151355 1325*3147Sxc151355 /* 1326*3147Sxc151355 * Special case ourself; we may be idle for extended periods 1327*3147Sxc151355 * of time and regardless reclaiming our state is wrong. 1328*3147Sxc151355 */ 1329*3147Sxc151355 if (in == ic->ic_bss) 1330*3147Sxc151355 continue; 1331*3147Sxc151355 in->in_inact--; 1332*3147Sxc151355 if (in->in_associd != 0 || isadhoc) { 1333*3147Sxc151355 /* 1334*3147Sxc151355 * Probe the station before time it out. We 1335*3147Sxc151355 * send a null data frame which may not be 1336*3147Sxc151355 * uinversally supported by drivers (need it 1337*3147Sxc151355 * for ps-poll support so it should be...). 1338*3147Sxc151355 */ 1339*3147Sxc151355 if (0 < in->in_inact && 1340*3147Sxc151355 in->in_inact <= im->im_inact_probe) { 1341*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "net80211: " 1342*3147Sxc151355 "probe station due to inactivity\n"); 1343*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1344*3147Sxc151355 IEEE80211_UNLOCK(ic); 1345*3147Sxc151355 (void) ieee80211_send_nulldata(in); 1346*3147Sxc151355 IEEE80211_LOCK(ic); 1347*3147Sxc151355 goto restart; 1348*3147Sxc151355 } 1349*3147Sxc151355 } 1350*3147Sxc151355 if (in->in_inact <= 0) { 1351*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "net80211: " 1352*3147Sxc151355 "station timed out due to inact (refcnt %u)\n", 1353*3147Sxc151355 ieee80211_node_refcnt(in)); 1354*3147Sxc151355 /* 1355*3147Sxc151355 * Send a deauthenticate frame and drop the station. 1356*3147Sxc151355 * This is somewhat complicated due to reference counts 1357*3147Sxc151355 * and locking. At this point a station will typically 1358*3147Sxc151355 * have a reference count of 1. ieee80211_node_leave 1359*3147Sxc151355 * will do a "free" of the node which will drop the 1360*3147Sxc151355 * reference count. But in the meantime a reference 1361*3147Sxc151355 * wil be held by the deauth frame. The actual reclaim 1362*3147Sxc151355 * of the node will happen either after the tx is 1363*3147Sxc151355 * completed or by ieee80211_node_leave. 1364*3147Sxc151355 * 1365*3147Sxc151355 * Separately we must drop the node lock before sending 1366*3147Sxc151355 * in case the driver takes a lock, as this will result 1367*3147Sxc151355 * in LOR between the node lock and the driver lock. 1368*3147Sxc151355 */ 1369*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1370*3147Sxc151355 if (in->in_associd != 0) { 1371*3147Sxc151355 IEEE80211_UNLOCK(ic); 1372*3147Sxc151355 IEEE80211_SEND_MGMT(ic, in, 1373*3147Sxc151355 IEEE80211_FC0_SUBTYPE_DEAUTH, 1374*3147Sxc151355 IEEE80211_REASON_AUTH_EXPIRE); 1375*3147Sxc151355 IEEE80211_LOCK(ic); 1376*3147Sxc151355 } 1377*3147Sxc151355 ieee80211_node_leave(ic, in); 1378*3147Sxc151355 goto restart; 1379*3147Sxc151355 } 1380*3147Sxc151355 } 1381*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1382*3147Sxc151355 1383*3147Sxc151355 IEEE80211_SCAN_UNLOCK(nt); 1384*3147Sxc151355 1385*3147Sxc151355 nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1386*3147Sxc151355 } 1387*3147Sxc151355 1388*3147Sxc151355 /* 1389*3147Sxc151355 * Call the user-defined call back function for all nodes in 1390*3147Sxc151355 * the node cache. The callback is invoked with the user-supplied 1391*3147Sxc151355 * value and a pointer to the current node. 1392*3147Sxc151355 */ 1393*3147Sxc151355 void 1394*3147Sxc151355 ieee80211_iterate_nodes(ieee80211_node_table_t *nt, ieee80211_iter_func *f, 1395*3147Sxc151355 void *arg) 1396*3147Sxc151355 { 1397*3147Sxc151355 ieee80211_node_t *in; 1398*3147Sxc151355 1399*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1400*3147Sxc151355 in = list_head(&nt->nt_node); 1401*3147Sxc151355 while (in != NULL) { 1402*3147Sxc151355 (void) ieee80211_ref_node(in); 1403*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1404*3147Sxc151355 (*f)(arg, in); 1405*3147Sxc151355 ieee80211_free_node(in); 1406*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1407*3147Sxc151355 in = list_next(&nt->nt_node, in); 1408*3147Sxc151355 } 1409*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1410*3147Sxc151355 } 1411*3147Sxc151355 1412*3147Sxc151355 /* 1413*3147Sxc151355 * Handle bookkeeping for station deauthentication/disassociation 1414*3147Sxc151355 * when operating as an ap. 1415*3147Sxc151355 */ 1416*3147Sxc151355 static void 1417*3147Sxc151355 ieee80211_node_leave(ieee80211com_t *ic, ieee80211_node_t *in) 1418*3147Sxc151355 { 1419*3147Sxc151355 ieee80211_node_table_t *nt = in->in_table; 1420*3147Sxc151355 1421*3147Sxc151355 ASSERT(ic->ic_opmode == IEEE80211_M_IBSS); 1422*3147Sxc151355 1423*3147Sxc151355 /* 1424*3147Sxc151355 * Remove the node from any table it's recorded in and 1425*3147Sxc151355 * drop the caller's reference. Removal from the table 1426*3147Sxc151355 * is important to insure the node is not reprocessed 1427*3147Sxc151355 * for inactivity. 1428*3147Sxc151355 */ 1429*3147Sxc151355 if (nt != NULL) { 1430*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1431*3147Sxc151355 ieee80211_node_reclaim(nt, in); 1432*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1433*3147Sxc151355 } else { 1434*3147Sxc151355 ieee80211_free_node(in); 1435*3147Sxc151355 } 1436*3147Sxc151355 } 1437*3147Sxc151355 1438*3147Sxc151355 /* 1439*3147Sxc151355 * Initialize a node table with specified name, inactivity timer value 1440*3147Sxc151355 * and callback inactivity timeout function. Associate the node table 1441*3147Sxc151355 * with interface softc, ic. 1442*3147Sxc151355 */ 1443*3147Sxc151355 static void 1444*3147Sxc151355 ieee80211_node_table_init(ieee80211com_t *ic, ieee80211_node_table_t *nt, 1445*3147Sxc151355 const char *name, int inact, int keyixmax, 1446*3147Sxc151355 void (*timeout)(ieee80211_node_table_t *)) 1447*3147Sxc151355 { 1448*3147Sxc151355 int i; 1449*3147Sxc151355 1450*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_init():" 1451*3147Sxc151355 "%s table, inact %d\n", name, inact); 1452*3147Sxc151355 1453*3147Sxc151355 nt->nt_ic = ic; 1454*3147Sxc151355 nt->nt_name = name; 1455*3147Sxc151355 nt->nt_inact_timer = 0; 1456*3147Sxc151355 nt->nt_inact_init = inact; 1457*3147Sxc151355 nt->nt_timeout = timeout; 1458*3147Sxc151355 nt->nt_keyixmax = keyixmax; 1459*3147Sxc151355 nt->nt_scangen = 1; 1460*3147Sxc151355 mutex_init(&nt->nt_scanlock, NULL, MUTEX_DRIVER, NULL); 1461*3147Sxc151355 mutex_init(&nt->nt_nodelock, NULL, MUTEX_DRIVER, NULL); 1462*3147Sxc151355 1463*3147Sxc151355 list_create(&nt->nt_node, sizeof (ieee80211_node_t), 1464*3147Sxc151355 offsetof(ieee80211_node_t, in_node)); 1465*3147Sxc151355 for (i = 0; i < IEEE80211_NODE_HASHSIZE; i++) { 1466*3147Sxc151355 list_create(&nt->nt_hash[i], sizeof (ieee80211_node_t), 1467*3147Sxc151355 offsetof(ieee80211_node_t, in_hash)); 1468*3147Sxc151355 } 1469*3147Sxc151355 } 1470*3147Sxc151355 1471*3147Sxc151355 /* 1472*3147Sxc151355 * Reset a node table. Clean its inactivity timer and call 1473*3147Sxc151355 * ieee80211_free_allnodes_locked() to free all nodes in the 1474*3147Sxc151355 * node table. 1475*3147Sxc151355 */ 1476*3147Sxc151355 void 1477*3147Sxc151355 ieee80211_node_table_reset(ieee80211_node_table_t *nt) 1478*3147Sxc151355 { 1479*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_reset(): " 1480*3147Sxc151355 "%s table\n", nt->nt_name); 1481*3147Sxc151355 1482*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1483*3147Sxc151355 nt->nt_inact_timer = 0; 1484*3147Sxc151355 ieee80211_free_allnodes_locked(nt); 1485*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1486*3147Sxc151355 } 1487*3147Sxc151355 1488*3147Sxc151355 /* 1489*3147Sxc151355 * Destroy a node table. Free all nodes in the node table. 1490*3147Sxc151355 * This function is usually called by node detach function. 1491*3147Sxc151355 */ 1492*3147Sxc151355 static void 1493*3147Sxc151355 ieee80211_node_table_cleanup(ieee80211_node_table_t *nt) 1494*3147Sxc151355 { 1495*3147Sxc151355 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_cleanup(): " 1496*3147Sxc151355 "%s table\n", nt->nt_name); 1497*3147Sxc151355 1498*3147Sxc151355 IEEE80211_NODE_LOCK(nt); 1499*3147Sxc151355 ieee80211_free_allnodes_locked(nt); 1500*3147Sxc151355 IEEE80211_NODE_UNLOCK(nt); 1501*3147Sxc151355 mutex_destroy(&nt->nt_nodelock); 1502*3147Sxc151355 mutex_destroy(&nt->nt_scanlock); 1503*3147Sxc151355 } 1504