1*f186073cSJoerg Sonnenberger /* 2*f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 3*f186073cSJoerg Sonnenberger * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 4*f186073cSJoerg Sonnenberger * All rights reserved. 5*f186073cSJoerg Sonnenberger * 6*f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 7*f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions 8*f186073cSJoerg Sonnenberger * are met: 9*f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 10*f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 11*f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 12*f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 13*f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 14*f186073cSJoerg Sonnenberger * 3. The name of the author may not be used to endorse or promote products 15*f186073cSJoerg Sonnenberger * derived from this software without specific prior written permission. 16*f186073cSJoerg Sonnenberger * 17*f186073cSJoerg Sonnenberger * Alternatively, this software may be distributed under the terms of the 18*f186073cSJoerg Sonnenberger * GNU General Public License ("GPL") version 2 as published by the Free 19*f186073cSJoerg Sonnenberger * Software Foundation. 20*f186073cSJoerg Sonnenberger * 21*f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22*f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23*f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24*f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25*f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26*f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27*f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28*f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29*f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30*f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*f186073cSJoerg Sonnenberger * 32*f186073cSJoerg Sonnenberger * $FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.22 2004/04/05 04:15:55 sam Exp $ 33*f186073cSJoerg Sonnenberger * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.1 2004/07/26 16:30:17 joerg Exp $ 34*f186073cSJoerg Sonnenberger */ 35*f186073cSJoerg Sonnenberger 36*f186073cSJoerg Sonnenberger #include "opt_inet.h" 37*f186073cSJoerg Sonnenberger 38*f186073cSJoerg Sonnenberger #include <sys/param.h> 39*f186073cSJoerg Sonnenberger #include <sys/systm.h> 40*f186073cSJoerg Sonnenberger #include <sys/mbuf.h> 41*f186073cSJoerg Sonnenberger #include <sys/malloc.h> 42*f186073cSJoerg Sonnenberger #include <sys/kernel.h> 43*f186073cSJoerg Sonnenberger #include <sys/socket.h> 44*f186073cSJoerg Sonnenberger #include <sys/sockio.h> 45*f186073cSJoerg Sonnenberger #include <sys/endian.h> 46*f186073cSJoerg Sonnenberger #include <sys/errno.h> 47*f186073cSJoerg Sonnenberger #include <sys/bus.h> 48*f186073cSJoerg Sonnenberger #include <sys/proc.h> 49*f186073cSJoerg Sonnenberger #include <sys/sysctl.h> 50*f186073cSJoerg Sonnenberger #include <sys/thread.h> 51*f186073cSJoerg Sonnenberger #include <sys/thread2.h> 52*f186073cSJoerg Sonnenberger 53*f186073cSJoerg Sonnenberger #include <machine/atomic.h> 54*f186073cSJoerg Sonnenberger 55*f186073cSJoerg Sonnenberger #include <net/if.h> 56*f186073cSJoerg Sonnenberger #include <net/if_dl.h> 57*f186073cSJoerg Sonnenberger #include <net/if_media.h> 58*f186073cSJoerg Sonnenberger #include <net/if_arp.h> 59*f186073cSJoerg Sonnenberger #include <net/ethernet.h> 60*f186073cSJoerg Sonnenberger #include <net/if_llc.h> 61*f186073cSJoerg Sonnenberger 62*f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h> 63*f186073cSJoerg Sonnenberger 64*f186073cSJoerg Sonnenberger #include <net/bpf.h> 65*f186073cSJoerg Sonnenberger 66*f186073cSJoerg Sonnenberger #ifdef INET 67*f186073cSJoerg Sonnenberger #include <netinet/in.h> 68*f186073cSJoerg Sonnenberger #include <netinet/if_ether.h> 69*f186073cSJoerg Sonnenberger #endif 70*f186073cSJoerg Sonnenberger 71*f186073cSJoerg Sonnenberger static struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *); 72*f186073cSJoerg Sonnenberger static void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *); 73*f186073cSJoerg Sonnenberger static void ieee80211_node_copy(struct ieee80211com *, 74*f186073cSJoerg Sonnenberger struct ieee80211_node *, const struct ieee80211_node *); 75*f186073cSJoerg Sonnenberger static uint8_t ieee80211_node_getrssi(struct ieee80211com *, 76*f186073cSJoerg Sonnenberger struct ieee80211_node *); 77*f186073cSJoerg Sonnenberger 78*f186073cSJoerg Sonnenberger static void ieee80211_setup_node(struct ieee80211com *ic, 79*f186073cSJoerg Sonnenberger struct ieee80211_node *ni, uint8_t *macaddr); 80*f186073cSJoerg Sonnenberger static void _ieee80211_free_node(struct ieee80211com *, 81*f186073cSJoerg Sonnenberger struct ieee80211_node *); 82*f186073cSJoerg Sonnenberger 83*f186073cSJoerg Sonnenberger MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 84*f186073cSJoerg Sonnenberger 85*f186073cSJoerg Sonnenberger void 86*f186073cSJoerg Sonnenberger ieee80211_node_attach(struct ifnet *ifp) 87*f186073cSJoerg Sonnenberger { 88*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 89*f186073cSJoerg Sonnenberger 90*f186073cSJoerg Sonnenberger lwkt_token_init(&ic->ic_nodetoken); 91*f186073cSJoerg Sonnenberger TAILQ_INIT(&ic->ic_node); 92*f186073cSJoerg Sonnenberger ic->ic_node_alloc = ieee80211_node_alloc; 93*f186073cSJoerg Sonnenberger ic->ic_node_free = ieee80211_node_free; 94*f186073cSJoerg Sonnenberger ic->ic_node_copy = ieee80211_node_copy; 95*f186073cSJoerg Sonnenberger ic->ic_node_getrssi = ieee80211_node_getrssi; 96*f186073cSJoerg Sonnenberger ic->ic_scangen = 1; 97*f186073cSJoerg Sonnenberger } 98*f186073cSJoerg Sonnenberger 99*f186073cSJoerg Sonnenberger void 100*f186073cSJoerg Sonnenberger ieee80211_node_lateattach(struct ifnet *ifp) 101*f186073cSJoerg Sonnenberger { 102*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 103*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 104*f186073cSJoerg Sonnenberger 105*f186073cSJoerg Sonnenberger ni = (*ic->ic_node_alloc)(ic); 106*f186073cSJoerg Sonnenberger KASSERT(ni != NULL, ("unable to setup inital BSS node")); 107*f186073cSJoerg Sonnenberger ni->ni_chan = IEEE80211_CHAN_ANYC; 108*f186073cSJoerg Sonnenberger ic->ic_bss = ni; 109*f186073cSJoerg Sonnenberger ic->ic_txpower = IEEE80211_TXPOWER_MAX; 110*f186073cSJoerg Sonnenberger } 111*f186073cSJoerg Sonnenberger 112*f186073cSJoerg Sonnenberger void 113*f186073cSJoerg Sonnenberger ieee80211_node_detach(struct ifnet *ifp) 114*f186073cSJoerg Sonnenberger { 115*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 116*f186073cSJoerg Sonnenberger 117*f186073cSJoerg Sonnenberger if (ic->ic_bss != NULL) 118*f186073cSJoerg Sonnenberger (*ic->ic_node_free)(ic, ic->ic_bss); 119*f186073cSJoerg Sonnenberger ieee80211_free_allnodes(ic); 120*f186073cSJoerg Sonnenberger lwkt_token_uninit(&ic->ic_nodetoken); 121*f186073cSJoerg Sonnenberger } 122*f186073cSJoerg Sonnenberger 123*f186073cSJoerg Sonnenberger /* 124*f186073cSJoerg Sonnenberger * AP scanning support. 125*f186073cSJoerg Sonnenberger */ 126*f186073cSJoerg Sonnenberger 127*f186073cSJoerg Sonnenberger /* 128*f186073cSJoerg Sonnenberger * Initialize the active channel set based on the set 129*f186073cSJoerg Sonnenberger * of available channels and the current PHY mode. 130*f186073cSJoerg Sonnenberger */ 131*f186073cSJoerg Sonnenberger static void 132*f186073cSJoerg Sonnenberger ieee80211_reset_scan(struct ifnet *ifp) 133*f186073cSJoerg Sonnenberger { 134*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 135*f186073cSJoerg Sonnenberger 136*f186073cSJoerg Sonnenberger memcpy(ic->ic_chan_scan, ic->ic_chan_active, 137*f186073cSJoerg Sonnenberger sizeof(ic->ic_chan_active)); 138*f186073cSJoerg Sonnenberger /* NB: hack, setup so next_scan starts with the first channel */ 139*f186073cSJoerg Sonnenberger if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC) 140*f186073cSJoerg Sonnenberger ic->ic_bss->ni_chan = &ic->ic_channels[IEEE80211_CHAN_MAX]; 141*f186073cSJoerg Sonnenberger } 142*f186073cSJoerg Sonnenberger 143*f186073cSJoerg Sonnenberger /* 144*f186073cSJoerg Sonnenberger * Begin an active scan. 145*f186073cSJoerg Sonnenberger */ 146*f186073cSJoerg Sonnenberger void 147*f186073cSJoerg Sonnenberger ieee80211_begin_scan(struct ifnet *ifp) 148*f186073cSJoerg Sonnenberger { 149*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 150*f186073cSJoerg Sonnenberger 151*f186073cSJoerg Sonnenberger /* 152*f186073cSJoerg Sonnenberger * In all but hostap mode scanning starts off in 153*f186073cSJoerg Sonnenberger * an active mode before switching to passive. 154*f186073cSJoerg Sonnenberger */ 155*f186073cSJoerg Sonnenberger if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 156*f186073cSJoerg Sonnenberger ic->ic_flags |= IEEE80211_F_ASCAN; 157*f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_active++; 158*f186073cSJoerg Sonnenberger } else 159*f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_passive++; 160*f186073cSJoerg Sonnenberger if (ifp->if_flags & IFF_DEBUG) 161*f186073cSJoerg Sonnenberger if_printf(ifp, "begin %s scan\n", 162*f186073cSJoerg Sonnenberger (ic->ic_flags & IEEE80211_F_ASCAN) ? 163*f186073cSJoerg Sonnenberger "active" : "passive"); 164*f186073cSJoerg Sonnenberger /* 165*f186073cSJoerg Sonnenberger * Clear scan state and flush any previously seen 166*f186073cSJoerg Sonnenberger * AP's. Note that the latter assumes we don't act 167*f186073cSJoerg Sonnenberger * as both an AP and a station, otherwise we'll 168*f186073cSJoerg Sonnenberger * potentially flush state of stations associated 169*f186073cSJoerg Sonnenberger * with us. 170*f186073cSJoerg Sonnenberger */ 171*f186073cSJoerg Sonnenberger ieee80211_reset_scan(ifp); 172*f186073cSJoerg Sonnenberger ieee80211_free_allnodes(ic); 173*f186073cSJoerg Sonnenberger 174*f186073cSJoerg Sonnenberger /* Scan the next channel. */ 175*f186073cSJoerg Sonnenberger ieee80211_next_scan(ifp); 176*f186073cSJoerg Sonnenberger } 177*f186073cSJoerg Sonnenberger 178*f186073cSJoerg Sonnenberger /* 179*f186073cSJoerg Sonnenberger * Switch to the next channel marked for scanning. 180*f186073cSJoerg Sonnenberger */ 181*f186073cSJoerg Sonnenberger void 182*f186073cSJoerg Sonnenberger ieee80211_next_scan(struct ifnet *ifp) 183*f186073cSJoerg Sonnenberger { 184*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 185*f186073cSJoerg Sonnenberger struct ieee80211_channel *chan; 186*f186073cSJoerg Sonnenberger 187*f186073cSJoerg Sonnenberger chan = ic->ic_bss->ni_chan; 188*f186073cSJoerg Sonnenberger for (;;) { 189*f186073cSJoerg Sonnenberger if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) 190*f186073cSJoerg Sonnenberger chan = &ic->ic_channels[0]; 191*f186073cSJoerg Sonnenberger if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) { 192*f186073cSJoerg Sonnenberger /* 193*f186073cSJoerg Sonnenberger * Honor channels marked passive-only 194*f186073cSJoerg Sonnenberger * during an active scan. 195*f186073cSJoerg Sonnenberger */ 196*f186073cSJoerg Sonnenberger if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 || 197*f186073cSJoerg Sonnenberger (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) 198*f186073cSJoerg Sonnenberger break; 199*f186073cSJoerg Sonnenberger } 200*f186073cSJoerg Sonnenberger if (chan == ic->ic_bss->ni_chan) { 201*f186073cSJoerg Sonnenberger ieee80211_end_scan(ifp); 202*f186073cSJoerg Sonnenberger return; 203*f186073cSJoerg Sonnenberger } 204*f186073cSJoerg Sonnenberger } 205*f186073cSJoerg Sonnenberger clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); 206*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("ieee80211_next_scan: chan %d->%d\n", 207*f186073cSJoerg Sonnenberger ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan), 208*f186073cSJoerg Sonnenberger ieee80211_chan2ieee(ic, chan))); 209*f186073cSJoerg Sonnenberger ic->ic_bss->ni_chan = chan; 210*f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 211*f186073cSJoerg Sonnenberger } 212*f186073cSJoerg Sonnenberger 213*f186073cSJoerg Sonnenberger void 214*f186073cSJoerg Sonnenberger ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) 215*f186073cSJoerg Sonnenberger { 216*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 217*f186073cSJoerg Sonnenberger struct ifnet *ifp = &ic->ic_if; 218*f186073cSJoerg Sonnenberger 219*f186073cSJoerg Sonnenberger ni = ic->ic_bss; 220*f186073cSJoerg Sonnenberger if (ifp->if_flags & IFF_DEBUG) 221*f186073cSJoerg Sonnenberger if_printf(ifp, "creating ibss\n"); 222*f186073cSJoerg Sonnenberger ic->ic_flags |= IEEE80211_F_SIBSS; 223*f186073cSJoerg Sonnenberger ni->ni_chan = chan; 224*f186073cSJoerg Sonnenberger ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 225*f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); 226*f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); 227*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) 228*f186073cSJoerg Sonnenberger ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ 229*f186073cSJoerg Sonnenberger ni->ni_esslen = ic->ic_des_esslen; 230*f186073cSJoerg Sonnenberger memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); 231*f186073cSJoerg Sonnenberger ni->ni_rssi = 0; 232*f186073cSJoerg Sonnenberger ni->ni_rstamp = 0; 233*f186073cSJoerg Sonnenberger memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); 234*f186073cSJoerg Sonnenberger ni->ni_intval = ic->ic_lintval; 235*f186073cSJoerg Sonnenberger ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; 236*f186073cSJoerg Sonnenberger if (ic->ic_flags & IEEE80211_F_WEPON) 237*f186073cSJoerg Sonnenberger ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 238*f186073cSJoerg Sonnenberger if (ic->ic_phytype == IEEE80211_T_FH) { 239*f186073cSJoerg Sonnenberger ni->ni_fhdwell = 200; /* XXX */ 240*f186073cSJoerg Sonnenberger ni->ni_fhindex = 1; 241*f186073cSJoerg Sonnenberger } 242*f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 243*f186073cSJoerg Sonnenberger } 244*f186073cSJoerg Sonnenberger 245*f186073cSJoerg Sonnenberger static int 246*f186073cSJoerg Sonnenberger ieee80211_match_bss(struct ifnet *ifp, struct ieee80211_node *ni) 247*f186073cSJoerg Sonnenberger { 248*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 249*f186073cSJoerg Sonnenberger uint8_t rate; 250*f186073cSJoerg Sonnenberger int fail; 251*f186073cSJoerg Sonnenberger 252*f186073cSJoerg Sonnenberger fail = 0; 253*f186073cSJoerg Sonnenberger if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 254*f186073cSJoerg Sonnenberger fail |= 0x01; 255*f186073cSJoerg Sonnenberger if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 256*f186073cSJoerg Sonnenberger ni->ni_chan != ic->ic_des_chan) 257*f186073cSJoerg Sonnenberger fail |= 0x01; 258*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 259*f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 260*f186073cSJoerg Sonnenberger fail |= 0x02; 261*f186073cSJoerg Sonnenberger } else { 262*f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 263*f186073cSJoerg Sonnenberger fail |= 0x02; 264*f186073cSJoerg Sonnenberger } 265*f186073cSJoerg Sonnenberger if (ic->ic_flags & IEEE80211_F_WEPON) { 266*f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 267*f186073cSJoerg Sonnenberger fail |= 0x04; 268*f186073cSJoerg Sonnenberger } else { 269*f186073cSJoerg Sonnenberger /* XXX does this mean privacy is supported or required? */ 270*f186073cSJoerg Sonnenberger if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 271*f186073cSJoerg Sonnenberger fail |= 0x04; 272*f186073cSJoerg Sonnenberger } 273*f186073cSJoerg Sonnenberger rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); 274*f186073cSJoerg Sonnenberger if (rate & IEEE80211_RATE_BASIC) 275*f186073cSJoerg Sonnenberger fail |= 0x08; 276*f186073cSJoerg Sonnenberger if (ic->ic_des_esslen != 0 && 277*f186073cSJoerg Sonnenberger (ni->ni_esslen != ic->ic_des_esslen || 278*f186073cSJoerg Sonnenberger memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) 279*f186073cSJoerg Sonnenberger fail |= 0x10; 280*f186073cSJoerg Sonnenberger if ((ic->ic_flags & IEEE80211_F_DESBSSID) && 281*f186073cSJoerg Sonnenberger !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) 282*f186073cSJoerg Sonnenberger fail |= 0x20; 283*f186073cSJoerg Sonnenberger #ifdef IEEE80211_DEBUG 284*f186073cSJoerg Sonnenberger if (ifp->if_flags & IFF_DEBUG) { 285*f186073cSJoerg Sonnenberger printf(" %c %6D", fail ? '-' : '+', ni->ni_macaddr, ":"); 286*f186073cSJoerg Sonnenberger printf(" %6D%c", ni->ni_bssid, ":", fail & 0x20 ? '!' : ' '); 287*f186073cSJoerg Sonnenberger printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), 288*f186073cSJoerg Sonnenberger fail & 0x01 ? '!' : ' '); 289*f186073cSJoerg Sonnenberger printf(" %+4d", ni->ni_rssi); 290*f186073cSJoerg Sonnenberger printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 291*f186073cSJoerg Sonnenberger fail & 0x08 ? '!' : ' '); 292*f186073cSJoerg Sonnenberger printf(" %4s%c", 293*f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 294*f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 295*f186073cSJoerg Sonnenberger "????", 296*f186073cSJoerg Sonnenberger fail & 0x02 ? '!' : ' '); 297*f186073cSJoerg Sonnenberger printf(" %3s%c ", 298*f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? 299*f186073cSJoerg Sonnenberger "wep" : "no", 300*f186073cSJoerg Sonnenberger fail & 0x04 ? '!' : ' '); 301*f186073cSJoerg Sonnenberger ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 302*f186073cSJoerg Sonnenberger printf("%s\n", fail & 0x10 ? "!" : ""); 303*f186073cSJoerg Sonnenberger } 304*f186073cSJoerg Sonnenberger #endif 305*f186073cSJoerg Sonnenberger return fail; 306*f186073cSJoerg Sonnenberger } 307*f186073cSJoerg Sonnenberger 308*f186073cSJoerg Sonnenberger /* 309*f186073cSJoerg Sonnenberger * Complete a scan of potential channels. 310*f186073cSJoerg Sonnenberger */ 311*f186073cSJoerg Sonnenberger void 312*f186073cSJoerg Sonnenberger ieee80211_end_scan(struct ifnet *ifp) 313*f186073cSJoerg Sonnenberger { 314*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 315*f186073cSJoerg Sonnenberger struct ieee80211_node *ni, *nextbs, *selbs; 316*f186073cSJoerg Sonnenberger int i, fail; 317*f186073cSJoerg Sonnenberger 318*f186073cSJoerg Sonnenberger ic->ic_flags &= ~IEEE80211_F_ASCAN; 319*f186073cSJoerg Sonnenberger ni = TAILQ_FIRST(&ic->ic_node); 320*f186073cSJoerg Sonnenberger 321*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 322*f186073cSJoerg Sonnenberger /* XXX off stack? */ 323*f186073cSJoerg Sonnenberger u_char occupied[roundup(IEEE80211_CHAN_MAX, NBBY)]; 324*f186073cSJoerg Sonnenberger /* 325*f186073cSJoerg Sonnenberger * The passive scan to look for existing AP's completed, 326*f186073cSJoerg Sonnenberger * select a channel to camp on. Identify the channels 327*f186073cSJoerg Sonnenberger * that already have one or more AP's and try to locate 328*f186073cSJoerg Sonnenberger * an unnoccupied one. If that fails, pick a random 329*f186073cSJoerg Sonnenberger * channel from the active set. 330*f186073cSJoerg Sonnenberger */ 331*f186073cSJoerg Sonnenberger for (; ni != NULL; ni = nextbs) { 332*f186073cSJoerg Sonnenberger ieee80211_ref_node(ni); 333*f186073cSJoerg Sonnenberger nextbs = TAILQ_NEXT(ni, ni_list); 334*f186073cSJoerg Sonnenberger setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan)); 335*f186073cSJoerg Sonnenberger ieee80211_free_node(ic, ni); 336*f186073cSJoerg Sonnenberger } 337*f186073cSJoerg Sonnenberger for (i = 0; i < IEEE80211_CHAN_MAX; i++) 338*f186073cSJoerg Sonnenberger if (isset(ic->ic_chan_active, i) && isclr(occupied, i)) 339*f186073cSJoerg Sonnenberger break; 340*f186073cSJoerg Sonnenberger if (i == IEEE80211_CHAN_MAX) { 341*f186073cSJoerg Sonnenberger fail = arc4random() & 3; /* random 0-3 */ 342*f186073cSJoerg Sonnenberger for (i = 0; i < IEEE80211_CHAN_MAX; i++) 343*f186073cSJoerg Sonnenberger if (isset(ic->ic_chan_active, i) && fail-- == 0) 344*f186073cSJoerg Sonnenberger break; 345*f186073cSJoerg Sonnenberger } 346*f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, &ic->ic_channels[i]); 347*f186073cSJoerg Sonnenberger return; 348*f186073cSJoerg Sonnenberger } 349*f186073cSJoerg Sonnenberger if (ni == NULL) { 350*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("%s: no scan candidate\n", __func__)); 351*f186073cSJoerg Sonnenberger notfound: 352*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS && 353*f186073cSJoerg Sonnenberger (ic->ic_flags & IEEE80211_F_IBSSON) && 354*f186073cSJoerg Sonnenberger ic->ic_des_esslen != 0) { 355*f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_ibss_chan); 356*f186073cSJoerg Sonnenberger return; 357*f186073cSJoerg Sonnenberger } 358*f186073cSJoerg Sonnenberger /* 359*f186073cSJoerg Sonnenberger * Reset the list of channels to scan and start again. 360*f186073cSJoerg Sonnenberger */ 361*f186073cSJoerg Sonnenberger ieee80211_reset_scan(ifp); 362*f186073cSJoerg Sonnenberger ieee80211_next_scan(ifp); 363*f186073cSJoerg Sonnenberger return; 364*f186073cSJoerg Sonnenberger } 365*f186073cSJoerg Sonnenberger selbs = NULL; 366*f186073cSJoerg Sonnenberger if (ifp->if_flags & IFF_DEBUG) 367*f186073cSJoerg Sonnenberger if_printf(ifp, "\tmacaddr bssid chan rssi rate flag wep essid\n"); 368*f186073cSJoerg Sonnenberger for (; ni != NULL; ni = nextbs) { 369*f186073cSJoerg Sonnenberger ieee80211_ref_node(ni); 370*f186073cSJoerg Sonnenberger nextbs = TAILQ_NEXT(ni, ni_list); 371*f186073cSJoerg Sonnenberger if (ni->ni_fails) { 372*f186073cSJoerg Sonnenberger /* 373*f186073cSJoerg Sonnenberger * The configuration of the access points may change 374*f186073cSJoerg Sonnenberger * during my scan. So delete the entry for the AP 375*f186073cSJoerg Sonnenberger * and retry to associate if there is another beacon. 376*f186073cSJoerg Sonnenberger */ 377*f186073cSJoerg Sonnenberger if (ni->ni_fails++ > 2) 378*f186073cSJoerg Sonnenberger ieee80211_free_node(ic, ni); 379*f186073cSJoerg Sonnenberger continue; 380*f186073cSJoerg Sonnenberger } 381*f186073cSJoerg Sonnenberger if (ieee80211_match_bss(ifp, ni) == 0) { 382*f186073cSJoerg Sonnenberger if (selbs == NULL) 383*f186073cSJoerg Sonnenberger selbs = ni; 384*f186073cSJoerg Sonnenberger else if (ni->ni_rssi > selbs->ni_rssi) { 385*f186073cSJoerg Sonnenberger ieee80211_unref_node(&selbs); 386*f186073cSJoerg Sonnenberger selbs = ni; 387*f186073cSJoerg Sonnenberger } else 388*f186073cSJoerg Sonnenberger ieee80211_unref_node(&ni); 389*f186073cSJoerg Sonnenberger } else { 390*f186073cSJoerg Sonnenberger ieee80211_unref_node(&ni); 391*f186073cSJoerg Sonnenberger } 392*f186073cSJoerg Sonnenberger } 393*f186073cSJoerg Sonnenberger if (selbs == NULL) 394*f186073cSJoerg Sonnenberger goto notfound; 395*f186073cSJoerg Sonnenberger (*ic->ic_node_copy)(ic, ic->ic_bss, selbs); 396*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 397*f186073cSJoerg Sonnenberger ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE | 398*f186073cSJoerg Sonnenberger IEEE80211_F_DONEGO | IEEE80211_F_DODEL); 399*f186073cSJoerg Sonnenberger if (ic->ic_bss->ni_rates.rs_nrates == 0) { 400*f186073cSJoerg Sonnenberger selbs->ni_fails++; 401*f186073cSJoerg Sonnenberger ieee80211_unref_node(&selbs); 402*f186073cSJoerg Sonnenberger goto notfound; 403*f186073cSJoerg Sonnenberger } 404*f186073cSJoerg Sonnenberger ieee80211_unref_node(&selbs); 405*f186073cSJoerg Sonnenberger /* 406*f186073cSJoerg Sonnenberger * Discard scan set; the nodes have a refcnt of zero 407*f186073cSJoerg Sonnenberger * and have not asked the driver to setup private 408*f186073cSJoerg Sonnenberger * node state. Let them be repopulated on demand either 409*f186073cSJoerg Sonnenberger * through transmission (ieee80211_find_txnode) or receipt 410*f186073cSJoerg Sonnenberger * of a probe response (to be added). 411*f186073cSJoerg Sonnenberger */ 412*f186073cSJoerg Sonnenberger ieee80211_free_allnodes(ic); 413*f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 414*f186073cSJoerg Sonnenberger } else { 415*f186073cSJoerg Sonnenberger ieee80211_unref_node(&selbs); 416*f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 417*f186073cSJoerg Sonnenberger } 418*f186073cSJoerg Sonnenberger } 419*f186073cSJoerg Sonnenberger 420*f186073cSJoerg Sonnenberger static struct ieee80211_node * 421*f186073cSJoerg Sonnenberger ieee80211_node_alloc(struct ieee80211com *ic) 422*f186073cSJoerg Sonnenberger { 423*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 424*f186073cSJoerg Sonnenberger MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node), 425*f186073cSJoerg Sonnenberger M_80211_NODE, M_NOWAIT | M_ZERO); 426*f186073cSJoerg Sonnenberger return ni; 427*f186073cSJoerg Sonnenberger } 428*f186073cSJoerg Sonnenberger 429*f186073cSJoerg Sonnenberger static void 430*f186073cSJoerg Sonnenberger ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni) 431*f186073cSJoerg Sonnenberger { 432*f186073cSJoerg Sonnenberger FREE(ni, M_80211_NODE); 433*f186073cSJoerg Sonnenberger } 434*f186073cSJoerg Sonnenberger 435*f186073cSJoerg Sonnenberger static void 436*f186073cSJoerg Sonnenberger ieee80211_node_copy(struct ieee80211com *ic, 437*f186073cSJoerg Sonnenberger struct ieee80211_node *dst, const struct ieee80211_node *src) 438*f186073cSJoerg Sonnenberger { 439*f186073cSJoerg Sonnenberger *dst = *src; 440*f186073cSJoerg Sonnenberger } 441*f186073cSJoerg Sonnenberger 442*f186073cSJoerg Sonnenberger static uint8_t 443*f186073cSJoerg Sonnenberger ieee80211_node_getrssi(struct ieee80211com *ic, struct ieee80211_node *ni) 444*f186073cSJoerg Sonnenberger { 445*f186073cSJoerg Sonnenberger return ni->ni_rssi; 446*f186073cSJoerg Sonnenberger } 447*f186073cSJoerg Sonnenberger 448*f186073cSJoerg Sonnenberger static void 449*f186073cSJoerg Sonnenberger ieee80211_setup_node(struct ieee80211com *ic, 450*f186073cSJoerg Sonnenberger struct ieee80211_node *ni, uint8_t *macaddr) 451*f186073cSJoerg Sonnenberger { 452*f186073cSJoerg Sonnenberger lwkt_tokref ilock; 453*f186073cSJoerg Sonnenberger int hash; 454*f186073cSJoerg Sonnenberger 455*f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 456*f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 457*f186073cSJoerg Sonnenberger ni->ni_refcnt = 1; /* mark referenced */ 458*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 459*f186073cSJoerg Sonnenberger TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list); 460*f186073cSJoerg Sonnenberger LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash); 461*f186073cSJoerg Sonnenberger /* 462*f186073cSJoerg Sonnenberger * Note we don't enable the inactive timer when acting 463*f186073cSJoerg Sonnenberger * as a station. Nodes created in this mode represent 464*f186073cSJoerg Sonnenberger * AP's identified while scanning. If we time them out 465*f186073cSJoerg Sonnenberger * then several things happen: we can't return the data 466*f186073cSJoerg Sonnenberger * to users to show the list of AP's we encountered, and 467*f186073cSJoerg Sonnenberger * more importantly, we'll incorrectly deauthenticate 468*f186073cSJoerg Sonnenberger * ourself because the inactivity timer will kick us off. 469*f186073cSJoerg Sonnenberger */ 470*f186073cSJoerg Sonnenberger if (ic->ic_opmode != IEEE80211_M_STA) 471*f186073cSJoerg Sonnenberger ic->ic_inact_timer = IEEE80211_INACT_WAIT; 472*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 473*f186073cSJoerg Sonnenberger } 474*f186073cSJoerg Sonnenberger 475*f186073cSJoerg Sonnenberger struct ieee80211_node * 476*f186073cSJoerg Sonnenberger ieee80211_alloc_node(struct ieee80211com *ic, uint8_t *macaddr) 477*f186073cSJoerg Sonnenberger { 478*f186073cSJoerg Sonnenberger struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic); 479*f186073cSJoerg Sonnenberger if (ni != NULL) 480*f186073cSJoerg Sonnenberger ieee80211_setup_node(ic, ni, macaddr); 481*f186073cSJoerg Sonnenberger else 482*f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 483*f186073cSJoerg Sonnenberger return ni; 484*f186073cSJoerg Sonnenberger } 485*f186073cSJoerg Sonnenberger 486*f186073cSJoerg Sonnenberger struct ieee80211_node * 487*f186073cSJoerg Sonnenberger ieee80211_dup_bss(struct ieee80211com *ic, uint8_t *macaddr) 488*f186073cSJoerg Sonnenberger { 489*f186073cSJoerg Sonnenberger struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic); 490*f186073cSJoerg Sonnenberger if (ni != NULL) { 491*f186073cSJoerg Sonnenberger ieee80211_setup_node(ic, ni, macaddr); 492*f186073cSJoerg Sonnenberger /* 493*f186073cSJoerg Sonnenberger * Inherit from ic_bss. 494*f186073cSJoerg Sonnenberger */ 495*f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 496*f186073cSJoerg Sonnenberger ni->ni_chan = ic->ic_bss->ni_chan; 497*f186073cSJoerg Sonnenberger } else 498*f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 499*f186073cSJoerg Sonnenberger return ni; 500*f186073cSJoerg Sonnenberger } 501*f186073cSJoerg Sonnenberger 502*f186073cSJoerg Sonnenberger static struct ieee80211_node * 503*f186073cSJoerg Sonnenberger _ieee80211_find_node(struct ieee80211com *ic, uint8_t *macaddr) 504*f186073cSJoerg Sonnenberger { 505*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 506*f186073cSJoerg Sonnenberger int hash; 507*f186073cSJoerg Sonnenberger 508*f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 509*f186073cSJoerg Sonnenberger LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { 510*f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 511*f186073cSJoerg Sonnenberger atomic_add_int(&ni->ni_refcnt, 1);/* mark referenced */ 512*f186073cSJoerg Sonnenberger return ni; 513*f186073cSJoerg Sonnenberger } 514*f186073cSJoerg Sonnenberger } 515*f186073cSJoerg Sonnenberger return NULL; 516*f186073cSJoerg Sonnenberger } 517*f186073cSJoerg Sonnenberger 518*f186073cSJoerg Sonnenberger struct ieee80211_node * 519*f186073cSJoerg Sonnenberger ieee80211_find_node(struct ieee80211com *ic, uint8_t *macaddr) 520*f186073cSJoerg Sonnenberger { 521*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 522*f186073cSJoerg Sonnenberger struct lwkt_tokref ilock; 523*f186073cSJoerg Sonnenberger 524*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 525*f186073cSJoerg Sonnenberger ni = _ieee80211_find_node(ic, macaddr); 526*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 527*f186073cSJoerg Sonnenberger return ni; 528*f186073cSJoerg Sonnenberger } 529*f186073cSJoerg Sonnenberger 530*f186073cSJoerg Sonnenberger /* 531*f186073cSJoerg Sonnenberger * Return a reference to the appropriate node for sending 532*f186073cSJoerg Sonnenberger * a data frame. This handles node discovery in adhoc networks. 533*f186073cSJoerg Sonnenberger */ 534*f186073cSJoerg Sonnenberger struct ieee80211_node * 535*f186073cSJoerg Sonnenberger ieee80211_find_txnode(struct ieee80211com *ic, uint8_t *macaddr) 536*f186073cSJoerg Sonnenberger { 537*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 538*f186073cSJoerg Sonnenberger struct lwkt_tokref ilock; 539*f186073cSJoerg Sonnenberger 540*f186073cSJoerg Sonnenberger /* 541*f186073cSJoerg Sonnenberger * The destination address should be in the node table 542*f186073cSJoerg Sonnenberger * unless we are operating in station mode or this is a 543*f186073cSJoerg Sonnenberger * multicast/broadcast frame. 544*f186073cSJoerg Sonnenberger */ 545*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) 546*f186073cSJoerg Sonnenberger return ic->ic_bss; 547*f186073cSJoerg Sonnenberger 548*f186073cSJoerg Sonnenberger /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ 549*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 550*f186073cSJoerg Sonnenberger ni = _ieee80211_find_node(ic, macaddr); 551*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 552*f186073cSJoerg Sonnenberger ni = _ieee80211_find_node(ic, macaddr); 553*f186073cSJoerg Sonnenberger if (ni == NULL && 554*f186073cSJoerg Sonnenberger (ic->ic_opmode == IEEE80211_M_IBSS || 555*f186073cSJoerg Sonnenberger ic->ic_opmode == IEEE80211_M_AHDEMO)) { 556*f186073cSJoerg Sonnenberger /* 557*f186073cSJoerg Sonnenberger * Fake up a node; this handles node discovery in 558*f186073cSJoerg Sonnenberger * adhoc mode. Note that for the driver's benefit 559*f186073cSJoerg Sonnenberger * we we treat this like an association so the driver 560*f186073cSJoerg Sonnenberger * has an opportunity to setup it's private state. 561*f186073cSJoerg Sonnenberger * 562*f186073cSJoerg Sonnenberger * XXX need better way to handle this; issue probe 563*f186073cSJoerg Sonnenberger * request so we can deduce rate set, etc. 564*f186073cSJoerg Sonnenberger */ 565*f186073cSJoerg Sonnenberger ni = ieee80211_dup_bss(ic, macaddr); 566*f186073cSJoerg Sonnenberger if (ni != NULL) { 567*f186073cSJoerg Sonnenberger /* XXX no rate negotiation; just dup */ 568*f186073cSJoerg Sonnenberger ni->ni_rates = ic->ic_bss->ni_rates; 569*f186073cSJoerg Sonnenberger if (ic->ic_newassoc) 570*f186073cSJoerg Sonnenberger (*ic->ic_newassoc)(ic, ni, 1); 571*f186073cSJoerg Sonnenberger } 572*f186073cSJoerg Sonnenberger } 573*f186073cSJoerg Sonnenberger return ni; 574*f186073cSJoerg Sonnenberger } 575*f186073cSJoerg Sonnenberger 576*f186073cSJoerg Sonnenberger /* 577*f186073cSJoerg Sonnenberger * Like find but search based on the channel too. 578*f186073cSJoerg Sonnenberger */ 579*f186073cSJoerg Sonnenberger struct ieee80211_node * 580*f186073cSJoerg Sonnenberger ieee80211_lookup_node(struct ieee80211com *ic, 581*f186073cSJoerg Sonnenberger uint8_t *macaddr, struct ieee80211_channel *chan) 582*f186073cSJoerg Sonnenberger { 583*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 584*f186073cSJoerg Sonnenberger int hash; 585*f186073cSJoerg Sonnenberger lwkt_tokref ilock; 586*f186073cSJoerg Sonnenberger 587*f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 588*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 589*f186073cSJoerg Sonnenberger LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { 590*f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 591*f186073cSJoerg Sonnenberger ni->ni_chan == chan) { 592*f186073cSJoerg Sonnenberger atomic_add_int(&ni->ni_refcnt, 1);/* mark referenced */ 593*f186073cSJoerg Sonnenberger break; 594*f186073cSJoerg Sonnenberger } 595*f186073cSJoerg Sonnenberger } 596*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 597*f186073cSJoerg Sonnenberger return ni; 598*f186073cSJoerg Sonnenberger } 599*f186073cSJoerg Sonnenberger 600*f186073cSJoerg Sonnenberger static void 601*f186073cSJoerg Sonnenberger _ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni) 602*f186073cSJoerg Sonnenberger { 603*f186073cSJoerg Sonnenberger KASSERT(ni != ic->ic_bss, ("freeing bss node")); 604*f186073cSJoerg Sonnenberger 605*f186073cSJoerg Sonnenberger TAILQ_REMOVE(&ic->ic_node, ni, ni_list); 606*f186073cSJoerg Sonnenberger LIST_REMOVE(ni, ni_hash); 607*f186073cSJoerg Sonnenberger if (TAILQ_EMPTY(&ic->ic_node)) 608*f186073cSJoerg Sonnenberger ic->ic_inact_timer = 0; 609*f186073cSJoerg Sonnenberger (*ic->ic_node_free)(ic, ni); 610*f186073cSJoerg Sonnenberger } 611*f186073cSJoerg Sonnenberger 612*f186073cSJoerg Sonnenberger void 613*f186073cSJoerg Sonnenberger ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni) 614*f186073cSJoerg Sonnenberger { 615*f186073cSJoerg Sonnenberger lwkt_tokref ilock; 616*f186073cSJoerg Sonnenberger 617*f186073cSJoerg Sonnenberger KASSERT(ni != ic->ic_bss, ("freeing ic_bss")); 618*f186073cSJoerg Sonnenberger 619*f186073cSJoerg Sonnenberger /* XXX DF atomic op */ 620*f186073cSJoerg Sonnenberger crit_enter(); 621*f186073cSJoerg Sonnenberger --ni->ni_refcnt; 622*f186073cSJoerg Sonnenberger if (ni->ni_refcnt == 0) { 623*f186073cSJoerg Sonnenberger crit_exit(); 624*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 625*f186073cSJoerg Sonnenberger _ieee80211_free_node(ic, ni); 626*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 627*f186073cSJoerg Sonnenberger } else { 628*f186073cSJoerg Sonnenberger crit_exit(); 629*f186073cSJoerg Sonnenberger } 630*f186073cSJoerg Sonnenberger } 631*f186073cSJoerg Sonnenberger 632*f186073cSJoerg Sonnenberger void 633*f186073cSJoerg Sonnenberger ieee80211_free_allnodes(struct ieee80211com *ic) 634*f186073cSJoerg Sonnenberger { 635*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 636*f186073cSJoerg Sonnenberger lwkt_tokref ilock; 637*f186073cSJoerg Sonnenberger 638*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 639*f186073cSJoerg Sonnenberger while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL) 640*f186073cSJoerg Sonnenberger _ieee80211_free_node(ic, ni); 641*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 642*f186073cSJoerg Sonnenberger } 643*f186073cSJoerg Sonnenberger 644*f186073cSJoerg Sonnenberger /* 645*f186073cSJoerg Sonnenberger * Timeout inactive nodes. Note that we cannot hold the node 646*f186073cSJoerg Sonnenberger * lock while sending a frame as this would lead to a LOR. 647*f186073cSJoerg Sonnenberger * Instead we use a generation number to mark nodes that we've 648*f186073cSJoerg Sonnenberger * scanned and drop the lock and restart a scan if we have to 649*f186073cSJoerg Sonnenberger * time out a node. Since we are single-threaded by virtue of 650*f186073cSJoerg Sonnenberger * controlling the inactivity timer we can be sure this will 651*f186073cSJoerg Sonnenberger * process each node only once. 652*f186073cSJoerg Sonnenberger */ 653*f186073cSJoerg Sonnenberger void 654*f186073cSJoerg Sonnenberger ieee80211_timeout_nodes(struct ieee80211com *ic) 655*f186073cSJoerg Sonnenberger { 656*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 657*f186073cSJoerg Sonnenberger lwkt_tokref ilock; 658*f186073cSJoerg Sonnenberger u_int gen = ic->ic_scangen++; /* NB: ok 'cuz single-threaded*/ 659*f186073cSJoerg Sonnenberger 660*f186073cSJoerg Sonnenberger restart: 661*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 662*f186073cSJoerg Sonnenberger TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 663*f186073cSJoerg Sonnenberger if (ni->ni_scangen == gen) /* previously handled */ 664*f186073cSJoerg Sonnenberger continue; 665*f186073cSJoerg Sonnenberger ni->ni_scangen = gen; 666*f186073cSJoerg Sonnenberger if (++ni->ni_inact > IEEE80211_INACT_MAX) { 667*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("station %6D timed out " 668*f186073cSJoerg Sonnenberger "due to inactivity (%u secs)\n", 669*f186073cSJoerg Sonnenberger ni->ni_macaddr, ":", ni->ni_inact)); 670*f186073cSJoerg Sonnenberger /* 671*f186073cSJoerg Sonnenberger * Send a deauthenticate frame. 672*f186073cSJoerg Sonnenberger * 673*f186073cSJoerg Sonnenberger * Drop the node lock before sending the 674*f186073cSJoerg Sonnenberger * deauthentication frame in case the driver takes 675*f186073cSJoerg Sonnenberger * a lock, as this will result in a LOR between the 676*f186073cSJoerg Sonnenberger * node lock and the driver lock. 677*f186073cSJoerg Sonnenberger */ 678*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 679*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 680*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 681*f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_EXPIRE); 682*f186073cSJoerg Sonnenberger ieee80211_free_node(ic, ni); 683*f186073cSJoerg Sonnenberger ic->ic_stats.is_node_timeout++; 684*f186073cSJoerg Sonnenberger goto restart; 685*f186073cSJoerg Sonnenberger } 686*f186073cSJoerg Sonnenberger } 687*f186073cSJoerg Sonnenberger if (!TAILQ_EMPTY(&ic->ic_node)) 688*f186073cSJoerg Sonnenberger ic->ic_inact_timer = IEEE80211_INACT_WAIT; 689*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 690*f186073cSJoerg Sonnenberger } 691*f186073cSJoerg Sonnenberger 692*f186073cSJoerg Sonnenberger void 693*f186073cSJoerg Sonnenberger ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg) 694*f186073cSJoerg Sonnenberger { 695*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 696*f186073cSJoerg Sonnenberger struct lwkt_tokref ilock; 697*f186073cSJoerg Sonnenberger 698*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 699*f186073cSJoerg Sonnenberger TAILQ_FOREACH(ni, &ic->ic_node, ni_list) 700*f186073cSJoerg Sonnenberger (*f)(arg, ni); 701*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 702*f186073cSJoerg Sonnenberger } 703