Home | History | Annotate | Line # | Download | only in net80211
ieee80211_node.c revision 1.1
      1 /*-
      2  * Copyright (c) 2001 Atsushi Onoe
      3  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * Alternatively, this software may be distributed under the terms of the
     18  * GNU General Public License ("GPL") version 2 as published by the Free
     19  * Software Foundation.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.6 2003/08/19 22:17:03 sam Exp $");
     35 
     36 #include "opt_inet.h"
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/mbuf.h>
     41 #include <sys/malloc.h>
     42 #include <sys/kernel.h>
     43 #include <sys/socket.h>
     44 #include <sys/sockio.h>
     45 #include <sys/endian.h>
     46 #include <sys/errno.h>
     47 #include <sys/bus.h>
     48 #include <sys/proc.h>
     49 #include <sys/sysctl.h>
     50 
     51 #include <machine/atomic.h>
     52 
     53 #include <net/if.h>
     54 #include <net/if_dl.h>
     55 #include <net/if_media.h>
     56 #include <net/if_arp.h>
     57 #include <net/ethernet.h>
     58 #include <net/if_llc.h>
     59 
     60 #include <net80211/ieee80211_var.h>
     61 
     62 #include <net/bpf.h>
     63 
     64 #ifdef INET
     65 #include <netinet/in.h>
     66 #include <netinet/if_ether.h>
     67 #endif
     68 
     69 static struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *);
     70 static void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *);
     71 static void ieee80211_node_copy(struct ieee80211com *,
     72 		struct ieee80211_node *, const struct ieee80211_node *);
     73 static void ieee80211_setup_node(struct ieee80211com *ic,
     74 		struct ieee80211_node *ni, u_int8_t *macaddr);
     75 static void _ieee80211_free_node(struct ieee80211com *,
     76 		struct ieee80211_node *);
     77 
     78 void
     79 ieee80211_node_attach(struct ifnet *ifp)
     80 {
     81 	struct ieee80211com *ic = (void *)ifp;
     82 
     83 	/* XXX need unit */
     84 	mtx_init(&ic->ic_nodelock, ifp->if_name, "802.11 node table", MTX_DEF);
     85 	TAILQ_INIT(&ic->ic_node);
     86 	ic->ic_node_alloc = ieee80211_node_alloc;
     87 	ic->ic_node_free = ieee80211_node_free;
     88 	ic->ic_node_copy = ieee80211_node_copy;
     89 }
     90 
     91 void
     92 ieee80211_node_lateattach(struct ifnet *ifp)
     93 {
     94 	struct ieee80211com *ic = (void *)ifp;
     95 
     96 	ic->ic_bss = (*ic->ic_node_alloc)(ic);
     97 	KASSERT(ic->ic_bss != NULL, ("unable to setup inital BSS node"));
     98 	ic->ic_bss->ni_chan = IEEE80211_CHAN_ANYC;
     99 }
    100 
    101 void
    102 ieee80211_node_detach(struct ifnet *ifp)
    103 {
    104 	struct ieee80211com *ic = (void *)ifp;
    105 
    106 	if (ic->ic_bss != NULL)
    107 		(*ic->ic_node_free)(ic, ic->ic_bss);
    108 	ieee80211_free_allnodes(ic);
    109 	mtx_destroy(&ic->ic_nodelock);
    110 }
    111 
    112 /*
    113  * AP scanning support.
    114  */
    115 
    116 /*
    117  * Initialize the active channel set based on the set
    118  * of available channels and the current PHY mode.
    119  */
    120 static void
    121 ieee80211_reset_scan(struct ifnet *ifp)
    122 {
    123 	struct ieee80211com *ic = (void *)ifp;
    124 
    125 	memcpy(ic->ic_chan_scan, ic->ic_chan_active,
    126 		sizeof(ic->ic_chan_active));
    127 	/* NB: hack, setup so next_scan starts with the first channel */
    128 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC)
    129 		ic->ic_bss->ni_chan = &ic->ic_channels[IEEE80211_CHAN_MAX];
    130 }
    131 
    132 /*
    133  * Begin an active scan.
    134  */
    135 void
    136 ieee80211_begin_scan(struct ifnet *ifp)
    137 {
    138 	struct ieee80211com *ic = (void *)ifp;
    139 
    140 	/*
    141 	 * In all but hostap mode scanning starts off in
    142 	 * an active mode before switching to passive.
    143 	 */
    144 	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
    145 		ic->ic_flags |= IEEE80211_F_ASCAN;
    146 	if (ifp->if_flags & IFF_DEBUG)
    147 		if_printf(ifp, "begin %s scan\n",
    148 			(ic->ic_flags & IEEE80211_F_ASCAN) ?
    149 				"active" : "passive");
    150 	/*
    151 	 * Clear scan state and flush any previously seen
    152 	 * AP's.  Note that the latter assumes we don't act
    153 	 * as both an AP and a station, otherwise we'll
    154 	 * potentially flush state of stations associated
    155 	 * with us.
    156 	 */
    157 	ieee80211_reset_scan(ifp);
    158 	ieee80211_free_allnodes(ic);
    159 
    160 	/* Scan the next channel. */
    161 	ieee80211_next_scan(ifp);
    162 }
    163 
    164 /*
    165  * Switch to the next channel marked for scanning.
    166  */
    167 void
    168 ieee80211_next_scan(struct ifnet *ifp)
    169 {
    170 	struct ieee80211com *ic = (void *)ifp;
    171 	struct ieee80211_channel *chan;
    172 
    173 	chan = ic->ic_bss->ni_chan;
    174 	for (;;) {
    175 		if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX])
    176 			chan = &ic->ic_channels[0];
    177 		if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) {
    178 			/*
    179 			 * Honor channels marked passive-only
    180 			 * during an active scan.
    181 			 */
    182 			if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 ||
    183 			    (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
    184 				break;
    185 		}
    186 		if (chan == ic->ic_bss->ni_chan) {
    187 			ieee80211_end_scan(ifp);
    188 			return;
    189 		}
    190 	}
    191 	clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
    192 	IEEE80211_DPRINTF(("ieee80211_next_scan: chan %d->%d\n",
    193 	    ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
    194 	    ieee80211_chan2ieee(ic, chan)));
    195 	ic->ic_bss->ni_chan = chan;
    196 	ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    197 }
    198 
    199 void
    200 ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
    201 {
    202 	struct ieee80211_node *ni;
    203 	struct ifnet *ifp = &ic->ic_if;
    204 
    205 	ni = ic->ic_bss;
    206 	if (ifp->if_flags & IFF_DEBUG)
    207 		if_printf(ifp, "creating ibss\n");
    208 	ic->ic_flags |= IEEE80211_F_SIBSS;
    209 	ni->ni_chan = chan;
    210 	ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
    211 	IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
    212 	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
    213 	if (ic->ic_opmode == IEEE80211_M_IBSS)
    214 		ni->ni_bssid[0] |= 0x02;	/* local bit for IBSS */
    215 	ni->ni_esslen = ic->ic_des_esslen;
    216 	memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
    217 	ni->ni_rssi = 0;
    218 	ni->ni_rstamp = 0;
    219 	memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
    220 	ni->ni_intval = ic->ic_lintval;
    221 	ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
    222 	if (ic->ic_flags & IEEE80211_F_WEPON)
    223 		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
    224 	if (ic->ic_phytype == IEEE80211_T_FH) {
    225 		ni->ni_fhdwell = 200;	/* XXX */
    226 		ni->ni_fhindex = 1;
    227 	}
    228 	ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
    229 }
    230 
    231 /*
    232  * Complete a scan of potential channels.
    233  */
    234 void
    235 ieee80211_end_scan(struct ifnet *ifp)
    236 {
    237 	struct ieee80211com *ic = (void *)ifp;
    238 	struct ieee80211_node *ni, *nextbs, *selbs;
    239 	u_int8_t rate;
    240 	int i, fail;
    241 
    242 	ic->ic_flags &= ~IEEE80211_F_ASCAN;
    243 	ni = TAILQ_FIRST(&ic->ic_node);
    244 
    245 	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
    246 		/* XXX off stack? */
    247 		u_char occupied[roundup(IEEE80211_CHAN_MAX, NBBY)];
    248 		/*
    249 		 * The passive scan to look for existing AP's completed,
    250 		 * select a channel to camp on.  Identify the channels
    251 		 * that already have one or more AP's and try to locate
    252 		 * an unnoccupied one.  If that fails, pick a random
    253 		 * channel from the active set.
    254 		 */
    255 		for (; ni != NULL; ni = nextbs) {
    256 			ieee80211_ref_node(ni);
    257 			nextbs = TAILQ_NEXT(ni, ni_list);
    258 			setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan));
    259 			ieee80211_free_node(ic, ni);
    260 		}
    261 		for (i = 0; i < IEEE80211_CHAN_MAX; i++)
    262 			if (isset(ic->ic_chan_active, i) && isclr(occupied, i))
    263 				break;
    264 		if (i == IEEE80211_CHAN_MAX) {
    265 			fail = arc4random() & 3;	/* random 0-3 */
    266 			for (i = 0; i < IEEE80211_CHAN_MAX; i++)
    267 				if (isset(ic->ic_chan_active, i) && fail-- == 0)
    268 					break;
    269 		}
    270 		ieee80211_create_ibss(ic, &ic->ic_channels[i]);
    271 		return;
    272 	}
    273 	if (ni == NULL) {
    274 		IEEE80211_DPRINTF(("%s: no scan candidate\n", __func__));
    275   notfound:
    276 		if (ic->ic_opmode == IEEE80211_M_IBSS &&
    277 		    (ic->ic_flags & IEEE80211_F_IBSSON) &&
    278 		    ic->ic_des_esslen != 0) {
    279 			ieee80211_create_ibss(ic, ic->ic_ibss_chan);
    280 			return;
    281 		}
    282 		/*
    283 		 * Reset the list of channels to scan and start again.
    284 		 */
    285 		ieee80211_reset_scan(ifp);
    286 		ieee80211_next_scan(ifp);
    287 		return;
    288 	}
    289 	selbs = NULL;
    290 	if (ifp->if_flags & IFF_DEBUG)
    291 		if_printf(ifp, "\tmacaddr          bssid         chan  rssi rate flag  wep  essid\n");
    292 	for (; ni != NULL; ni = nextbs) {
    293 		ieee80211_ref_node(ni);
    294 		nextbs = TAILQ_NEXT(ni, ni_list);
    295 		if (ni->ni_fails) {
    296 			/*
    297 			 * The configuration of the access points may change
    298 			 * during my scan.  So delete the entry for the AP
    299 			 * and retry to associate if there is another beacon.
    300 			 */
    301 			if (ni->ni_fails++ > 2)
    302 				ieee80211_free_node(ic, ni);
    303 			continue;
    304 		}
    305 		fail = 0;
    306 		if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
    307 			fail |= 0x01;
    308 		if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
    309 		    ni->ni_chan != ic->ic_des_chan)
    310 			fail |= 0x01;
    311 		if (ic->ic_opmode == IEEE80211_M_IBSS) {
    312 			if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
    313 				fail |= 0x02;
    314 		} else {
    315 			if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
    316 				fail |= 0x02;
    317 		}
    318 		if (ic->ic_flags & IEEE80211_F_WEPON) {
    319 			if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
    320 				fail |= 0x04;
    321 		} else {
    322 			if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
    323 				fail |= 0x04;
    324 		}
    325 		rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
    326 		if (rate & IEEE80211_RATE_BASIC)
    327 			fail |= 0x08;
    328 		if (ic->ic_des_esslen != 0 &&
    329 		    (ni->ni_esslen != ic->ic_des_esslen ||
    330 		     memcmp(ni->ni_essid, ic->ic_des_essid,
    331 		     ic->ic_des_esslen != 0)))
    332 			fail |= 0x10;
    333 		if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
    334 		    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
    335 			fail |= 0x20;
    336 		if (ifp->if_flags & IFF_DEBUG) {
    337 			printf(" %c %s", fail ? '-' : '+',
    338 			    ether_sprintf(ni->ni_macaddr));
    339 			printf(" %s%c", ether_sprintf(ni->ni_bssid),
    340 			    fail & 0x20 ? '!' : ' ');
    341 			printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
    342 				fail & 0x01 ? '!' : ' ');
    343 			printf(" %+4d", ni->ni_rssi);
    344 			printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
    345 			    fail & 0x08 ? '!' : ' ');
    346 			printf(" %4s%c",
    347 			    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
    348 			    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
    349 			    "????",
    350 			    fail & 0x02 ? '!' : ' ');
    351 			printf(" %3s%c ",
    352 			    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
    353 			    "wep" : "no",
    354 			    fail & 0x04 ? '!' : ' ');
    355 			ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
    356 			printf("%s\n", fail & 0x10 ? "!" : "");
    357 		}
    358 		if (!fail) {
    359 			if (selbs == NULL)
    360 				selbs = ni;
    361 			else if (ni->ni_rssi > selbs->ni_rssi) {
    362 				ieee80211_unref_node(&selbs);
    363 				selbs = ni;
    364 			} else
    365 				ieee80211_unref_node(&ni);
    366 		} else {
    367 			ieee80211_unref_node(&ni);
    368 		}
    369 	}
    370 	if (selbs == NULL)
    371 		goto notfound;
    372 	(*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
    373 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
    374 		ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE |
    375 		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
    376 		if (ic->ic_bss->ni_rates.rs_nrates == 0) {
    377 			selbs->ni_fails++;
    378 			ieee80211_unref_node(&selbs);
    379 			goto notfound;
    380 		}
    381 		ieee80211_unref_node(&selbs);
    382 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
    383 	} else {
    384 		ieee80211_unref_node(&selbs);
    385 		ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
    386 	}
    387 }
    388 
    389 static struct ieee80211_node *
    390 ieee80211_node_alloc(struct ieee80211com *ic)
    391 {
    392 	return malloc(sizeof(struct ieee80211_node), M_DEVBUF,
    393 		M_NOWAIT | M_ZERO);
    394 }
    395 
    396 static void
    397 ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
    398 {
    399 	free(ni, M_DEVBUF);
    400 }
    401 
    402 static void
    403 ieee80211_node_copy(struct ieee80211com *ic,
    404 	struct ieee80211_node *dst, const struct ieee80211_node *src)
    405 {
    406 	*dst = *src;
    407 }
    408 
    409 static void
    410 ieee80211_setup_node(struct ieee80211com *ic,
    411 	struct ieee80211_node *ni, u_int8_t *macaddr)
    412 {
    413 	int hash;
    414 
    415 	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
    416 	hash = IEEE80211_NODE_HASH(macaddr);
    417 	ni->ni_refcnt = 1;		/* mark referenced */
    418 	mtx_lock(&ic->ic_nodelock);
    419 	TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list);
    420 	LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash);
    421 	/*
    422 	 * Note we don't enable the inactive timer when acting
    423 	 * as a station.  Nodes created in this mode represent
    424 	 * AP's identified while scanning.  If we time them out
    425 	 * then several things happen: we can't return the data
    426 	 * to users to show the list of AP's we encountered, and
    427 	 * more importantly, we'll incorrectly deauthenticate
    428 	 * ourself because the inactivity timer will kick us off.
    429 	 */
    430 	if (ic->ic_opmode != IEEE80211_M_STA)
    431 		ic->ic_inact_timer = IEEE80211_INACT_WAIT;
    432 	mtx_unlock(&ic->ic_nodelock);
    433 }
    434 
    435 struct ieee80211_node *
    436 ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr)
    437 {
    438 	struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
    439 	if (ni != NULL)
    440 		ieee80211_setup_node(ic, ni, macaddr);
    441 	return ni;
    442 }
    443 
    444 struct ieee80211_node *
    445 ieee80211_dup_bss(struct ieee80211com *ic, u_int8_t *macaddr)
    446 {
    447 	struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
    448 	if (ni != NULL) {
    449 		memcpy(ni, ic->ic_bss, sizeof(struct ieee80211_node));
    450 		ieee80211_setup_node(ic, ni, macaddr);
    451 	}
    452 	return ni;
    453 }
    454 
    455 struct ieee80211_node *
    456 ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr)
    457 {
    458 	struct ieee80211_node *ni;
    459 	int hash;
    460 
    461 	hash = IEEE80211_NODE_HASH(macaddr);
    462 	mtx_lock(&ic->ic_nodelock);
    463 	LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
    464 		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
    465 			atomic_add_int(&ni->ni_refcnt, 1); /* mark referenced */
    466 			break;
    467 		}
    468 	}
    469 	mtx_unlock(&ic->ic_nodelock);
    470 	return ni;
    471 }
    472 
    473 /*
    474  * Like find but search based on the channel too.
    475  */
    476 struct ieee80211_node *
    477 ieee80211_lookup_node(struct ieee80211com *ic,
    478 	u_int8_t *macaddr, struct ieee80211_channel *chan)
    479 {
    480 	struct ieee80211_node *ni;
    481 	int hash;
    482 
    483 	hash = IEEE80211_NODE_HASH(macaddr);
    484 	mtx_lock(&ic->ic_nodelock);
    485 	LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
    486 		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && ni->ni_chan == chan) {
    487 			atomic_add_int(&ni->ni_refcnt, 1);/* mark referenced */
    488 			break;
    489 		}
    490 	}
    491 	mtx_unlock(&ic->ic_nodelock);
    492 	return ni;
    493 }
    494 
    495 static void
    496 _ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
    497 {
    498 	KASSERT(ni != ic->ic_bss, ("freeing bss node"));
    499 
    500 	TAILQ_REMOVE(&ic->ic_node, ni, ni_list);
    501 	LIST_REMOVE(ni, ni_hash);
    502 	if (TAILQ_EMPTY(&ic->ic_node))
    503 		ic->ic_inact_timer = 0;
    504 	(*ic->ic_node_free)(ic, ni);
    505 }
    506 
    507 void
    508 ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
    509 {
    510 	KASSERT(ni != ic->ic_bss, ("freeing ic_bss"));
    511 
    512 	/* XXX need equivalent of atomic_dec_and_test */
    513 	atomic_subtract_int(&ni->ni_refcnt, 1);
    514 	if (atomic_cmpset_int(&ni->ni_refcnt, 0, 1)) {
    515 		mtx_lock(&ic->ic_nodelock);
    516 		_ieee80211_free_node(ic, ni);
    517 		mtx_unlock(&ic->ic_nodelock);
    518 	}
    519 }
    520 
    521 void
    522 ieee80211_free_allnodes(struct ieee80211com *ic)
    523 {
    524 	struct ieee80211_node *ni;
    525 
    526 	mtx_lock(&ic->ic_nodelock);
    527 	while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL)
    528 		_ieee80211_free_node(ic, ni);
    529 	mtx_unlock(&ic->ic_nodelock);
    530 }
    531 
    532 void
    533 ieee80211_timeout_nodes(struct ieee80211com *ic)
    534 {
    535 	struct ieee80211_node *ni, *nextbs;
    536 
    537 	mtx_lock(&ic->ic_nodelock);
    538 	for (ni = TAILQ_FIRST(&ic->ic_node); ni != NULL;) {
    539 		if (++ni->ni_inact > IEEE80211_INACT_MAX) {
    540 			IEEE80211_DPRINTF(("station %s timed out "
    541 			    "due to inactivity (%u secs)\n",
    542 			    ether_sprintf(ni->ni_macaddr),
    543 			    ni->ni_inact));
    544 			nextbs = TAILQ_NEXT(ni, ni_list);
    545 			/*
    546 			 * Send a deauthenticate frame.
    547 			 */
    548 			IEEE80211_SEND_MGMT(ic, ni,
    549 			    IEEE80211_FC0_SUBTYPE_DEAUTH,
    550 			    IEEE80211_REASON_AUTH_EXPIRE);
    551 			ieee80211_free_node(ic, ni);
    552 			ni = nextbs;
    553 		} else
    554 			ni = TAILQ_NEXT(ni, ni_list);
    555 	}
    556 	if (!TAILQ_EMPTY(&ic->ic_node))
    557 		ic->ic_inact_timer = IEEE80211_INACT_WAIT;
    558 	mtx_unlock(&ic->ic_nodelock);
    559 }
    560 
    561 void
    562 ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg)
    563 {
    564 	struct ieee80211_node *ni;
    565 
    566 	mtx_lock(&ic->ic_nodelock);
    567 	TAILQ_FOREACH(ni, &ic->ic_node, ni_list)
    568 		(*f)(arg, ni);
    569 	mtx_unlock(&ic->ic_nodelock);
    570 }
    571