Merge commit '80d5689f5d4588adc071138e25e9d0d5252d9b55'
[unleashed.git] / kernel / net / net80211 / net80211_node.c
blobe53d63ee366657b58bcd12f41fcae7837ad9ae49
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * Node management routines
42 #include "net80211_impl.h"
44 static ieee80211_node_t *ieee80211_node_alloc(ieee80211com_t *);
45 static void ieee80211_node_cleanup(ieee80211_node_t *);
46 static void ieee80211_node_free(ieee80211_node_t *);
47 static uint8_t ieee80211_node_getrssi(const ieee80211_node_t *);
48 static void ieee80211_setup_node(ieee80211com_t *, ieee80211_node_table_t *,
49 ieee80211_node_t *, const uint8_t *);
50 static void ieee80211_node_reclaim(ieee80211_node_table_t *,
51 ieee80211_node_t *);
52 static void ieee80211_free_node_locked(ieee80211_node_t *);
53 static void ieee80211_free_allnodes(ieee80211_node_table_t *);
54 static void ieee80211_node_leave(ieee80211com_t *, ieee80211_node_t *);
55 static void ieee80211_timeout_scan_candidates(ieee80211_node_table_t *);
56 static void ieee80211_timeout_stations(ieee80211_node_table_t *);
57 static void ieee80211_node_table_init(ieee80211com_t *,
58 ieee80211_node_table_t *, const char *, int, int,
59 void (*timeout)(ieee80211_node_table_t *));
60 static void ieee80211_node_table_cleanup(ieee80211_node_table_t *);
63 * association failures before ignored
64 * The failure may be caused by the response frame is lost for
65 * environmental reason. So Try associate more than once before
66 * ignore the node
68 #define IEEE80211_STA_FAILS_MAX 2
71 * Initialize node database management callbacks for the interface.
72 * This function is called by ieee80211_attach(). These callback
73 * functions may be overridden in special circumstances, as long as
74 * as this is done after calling ieee80211_attach() and prior to any
75 * other call which may allocate a node
77 void
78 ieee80211_node_attach(ieee80211com_t *ic)
80 struct ieee80211_impl *im = ic->ic_private;
82 ic->ic_node_alloc = ieee80211_node_alloc;
83 ic->ic_node_free = ieee80211_node_free;
84 ic->ic_node_cleanup = ieee80211_node_cleanup;
85 ic->ic_node_getrssi = ieee80211_node_getrssi;
87 /* default station inactivity timer setings */
88 im->im_inact_init = IEEE80211_INACT_INIT;
89 im->im_inact_assoc = IEEE80211_INACT_ASSOC;
90 im->im_inact_run = IEEE80211_INACT_RUN;
91 im->im_inact_probe = IEEE80211_INACT_PROBE;
95 * Initialize node databases and the ic_bss node element.
97 void
98 ieee80211_node_lateattach(ieee80211com_t *ic)
101 * Calculate ic_tim_bitmap size in bytes
102 * IEEE80211_AID_MAX defines maximum bits in ic_tim_bitmap
104 ic->ic_tim_len = howmany(IEEE80211_AID_MAX, 8) * sizeof (uint8_t);
106 ieee80211_node_table_init(ic, &ic->ic_sta, "station",
107 IEEE80211_INACT_INIT, IEEE80211_WEP_NKID,
108 ieee80211_timeout_stations);
109 ieee80211_node_table_init(ic, &ic->ic_scan, "scan",
110 IEEE80211_INACT_SCAN, 0, ieee80211_timeout_scan_candidates);
112 ieee80211_reset_bss(ic);
116 * Destroy all node databases and is usually called during device detach
118 void
119 ieee80211_node_detach(ieee80211com_t *ic)
121 /* Node Detach */
122 if (ic->ic_bss != NULL) {
123 ieee80211_free_node(ic->ic_bss);
124 ic->ic_bss = NULL;
126 ieee80211_node_table_cleanup(&ic->ic_scan);
127 ieee80211_node_table_cleanup(&ic->ic_sta);
131 * Increase a node's reference count
133 * Return pointer to the node
135 ieee80211_node_t *
136 ieee80211_ref_node(ieee80211_node_t *in)
138 ieee80211_node_incref(in);
139 return (in);
143 * Dexrease a node's reference count
145 void
146 ieee80211_unref_node(ieee80211_node_t **in)
148 ieee80211_node_decref(*in);
149 *in = NULL; /* guard against use */
153 * Mark ports authorized for data traffic. This function is usually
154 * used by 802.1x authenticator.
156 void
157 ieee80211_node_authorize(ieee80211_node_t *in)
159 ieee80211_impl_t *im = in->in_ic->ic_private;
161 in->in_flags |= IEEE80211_NODE_AUTH;
162 in->in_inact_reload = im->im_inact_run;
163 in->in_inact = in->in_inact_reload;
167 * Mark ports unauthorized for data traffic. This function is usually
168 * used by 802.1x authenticator.
170 void
171 ieee80211_node_unauthorize(ieee80211_node_t *in)
173 in->in_flags &= ~IEEE80211_NODE_AUTH;
177 * Set/change the channel. The rate set is also updated as
178 * to insure a consistent view by drivers.
180 static void
181 ieee80211_node_setchan(ieee80211com_t *ic, ieee80211_node_t *in,
182 struct ieee80211_channel *chan)
184 if (chan == IEEE80211_CHAN_ANYC)
185 chan = ic->ic_curchan;
186 in->in_chan = chan;
187 if (IEEE80211_IS_CHAN_HT(chan)) {
189 * Gotta be careful here; the rate set returned by
190 * ieee80211_get_suprates is actually any HT rate
191 * set so blindly copying it will be bad. We must
192 * install the legacy rate est in ni_rates and the
193 * HT rate set in ni_htrates.
195 in->in_htrates = *ieee80211_get_suphtrates(ic, chan);
197 in->in_rates = *ieee80211_get_suprates(ic, chan);
198 /* in->in_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; */
202 * Initialize the channel set to scan based on the available channels
203 * and the current PHY mode.
205 static void
206 ieee80211_reset_scan(ieee80211com_t *ic)
208 ieee80211_impl_t *im = ic->ic_private;
210 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
211 (void) memset(im->im_chan_scan, 0, sizeof (im->im_chan_scan));
212 ieee80211_setbit(im->im_chan_scan,
213 ieee80211_chan2ieee(ic, ic->ic_des_chan));
214 } else {
215 bcopy(ic->ic_chan_active, im->im_chan_scan,
216 sizeof (ic->ic_chan_active));
218 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_reset_scan(): "
219 "start chan %u\n", ieee80211_chan2ieee(ic, ic->ic_curchan));
223 * Begin an active scan. Initialize the node cache. The scan
224 * begins on the next radio channel by calling ieee80211_next_scan().
225 * The actual scanning is not automated. The driver itself
226 * only handles setting the radio frequency and stepping through
227 * the channels.
229 void
230 ieee80211_begin_scan(ieee80211com_t *ic, boolean_t reset)
232 IEEE80211_LOCK(ic);
234 if (ic->ic_opmode != IEEE80211_M_HOSTAP)
235 ic->ic_flags |= IEEE80211_F_ASCAN;
236 ieee80211_dbg(IEEE80211_MSG_SCAN,
237 "begin %s scan in %s mode on channel %u\n",
238 (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive",
239 ieee80211_phymode_name[ic->ic_curmode],
240 ieee80211_chan2ieee(ic, ic->ic_curchan));
243 * Clear scan state and flush any previously seen AP's.
245 ieee80211_reset_scan(ic);
246 if (reset)
247 ieee80211_free_allnodes(&ic->ic_scan);
249 ic->ic_flags |= IEEE80211_F_SCAN;
250 IEEE80211_UNLOCK(ic);
252 /* Scan the next channel. */
253 ieee80211_next_scan(ic);
257 * Switch to the next channel marked for scanning.
258 * A driver is expected to first call ieee80211_begin_scan(),
259 * to initialize the node cache, then set the radio channel
260 * on the device. And then after a certain time has elapsed,
261 * call ieee80211_next_scan() to move to the next channel.
262 * Typically, a timeout routine is used to automate this process.
264 void
265 ieee80211_next_scan(ieee80211com_t *ic)
267 ieee80211_impl_t *im = ic->ic_private;
268 struct ieee80211_channel *chan;
270 IEEE80211_LOCK(ic);
272 * Insure any previous mgt frame timeouts don't fire.
273 * This assumes the driver does the right thing in
274 * flushing anything queued in the driver and below.
276 im->im_mgt_timer = 0;
278 chan = ic->ic_curchan;
279 do {
280 if (++chan > &ic->ic_sup_channels[IEEE80211_CHAN_MAX])
281 chan = &ic->ic_sup_channels[0];
282 if (ieee80211_isset(im->im_chan_scan,
283 ieee80211_chan2ieee(ic, chan))) {
284 ieee80211_clrbit(im->im_chan_scan,
285 ieee80211_chan2ieee(ic, chan));
286 ieee80211_dbg(IEEE80211_MSG_SCAN,
287 "ieee80211_next_scan: chan %d->%d\n",
288 ieee80211_chan2ieee(ic, ic->ic_curchan),
289 ieee80211_chan2ieee(ic, chan));
290 ic->ic_curchan = chan;
292 * drivers should do this as needed,
293 * for now maintain compatibility
295 ic->ic_bss->in_rates =
296 ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)];
297 IEEE80211_UNLOCK(ic);
298 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
299 return;
301 } while (chan != ic->ic_curchan);
302 IEEE80211_UNLOCK(ic);
303 ieee80211_end_scan(ic);
307 * Copy useful state from node obss into nbss.
309 static void
310 ieee80211_copy_bss(ieee80211_node_t *nbss, const ieee80211_node_t *obss)
312 /* propagate useful state */
313 nbss->in_authmode = obss->in_authmode;
314 nbss->in_txpower = obss->in_txpower;
315 nbss->in_vlan = obss->in_vlan;
319 * Setup the net80211 specific portion of an interface's softc, ic,
320 * for use in IBSS mode
322 void
323 ieee80211_create_ibss(ieee80211com_t *ic, struct ieee80211_channel *chan)
325 ieee80211_impl_t *im = ic->ic_private;
326 ieee80211_node_table_t *nt;
327 ieee80211_node_t *in;
329 IEEE80211_LOCK_ASSERT(ic);
330 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_create_ibss: "
331 "creating ibss\n");
334 * Create the station/neighbor table. Note that for adhoc
335 * mode we make the initial inactivity timer longer since
336 * we create nodes only through discovery and they typically
337 * are long-lived associations.
339 nt = &ic->ic_sta;
340 IEEE80211_NODE_LOCK(nt);
341 nt->nt_name = "neighbor";
342 nt->nt_inact_init = im->im_inact_run;
343 IEEE80211_NODE_UNLOCK(nt);
345 in = ieee80211_alloc_node(ic, &ic->ic_sta, ic->ic_macaddr);
346 if (in == NULL) {
347 ieee80211_err("ieee80211_create_ibss(): alloc node failed\n");
348 return;
350 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_macaddr);
351 in->in_esslen = ic->ic_des_esslen;
352 (void) memcpy(in->in_essid, ic->ic_des_essid, in->in_esslen);
353 ieee80211_copy_bss(in, ic->ic_bss);
354 in->in_intval = ic->ic_bintval;
355 if (ic->ic_flags & IEEE80211_F_PRIVACY)
356 in->in_capinfo |= IEEE80211_CAPINFO_PRIVACY;
357 if (ic->ic_phytype == IEEE80211_T_FH) {
358 in->in_fhdwell = 200;
359 in->in_fhindex = 1;
361 switch (ic->ic_opmode) {
362 case IEEE80211_M_IBSS:
363 ic->ic_flags |= IEEE80211_F_SIBSS;
364 in->in_capinfo |= IEEE80211_CAPINFO_IBSS;
365 if (ic->ic_flags & IEEE80211_F_DESBSSID)
366 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_des_bssid);
367 else
368 in->in_bssid[0] |= 0x02; /* local bit for IBSS */
369 break;
370 case IEEE80211_M_AHDEMO:
371 if (ic->ic_flags & IEEE80211_F_DESBSSID)
372 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_des_bssid);
373 else
374 (void) memset(in->in_bssid, 0, IEEE80211_ADDR_LEN);
375 break;
376 default:
377 ieee80211_err("ieee80211_create_ibss(): "
378 "wrong opmode %u to creat IBSS, abort\n",
379 ic->ic_opmode);
380 ieee80211_free_node(in);
381 return;
385 * Fix the channel and related attributes.
387 ieee80211_node_setchan(ic, in, chan);
388 ic->ic_curchan = chan;
389 ic->ic_curmode = ieee80211_chan2mode(ic, chan);
391 * Do mode-specific rate setup.
393 ieee80211_setbasicrates(&in->in_rates, ic->ic_curmode);
394 IEEE80211_UNLOCK(ic);
395 ieee80211_sta_join(ic, ieee80211_ref_node(in));
396 IEEE80211_LOCK(ic);
399 void
400 ieee80211_reset_bss(ieee80211com_t *ic)
402 ieee80211_node_t *in;
403 ieee80211_node_t *obss;
405 ieee80211_node_table_reset(&ic->ic_sta);
406 ieee80211_reset_erp(ic);
408 in = ieee80211_alloc_node(ic, &ic->ic_scan, ic->ic_macaddr);
409 ASSERT(in != NULL);
410 obss = ic->ic_bss;
411 ic->ic_bss = ieee80211_ref_node(in);
412 if (obss != NULL) {
413 ieee80211_copy_bss(in, obss);
414 in->in_intval = ic->ic_bintval;
415 ieee80211_free_node(obss);
419 static int
420 ieee80211_match_bss(ieee80211com_t *ic, ieee80211_node_t *in)
422 uint8_t rate;
423 int fail;
425 fail = 0;
426 if (ieee80211_isclr(ic->ic_chan_active,
427 ieee80211_chan2ieee(ic, in->in_chan))) {
428 fail |= IEEE80211_BADCHAN;
430 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
431 in->in_chan != ic->ic_des_chan) {
432 fail |= IEEE80211_BADCHAN;
434 if (ic->ic_opmode == IEEE80211_M_IBSS) {
435 if (!(in->in_capinfo & IEEE80211_CAPINFO_IBSS))
436 fail |= IEEE80211_BADOPMODE;
437 } else {
438 if (!(in->in_capinfo & IEEE80211_CAPINFO_ESS))
439 fail |= IEEE80211_BADOPMODE;
441 if (ic->ic_flags & IEEE80211_F_PRIVACY) {
442 if (!(in->in_capinfo & IEEE80211_CAPINFO_PRIVACY))
443 fail |= IEEE80211_BADPRIVACY;
444 } else {
445 if (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY)
446 fail |= IEEE80211_BADPRIVACY;
448 rate = ieee80211_fix_rate(in, &in->in_rates,
449 IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
450 if (rate & IEEE80211_RATE_BASIC)
451 fail |= IEEE80211_BADRATE;
452 if (ic->ic_des_esslen != 0 &&
453 (in->in_esslen != ic->ic_des_esslen ||
454 memcmp(in->in_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) {
455 fail |= IEEE80211_BADESSID;
457 if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
458 !IEEE80211_ADDR_EQ(ic->ic_des_bssid, in->in_bssid)) {
459 fail |= IEEE80211_BADBSSID;
461 if (in->in_fails >= IEEE80211_STA_FAILS_MAX)
462 fail |= IEEE80211_NODEFAIL;
464 return (fail);
467 #define IEEE80211_MAXRATE(_rs) \
468 ((_rs).ir_rates[(_rs).ir_nrates - 1] & IEEE80211_RATE_VAL)
471 * Compare the capabilities of node a with node b and decide which is
472 * more desirable (return b if b is considered better than a). Note
473 * that we assume compatibility/usability has already been checked
474 * so we don't need to (e.g. validate whether privacy is supported).
475 * Used to select the best scan candidate for association in a BSS.
477 * Return desired node
479 static ieee80211_node_t *
480 ieee80211_node_compare(ieee80211com_t *ic, ieee80211_node_t *a,
481 ieee80211_node_t *b)
483 uint8_t maxa;
484 uint8_t maxb;
485 uint8_t rssia;
486 uint8_t rssib;
488 /* privacy support preferred */
489 if ((a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
490 !(b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) {
491 return (a);
493 if (!(a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
494 (b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) {
495 return (b);
498 /* compare count of previous failures */
499 if (b->in_fails != a->in_fails)
500 return ((a->in_fails > b->in_fails) ? b : a);
502 rssia = ic->ic_node_getrssi(a);
503 rssib = ic->ic_node_getrssi(b);
504 if (ABS(rssib - rssia) < IEEE80211_RSSI_CMP_THRESHOLD) {
505 /* best/max rate preferred if signal level close enough */
506 maxa = IEEE80211_MAXRATE(a->in_rates);
507 maxb = IEEE80211_MAXRATE(b->in_rates);
508 if (maxa != maxb)
509 return ((maxb > maxa) ? b : a);
510 /* for now just prefer 5Ghz band to all other bands */
511 if (IEEE80211_IS_CHAN_5GHZ(a->in_chan) &&
512 !IEEE80211_IS_CHAN_5GHZ(b->in_chan)) {
513 return (a);
515 if (!IEEE80211_IS_CHAN_5GHZ(a->in_chan) &&
516 IEEE80211_IS_CHAN_5GHZ(b->in_chan)) {
517 return (b);
520 /* all things being equal, compare signal level */
521 return ((rssib > rssia) ? b : a);
525 * Mark an ongoing scan stopped.
527 void
528 ieee80211_cancel_scan(ieee80211com_t *ic)
530 IEEE80211_LOCK(ic);
531 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_cancel_scan()"
532 "end %s scan\n",
533 (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive");
534 ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN);
535 cv_broadcast(&((ieee80211_impl_t *)ic->ic_private)->im_scan_cv);
536 IEEE80211_UNLOCK(ic);
540 * Complete a scan of potential channels. It is called by
541 * ieee80211_next_scan() when the state machine has performed
542 * a full cycle of scaning on all available radio channels.
543 * ieee80211_end_scan() will inspect the node cache for suitable
544 * APs found during scaning, and associate with one, should
545 * the parameters of the node match those of the configuration
546 * requested from userland.
548 void
549 ieee80211_end_scan(ieee80211com_t *ic)
551 ieee80211_node_table_t *nt = &ic->ic_scan;
552 ieee80211_node_t *in;
553 ieee80211_node_t *selbs;
555 ieee80211_cancel_scan(ic);
556 /* notify SCAN done */
557 ieee80211_notify(ic, EVENT_SCAN_RESULTS);
558 IEEE80211_LOCK(ic);
561 * Automatic sequencing; look for a candidate and
562 * if found join the network.
564 /* NB: unlocked read should be ok */
565 in = list_head(&nt->nt_node);
566 if (in == NULL && (ic->ic_flags & IEEE80211_F_WPA) == 0) {
567 ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_end_scan: "
568 "no scan candidate\n");
569 notfound:
570 if (ic->ic_opmode == IEEE80211_M_IBSS &&
571 (ic->ic_flags & IEEE80211_F_IBSSON) &&
572 ic->ic_des_esslen != 0) {
573 ieee80211_create_ibss(ic, ic->ic_ibss_chan);
574 IEEE80211_UNLOCK(ic);
575 return;
579 * Reset the list of channels to scan and start again.
581 ieee80211_reset_scan(ic);
582 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
583 IEEE80211_UNLOCK(ic);
585 ieee80211_next_scan(ic);
586 return;
589 if (ic->ic_flags & IEEE80211_F_SCANONLY ||
590 ic->ic_flags & IEEE80211_F_WPA) { /* scan only */
591 ic->ic_flags &= ~IEEE80211_F_SCANONLY;
592 IEEE80211_UNLOCK(ic);
593 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
594 return;
597 selbs = NULL;
598 IEEE80211_NODE_LOCK(nt);
599 while (in != NULL) {
600 if (in->in_fails >= IEEE80211_STA_FAILS_MAX) {
601 ieee80211_node_t *tmpin = in;
604 * The configuration of the access points may change
605 * during my scan. So delete the entry for the AP
606 * and retry to associate if there is another beacon.
608 in = list_next(&nt->nt_node, tmpin);
609 ieee80211_node_reclaim(nt, tmpin);
610 continue;
613 * It's possible at some special moments, the in_chan will
614 * be none. Need to skip the null node.
616 if (in->in_chan == IEEE80211_CHAN_ANYC) {
617 in = list_next(&nt->nt_node, in);
618 continue;
620 if (ieee80211_match_bss(ic, in) == 0) {
621 if (selbs == NULL)
622 selbs = in;
623 else
624 selbs = ieee80211_node_compare(ic, selbs, in);
626 in = list_next(&nt->nt_node, in);
628 if (selbs != NULL) /* grab ref while dropping lock */
629 (void) ieee80211_ref_node(selbs);
630 IEEE80211_NODE_UNLOCK(nt);
631 if (selbs == NULL)
632 goto notfound;
633 IEEE80211_UNLOCK(ic);
634 ieee80211_sta_join(ic, selbs);
639 * Handle 802.11 ad hoc network merge. The convention, set by the
640 * Wireless Ethernet Compatibility Alliance (WECA), is that an 802.11
641 * station will change its BSSID to match the "oldest" 802.11 ad hoc
642 * network, on the same channel, that has the station's desired SSID.
643 * The "oldest" 802.11 network sends beacons with the greatest TSF
644 * timestamp.
645 * The caller is assumed to validate TSF's before attempting a merge.
647 * Return B_TRUE if the BSSID changed, B_FALSE otherwise.
649 boolean_t
650 ieee80211_ibss_merge(ieee80211_node_t *in)
652 ieee80211com_t *ic = in->in_ic;
654 if (in == ic->ic_bss ||
655 IEEE80211_ADDR_EQ(in->in_bssid, ic->ic_bss->in_bssid)) {
656 /* unchanged, nothing to do */
657 return (B_FALSE);
659 if (ieee80211_match_bss(ic, in) != 0) { /* capabilities mismatch */
660 ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_ibss_merge: "
661 " merge failed, capabilities mismatch\n");
662 return (B_FALSE);
664 ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_ibss_merge: "
665 "new bssid %s: %s preamble, %s slot time%s\n",
666 ieee80211_macaddr_sprintf(in->in_bssid),
667 (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long",
668 (ic->ic_flags & IEEE80211_F_SHSLOT) ? "short" : "long",
669 (ic->ic_flags&IEEE80211_F_USEPROT) ? ", protection" : "");
670 ieee80211_sta_join(ic, ieee80211_ref_node(in));
671 return (B_TRUE);
675 * Change the bss channel.
677 void
678 ieee80211_setcurchan(ieee80211com_t *ic, struct ieee80211_channel *c)
680 ic->ic_curchan = c;
681 ic->ic_curmode = ieee80211_chan2mode(ic, ic->ic_curchan);
682 if (ic->ic_set_channel != NULL)
683 ic->ic_set_channel(ic);
687 * Join the specified IBSS/BSS network. The node is assumed to
688 * be passed in with a held reference.
690 void
691 ieee80211_sta_join(ieee80211com_t *ic, ieee80211_node_t *selbs)
693 ieee80211_impl_t *im = ic->ic_private;
694 ieee80211_node_t *obss;
696 IEEE80211_LOCK(ic);
697 if (ic->ic_opmode == IEEE80211_M_IBSS) {
698 ieee80211_node_table_t *nt;
701 * Delete unusable rates; we've already checked
702 * that the negotiated rate set is acceptable.
704 (void) ieee80211_fix_rate(selbs, &selbs->in_rates,
705 IEEE80211_F_DODEL);
707 * Fillin the neighbor table
709 nt = &ic->ic_sta;
710 IEEE80211_NODE_LOCK(nt);
711 nt->nt_name = "neighbor";
712 nt->nt_inact_init = im->im_inact_run;
713 IEEE80211_NODE_UNLOCK(nt);
717 * Committed to selbs, setup state.
719 obss = ic->ic_bss;
720 ic->ic_bss = selbs; /* caller assumed to bump refcnt */
721 if (obss != NULL) {
722 ieee80211_copy_bss(selbs, obss);
723 ieee80211_free_node(obss);
725 ic->ic_curmode = ieee80211_chan2mode(ic, selbs->in_chan);
726 ic->ic_curchan = selbs->in_chan;
727 ic->ic_phytype = selbs->in_phytype;
729 * Set the erp state (mostly the slot time) to deal with
730 * the auto-select case; this should be redundant if the
731 * mode is locked.
733 ieee80211_reset_erp(ic);
734 ieee80211_wme_initparams(ic);
736 IEEE80211_UNLOCK(ic);
737 if (ic->ic_opmode == IEEE80211_M_STA)
738 ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
739 else
740 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
744 * Leave the specified IBSS/BSS network. The node is assumed to
745 * be passed in with a held reference.
747 void
748 ieee80211_sta_leave(ieee80211com_t *ic, ieee80211_node_t *in)
750 IEEE80211_LOCK(ic);
751 ic->ic_node_cleanup(in);
752 ieee80211_notify_node_leave(ic, in);
753 IEEE80211_UNLOCK(ic);
757 * Allocate a node. This is the default callback function for
758 * ic_node_alloc. This function may be overridden by the driver
759 * to allocate device specific node structure.
761 /* ARGSUSED */
762 static ieee80211_node_t *
763 ieee80211_node_alloc(ieee80211com_t *ic)
765 return (kmem_zalloc(sizeof (ieee80211_node_t), KM_SLEEP));
769 * Cleanup a node, free any memory associated with the node.
770 * This is the default callback function for ic_node_cleanup
771 * and may be overridden by the driver.
773 static void
774 ieee80211_node_cleanup(ieee80211_node_t *in)
776 in->in_associd = 0;
777 in->in_rssi = 0;
778 in->in_rstamp = 0;
779 if (in->in_challenge != NULL) {
780 kmem_free(in->in_challenge, IEEE80211_CHALLENGE_LEN);
781 in->in_challenge = NULL;
783 if (in->in_rxfrag != NULL) {
784 freemsg(in->in_rxfrag);
785 in->in_rxfrag = NULL;
790 * Free a node. This is the default callback function for ic_node_free
791 * and may be overridden by the driver to free memory used by device
792 * specific node structure
794 static void
795 ieee80211_node_free(ieee80211_node_t *in)
797 ieee80211com_t *ic = in->in_ic;
799 ic->ic_node_cleanup(in);
800 if (in->in_wpa_ie != NULL)
801 ieee80211_free(in->in_wpa_ie);
802 if (in->in_wme_ie != NULL)
803 ieee80211_free(in->in_wme_ie);
804 if (in->in_htcap_ie != NULL)
805 ieee80211_free(in->in_htcap_ie);
806 kmem_free(in, sizeof (ieee80211_node_t));
810 * Get a node current RSSI value. This is the default callback function
811 * for ic_node_getrssi and may be overridden by the driver to provide
812 * device specific RSSI calculation algorithm.
814 static uint8_t
815 ieee80211_node_getrssi(const ieee80211_node_t *in)
817 return (in->in_rssi);
820 /* Free fragment if not needed anymore */
821 static void
822 node_cleanfrag(ieee80211_node_t *in)
824 clock_t ticks;
826 ticks = ddi_get_lbolt();
827 if (in->in_rxfrag != NULL && ticks > (in->in_rxfragstamp + hz)) {
828 freemsg(in->in_rxfrag);
829 in->in_rxfrag = NULL;
834 * Setup a node. Initialize the node with specified macaddr. Associate
835 * with the interface softc, ic, and add it to the specified node
836 * database.
838 static void
839 ieee80211_setup_node(ieee80211com_t *ic, ieee80211_node_table_t *nt,
840 ieee80211_node_t *in, const uint8_t *macaddr)
842 int32_t hash;
844 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_setup_node(): "
845 "%p<%s> in %s table\n", in,
846 ieee80211_macaddr_sprintf(macaddr),
847 (nt != NULL) ? nt->nt_name : "NULL");
849 in->in_ic = ic;
850 IEEE80211_ADDR_COPY(in->in_macaddr, macaddr);
851 hash = ieee80211_node_hash(macaddr);
852 ieee80211_node_initref(in); /* mark referenced */
853 in->in_authmode = IEEE80211_AUTH_OPEN;
854 in->in_txpower = ic->ic_txpowlimit; /* max power */
855 in->in_chan = IEEE80211_CHAN_ANYC;
856 in->in_inact_reload = IEEE80211_INACT_INIT;
857 in->in_inact = in->in_inact_reload;
858 ieee80211_crypto_resetkey(ic, &in->in_ucastkey, IEEE80211_KEYIX_NONE);
860 if (nt != NULL) {
861 IEEE80211_NODE_LOCK(nt);
862 list_insert_tail(&nt->nt_node, in);
863 list_insert_tail(&nt->nt_hash[hash], in);
864 in->in_table = nt;
865 in->in_inact_reload = nt->nt_inact_init;
866 IEEE80211_NODE_UNLOCK(nt);
871 * Allocates and initialize a node with specified MAC address.
872 * Associate the node with the interface ic. If the allocation
873 * is successful, the node structure is initialized by
874 * ieee80211_setup_node(); otherwise, NULL is returned
876 ieee80211_node_t *
877 ieee80211_alloc_node(ieee80211com_t *ic, ieee80211_node_table_t *nt,
878 const uint8_t *macaddr)
880 ieee80211_node_t *in;
882 in = ic->ic_node_alloc(ic);
883 if (in != NULL)
884 ieee80211_setup_node(ic, nt, in, macaddr);
885 return (in);
889 * Craft a temporary node suitable for sending a management frame
890 * to the specified station. We craft only as much state as we
891 * need to do the work since the node will be immediately reclaimed
892 * once the send completes.
894 ieee80211_node_t *
895 ieee80211_tmp_node(ieee80211com_t *ic, const uint8_t *macaddr)
897 ieee80211_node_t *in;
899 in = ic->ic_node_alloc(ic);
900 if (in != NULL) {
901 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_tmp_node: "
902 "%p<%s>\n", in, ieee80211_macaddr_sprintf(macaddr));
904 IEEE80211_ADDR_COPY(in->in_macaddr, macaddr);
905 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_bss->in_bssid);
906 ieee80211_node_initref(in); /* mark referenced */
907 in->in_txpower = ic->ic_bss->in_txpower;
908 /* NB: required by ieee80211_fix_rate */
909 ieee80211_node_setchan(ic, in, ic->ic_bss->in_chan);
910 ieee80211_crypto_resetkey(ic, &in->in_ucastkey,
911 IEEE80211_KEYIX_NONE);
913 in->in_table = NULL; /* NB: pedantic */
914 in->in_ic = ic;
917 return (in);
921 * ieee80211_dup_bss() is similar to ieee80211_alloc_node(),
922 * but is instead used to create a node database entry for
923 * the specified BSSID. If the allocation is successful, the
924 * node is initialized, otherwise, NULL is returned.
926 ieee80211_node_t *
927 ieee80211_dup_bss(ieee80211_node_table_t *nt, const uint8_t *macaddr)
929 ieee80211com_t *ic = nt->nt_ic;
930 ieee80211_node_t *in;
932 in = ieee80211_alloc_node(ic, nt, macaddr);
933 if (in != NULL) {
935 * Inherit from ic_bss.
937 ieee80211_copy_bss(in, ic->ic_bss);
938 IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_bss->in_bssid);
939 ieee80211_node_setchan(ic, in, ic->ic_bss->in_chan);
942 return (in);
946 * Iterate through the node table, searching for a node entry which
947 * matches macaddr. If the entry is found, its reference count is
948 * incremented, and a pointer to the node is returned; otherwise,
949 * NULL will be returned.
950 * The node table lock is acquired by the caller.
952 static ieee80211_node_t *
953 ieee80211_find_node_locked(ieee80211_node_table_t *nt, const uint8_t *macaddr)
955 ieee80211_node_t *in;
956 int hash;
958 ASSERT(IEEE80211_NODE_IS_LOCKED(nt));
960 hash = ieee80211_node_hash(macaddr);
961 in = list_head(&nt->nt_hash[hash]);
962 while (in != NULL) {
963 if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr))
964 return (ieee80211_ref_node(in)); /* mark referenced */
965 in = list_next(&nt->nt_hash[hash], in);
967 return (NULL);
971 * Iterate through the node table, searching for a node entry
972 * which match specified mac address.
973 * Return NULL if no matching node found.
975 ieee80211_node_t *
976 ieee80211_find_node(ieee80211_node_table_t *nt, const uint8_t *macaddr)
978 ieee80211_node_t *in;
980 IEEE80211_NODE_LOCK(nt);
981 in = ieee80211_find_node_locked(nt, macaddr);
982 IEEE80211_NODE_UNLOCK(nt);
983 return (in);
987 * Like find but search based on the ssid too.
989 ieee80211_node_t *
990 ieee80211_find_node_with_ssid(ieee80211_node_table_t *nt,
991 const uint8_t *macaddr, uint32_t ssidlen, const uint8_t *ssid)
993 ieee80211_node_t *in;
994 int hash;
996 IEEE80211_NODE_LOCK(nt);
998 hash = ieee80211_node_hash(macaddr);
999 in = list_head(&nt->nt_hash[hash]);
1000 while (in != NULL) {
1001 if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr) &&
1002 in->in_esslen == ssidlen &&
1003 memcmp(in->in_essid, ssid, ssidlen) == 0)
1004 break;
1005 in = list_next(&nt->nt_hash[hash], in);
1007 if (in != NULL) {
1008 (void) ieee80211_ref_node(in); /* mark referenced */
1010 IEEE80211_NODE_UNLOCK(nt);
1012 return (in);
1016 * Fake up a node; this handles node discovery in adhoc mode.
1017 * Note that for the driver's benefit we treat this like an
1018 * association so the driver has an opportunity to setup it's
1019 * private state.
1021 ieee80211_node_t *
1022 ieee80211_fakeup_adhoc_node(ieee80211_node_table_t *nt, const uint8_t *macaddr)
1024 ieee80211com_t *ic = nt->nt_ic;
1025 ieee80211_node_t *in;
1027 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_fakeup_adhoc_node: "
1028 "mac<%s>\n", ieee80211_macaddr_sprintf(macaddr));
1029 in = ieee80211_dup_bss(nt, macaddr);
1030 if (in != NULL) {
1031 /* no rate negotiation; just dup */
1032 in->in_rates = ic->ic_bss->in_rates;
1033 if (ic->ic_node_newassoc != NULL)
1034 ic->ic_node_newassoc(in, 1);
1035 ieee80211_node_authorize(in);
1037 return (in);
1040 static void
1041 ieee80211_saveie(uint8_t **iep, const uint8_t *ie)
1043 uint_t ielen = ie[1]+2;
1045 * Record information element for later use.
1047 if (*iep == NULL || (*iep)[1] != ie[1]) {
1048 if (*iep != NULL)
1049 ieee80211_free(*iep);
1050 *iep = ieee80211_malloc(ielen);
1052 if (*iep != NULL)
1053 (void) memcpy(*iep, ie, ielen);
1056 static void
1057 saveie(uint8_t **iep, const uint8_t *ie)
1059 if (ie == NULL) {
1060 if (*iep != NULL)
1061 ieee80211_free(*iep);
1062 *iep = NULL;
1064 else
1065 ieee80211_saveie(iep, ie);
1069 * Process a beacon or probe response frame.
1071 void
1072 ieee80211_add_scan(ieee80211com_t *ic, const struct ieee80211_scanparams *sp,
1073 const struct ieee80211_frame *wh, int subtype, int rssi, int rstamp)
1075 ieee80211_node_table_t *nt = &ic->ic_scan;
1076 ieee80211_node_t *in;
1077 boolean_t newnode = B_FALSE;
1079 in = ieee80211_find_node(nt, wh->i_addr3);
1080 if (in == NULL) {
1082 * Create a new entry.
1084 in = ieee80211_alloc_node(ic, nt, wh->i_addr3);
1085 if (in == NULL) {
1086 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_add_scan: "
1087 "alloc node failed\n");
1088 return;
1091 * inherit from ic_bss.
1093 ieee80211_copy_bss(in, ic->ic_bss);
1094 ieee80211_node_setchan(ic, in, ic->ic_curchan);
1095 newnode = B_TRUE;
1098 /* ap beaconing multiple ssid w/ same bssid */
1101 * sp->ssid[0] - element ID
1102 * sp->ssid[1] - length
1103 * sp->ssid[2]... - ssid
1105 if (sp->ssid[1] != 0 &&
1106 subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP ||
1107 in->in_esslen == 0) {
1108 in->in_esslen = sp->ssid[1];
1109 bzero(in->in_essid, sizeof (in->in_essid));
1110 bcopy(sp->ssid + 2, in->in_essid, sp->ssid[1]);
1112 IEEE80211_ADDR_COPY(in->in_bssid, wh->i_addr3);
1113 in->in_rssi = (uint8_t)rssi;
1114 in->in_rstamp = rstamp;
1115 bcopy(sp->tstamp, in->in_tstamp.data, sizeof (in->in_tstamp));
1116 in->in_intval = sp->bintval;
1117 in->in_capinfo = sp->capinfo;
1118 in->in_chan = &ic->ic_sup_channels[sp->chan];
1119 in->in_phytype = sp->phytype;
1120 in->in_fhdwell = sp->fhdwell;
1121 in->in_fhindex = sp->fhindex;
1122 in->in_erp = sp->erp;
1123 if (sp->tim != NULL) {
1124 struct ieee80211_tim_ie *ie;
1126 ie = (struct ieee80211_tim_ie *)sp->tim;
1127 in->in_dtim_count = ie->tim_count;
1128 in->in_dtim_period = ie->tim_period;
1131 * Record the byte offset from the mac header to
1132 * the start of the TIM information element for
1133 * use by hardware and/or to speedup software
1134 * processing of beacon frames.
1136 in->in_tim_off = sp->timoff;
1138 * Record optional information elements that might be
1139 * used by applications or drivers.
1141 saveie(&in->in_wme_ie, sp->wme);
1142 saveie(&in->in_wpa_ie, sp->wpa);
1143 saveie(&in->in_htcap_ie, sp->htcap);
1144 /* parsed in ieee80211_sta_join() */
1145 if (sp->htcap != NULL)
1146 ieee80211_parse_htcap(in, in->in_htcap_ie);
1148 /* NB: must be after in_chan is setup */
1149 (void) ieee80211_setup_rates(in, sp->rates, sp->xrates,
1150 IEEE80211_F_DOSORT);
1152 if (!newnode)
1153 ieee80211_free_node(in);
1157 * Initialize/update an ad-hoc node with contents from a received
1158 * beacon frame.
1160 void
1161 ieee80211_init_neighbor(ieee80211_node_t *in, const struct ieee80211_frame *wh,
1162 const struct ieee80211_scanparams *sp)
1164 in->in_esslen = sp->ssid[1];
1165 (void) memcpy(in->in_essid, sp->ssid + 2, sp->ssid[1]);
1166 IEEE80211_ADDR_COPY(in->in_bssid, wh->i_addr3);
1167 (void) memcpy(in->in_tstamp.data, sp->tstamp, sizeof (in->in_tstamp));
1168 in->in_intval = sp->bintval;
1169 in->in_capinfo = sp->capinfo;
1170 in->in_chan = in->in_ic->ic_curchan;
1171 in->in_fhdwell = sp->fhdwell;
1172 in->in_fhindex = sp->fhindex;
1173 in->in_erp = sp->erp;
1174 in->in_tim_off = sp->timoff;
1175 if (sp->wme != NULL)
1176 ieee80211_saveie(&in->in_wme_ie, sp->wme);
1178 /* NB: must be after in_chan is setup */
1179 (void) ieee80211_setup_rates(in, sp->rates, sp->xrates,
1180 IEEE80211_F_DOSORT);
1184 * Do node discovery in adhoc mode on receipt of a beacon
1185 * or probe response frame. Note that for the driver's
1186 * benefit we we treat this like an association so the
1187 * driver has an opportuinty to setup it's private state.
1189 ieee80211_node_t *
1190 ieee80211_add_neighbor(ieee80211com_t *ic, const struct ieee80211_frame *wh,
1191 const struct ieee80211_scanparams *sp)
1193 ieee80211_node_t *in;
1195 in = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);
1196 if (in != NULL) {
1197 ieee80211_init_neighbor(in, wh, sp);
1198 if (ic->ic_node_newassoc != NULL)
1199 ic->ic_node_newassoc(in, 1);
1201 return (in);
1204 #define IEEE80211_IS_CTL(wh) \
1205 ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
1207 #define IEEE80211_IS_PSPOLL(wh) \
1208 ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
1209 IEEE80211_FC0_SUBTYPE_PS_POLL)
1211 #define IEEE80211_IS_BAR(wh) \
1212 ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
1213 IEEE80211_FC0_SUBTYPE_BAR)
1216 * Locate the node for sender, track state, and then pass the
1217 * (referenced) node up to the 802.11 layer for its use. We
1218 * are required to pass some node so we fall back to ic_bss
1219 * when this frame is from an unknown sender. The 802.11 layer
1220 * knows this means the sender wasn't in the node table and
1221 * acts accordingly.
1223 ieee80211_node_t *
1224 ieee80211_find_rxnode(ieee80211com_t *ic, const struct ieee80211_frame *wh)
1226 ieee80211_node_table_t *nt;
1227 ieee80211_node_t *in;
1229 /* may want scanned nodes in the neighbor table for adhoc */
1230 if (ic->ic_opmode == IEEE80211_M_STA ||
1231 (ic->ic_flags & IEEE80211_F_SCAN)) {
1232 nt = &ic->ic_scan;
1233 } else {
1234 nt = &ic->ic_sta;
1237 IEEE80211_NODE_LOCK(nt);
1238 if (IEEE80211_IS_CTL(wh) &&
1239 !IEEE80211_IS_PSPOLL(wh) && !IEEE80211_IS_BAR(wh))
1240 in = ieee80211_find_node_locked(nt, wh->i_addr1);
1241 else
1242 in = ieee80211_find_node_locked(nt, wh->i_addr2);
1243 IEEE80211_NODE_UNLOCK(nt);
1245 if (in == NULL)
1246 in = ieee80211_ref_node(ic->ic_bss);
1248 return (in);
1251 #undef IEEE80211_IS_BAR
1252 #undef IEEE80211_IS_PSPOLL
1253 #undef IEEE80211_IS_CTL
1256 * Return a reference to the appropriate node for sending
1257 * a data frame. This handles node discovery in adhoc networks.
1259 ieee80211_node_t *
1260 ieee80211_find_txnode(ieee80211com_t *ic, const uint8_t *daddr)
1262 ieee80211_node_table_t *nt = &ic->ic_sta;
1263 ieee80211_node_t *in;
1266 * The destination address should be in the node table
1267 * unless this is a multicast/broadcast frame. We can
1268 * also optimize station mode operation, all frames go
1269 * to the bss node.
1271 IEEE80211_NODE_LOCK(nt);
1272 if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(daddr))
1273 in = ieee80211_ref_node(ic->ic_bss);
1274 else
1275 in = ieee80211_find_node_locked(nt, daddr);
1276 IEEE80211_NODE_UNLOCK(nt);
1278 if (in == NULL) {
1279 if (ic->ic_opmode == IEEE80211_M_IBSS) {
1281 * In adhoc mode cons up a node for the destination.
1282 * Note that we need an additional reference for the
1283 * caller to be consistent with
1284 * ieee80211_find_node_locked
1285 * can't hold lock across ieee80211_dup_bss 'cuz of
1286 * recursive locking
1288 in = ieee80211_fakeup_adhoc_node(nt, daddr);
1289 if (in != NULL)
1290 (void) ieee80211_ref_node(in);
1291 } else {
1292 ieee80211_dbg(IEEE80211_MSG_OUTPUT,
1293 "ieee80211_find_txnode: "
1294 "[%s] no node, discard frame\n",
1295 ieee80211_macaddr_sprintf(daddr));
1298 return (in);
1302 * Remove a node from the node database entries and free memory
1303 * associated with the node. The node table lock is acquired by
1304 * the caller.
1306 static void
1307 ieee80211_free_node_locked(ieee80211_node_t *in)
1309 ieee80211com_t *ic = in->in_ic;
1310 ieee80211_node_table_t *nt = in->in_table;
1311 int32_t hash;
1313 if (nt != NULL) {
1314 hash = ieee80211_node_hash(in->in_macaddr);
1315 list_remove(&nt->nt_hash[hash], in);
1316 list_remove(&nt->nt_node, in);
1318 ic->ic_node_free(in);
1322 * Remove a node from the node database entries and free any
1323 * memory associated with the node.
1324 * This method can be overridden in ieee80211_attach()
1326 void
1327 ieee80211_free_node(ieee80211_node_t *in)
1329 ieee80211_node_table_t *nt = in->in_table;
1331 if (nt != NULL)
1332 IEEE80211_NODE_LOCK(nt);
1333 if (ieee80211_node_decref_nv(in) == 0)
1334 ieee80211_free_node_locked(in);
1335 if (nt != NULL)
1336 IEEE80211_NODE_UNLOCK(nt);
1340 * Reclaim a node. If this is the last reference count then
1341 * do the normal free work. Otherwise remove it from the node
1342 * table and mark it gone by clearing the back-reference.
1344 static void
1345 ieee80211_node_reclaim(ieee80211_node_table_t *nt, ieee80211_node_t *in)
1347 int32_t hash;
1349 IEEE80211_NODE_LOCK_ASSERT(nt);
1350 ieee80211_dbg(IEEE80211_MSG_NODE, "node_reclaim: "
1351 " remove %p<%s> from %s table, refcnt %d\n",
1352 in, ieee80211_macaddr_sprintf(in->in_macaddr), nt->nt_name,
1353 ieee80211_node_refcnt(in));
1355 if (ieee80211_node_decref_nv(in) != 0) {
1357 * Clear any entry in the unicast key mapping table.
1358 * We need to do it here so rx lookups don't find it
1359 * in the mapping table even if it's not in the hash
1360 * table. We cannot depend on the mapping table entry
1361 * being cleared because the node may not be free'd.
1363 hash = ieee80211_node_hash(in->in_macaddr);
1364 list_remove(&nt->nt_hash[hash], in);
1365 list_remove(&nt->nt_node, in);
1366 in->in_table = NULL;
1367 } else {
1368 ieee80211_free_node_locked(in);
1373 * Iterate through the node list and reclaim all node in the node table.
1374 * The node table lock is acquired by the caller
1376 static void
1377 ieee80211_free_allnodes_locked(ieee80211_node_table_t *nt)
1379 ieee80211_node_t *in;
1381 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_free_allnodes_locked(): "
1382 "free all nodes in %s table\n", nt->nt_name);
1384 in = list_head(&nt->nt_node);
1385 while (in != NULL) {
1386 ieee80211_node_reclaim(nt, in);
1387 in = list_head(&nt->nt_node);
1389 ieee80211_reset_erp(nt->nt_ic);
1393 * Iterate through the node list, calling ieee80211_node_reclaim() for
1394 * all nodes associated with the interface.
1396 static void
1397 ieee80211_free_allnodes(ieee80211_node_table_t *nt)
1399 IEEE80211_NODE_LOCK(nt);
1400 ieee80211_free_allnodes_locked(nt);
1401 IEEE80211_NODE_UNLOCK(nt);
1405 * Timeout entries in the scan cache. This is the timeout callback
1406 * function of node table ic_scan which is called when the inactivity
1407 * timer expires.
1409 static void
1410 ieee80211_timeout_scan_candidates(ieee80211_node_table_t *nt)
1412 ieee80211com_t *ic = nt->nt_ic;
1413 ieee80211_node_t *in;
1415 IEEE80211_NODE_LOCK(nt);
1416 in = ic->ic_bss;
1417 node_cleanfrag(in); /* Free fragment if not needed */
1418 nt->nt_inact_timer = IEEE80211_INACT_WAIT;
1419 IEEE80211_NODE_UNLOCK(nt);
1423 * Timeout inactive stations and do related housekeeping.
1424 * Note that we cannot hold the node lock while sending a
1425 * frame as this would lead to a LOR. Instead we use a
1426 * generation number to mark nodes that we've scanned and
1427 * drop the lock and restart a scan if we have to time out
1428 * a node. Since we are single-threaded by virtue of
1429 * controlling the inactivity timer we can be sure this will
1430 * process each node only once.
1432 static void
1433 ieee80211_timeout_stations(ieee80211_node_table_t *nt)
1435 ieee80211com_t *ic = nt->nt_ic;
1436 ieee80211_impl_t *im = ic->ic_private;
1437 ieee80211_node_t *in = NULL;
1438 uint32_t gen;
1439 boolean_t isadhoc;
1441 IEEE80211_LOCK_ASSERT(ic);
1442 isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS ||
1443 ic->ic_opmode == IEEE80211_M_AHDEMO);
1444 IEEE80211_SCAN_LOCK(nt);
1445 gen = ++nt->nt_scangen;
1446 restart:
1447 IEEE80211_NODE_LOCK(nt);
1448 for (in = list_head(&nt->nt_node); in != NULL;
1449 in = list_next(&nt->nt_node, in)) {
1450 if (in->in_scangen == gen) /* previously handled */
1451 continue;
1452 in->in_scangen = gen;
1453 node_cleanfrag(in); /* free fragment if not needed */
1456 * Special case ourself; we may be idle for extended periods
1457 * of time and regardless reclaiming our state is wrong.
1459 if (in == ic->ic_bss)
1460 continue;
1461 in->in_inact--;
1462 if (in->in_associd != 0 || isadhoc) {
1464 * Probe the station before time it out. We
1465 * send a null data frame which may not be
1466 * uinversally supported by drivers (need it
1467 * for ps-poll support so it should be...).
1469 if (0 < in->in_inact &&
1470 in->in_inact <= im->im_inact_probe) {
1471 ieee80211_dbg(IEEE80211_MSG_NODE, "net80211: "
1472 "probe station due to inactivity\n");
1473 IEEE80211_NODE_UNLOCK(nt);
1474 IEEE80211_UNLOCK(ic);
1475 (void) ieee80211_send_nulldata(in);
1476 IEEE80211_LOCK(ic);
1477 goto restart;
1480 if (in->in_inact <= 0) {
1481 ieee80211_dbg(IEEE80211_MSG_NODE, "net80211: "
1482 "station timed out due to inact (refcnt %u)\n",
1483 ieee80211_node_refcnt(in));
1485 * Send a deauthenticate frame and drop the station.
1486 * This is somewhat complicated due to reference counts
1487 * and locking. At this point a station will typically
1488 * have a reference count of 1. ieee80211_node_leave
1489 * will do a "free" of the node which will drop the
1490 * reference count. But in the meantime a reference
1491 * wil be held by the deauth frame. The actual reclaim
1492 * of the node will happen either after the tx is
1493 * completed or by ieee80211_node_leave.
1495 * Separately we must drop the node lock before sending
1496 * in case the driver takes a lock, as this will result
1497 * in LOR between the node lock and the driver lock.
1499 IEEE80211_NODE_UNLOCK(nt);
1500 if (in->in_associd != 0) {
1501 IEEE80211_UNLOCK(ic);
1502 IEEE80211_SEND_MGMT(ic, in,
1503 IEEE80211_FC0_SUBTYPE_DEAUTH,
1504 IEEE80211_REASON_AUTH_EXPIRE);
1505 IEEE80211_LOCK(ic);
1507 ieee80211_node_leave(ic, in);
1508 goto restart;
1511 IEEE80211_NODE_UNLOCK(nt);
1513 IEEE80211_SCAN_UNLOCK(nt);
1515 nt->nt_inact_timer = IEEE80211_INACT_WAIT;
1519 * Call the user-defined call back function for all nodes in
1520 * the node cache. The callback is invoked with the user-supplied
1521 * value and a pointer to the current node.
1523 void
1524 ieee80211_iterate_nodes(ieee80211_node_table_t *nt, ieee80211_iter_func *f,
1525 void *arg)
1527 ieee80211_node_t *in;
1529 IEEE80211_NODE_LOCK(nt);
1530 in = list_head(&nt->nt_node);
1531 while (in != NULL) {
1532 if (in->in_chan == IEEE80211_CHAN_ANYC) {
1533 in = list_next(&nt->nt_node, in);
1534 continue;
1536 (void) ieee80211_ref_node(in);
1537 IEEE80211_NODE_UNLOCK(nt);
1538 (*f)(arg, in);
1539 ieee80211_free_node(in);
1540 IEEE80211_NODE_LOCK(nt);
1541 in = list_next(&nt->nt_node, in);
1543 IEEE80211_NODE_UNLOCK(nt);
1547 * Handle bookkeeping for station deauthentication/disassociation
1548 * when operating as an ap.
1550 static void
1551 ieee80211_node_leave(ieee80211com_t *ic, ieee80211_node_t *in)
1553 ieee80211_node_table_t *nt = in->in_table;
1555 ASSERT(ic->ic_opmode == IEEE80211_M_IBSS);
1558 * Remove the node from any table it's recorded in and
1559 * drop the caller's reference. Removal from the table
1560 * is important to insure the node is not reprocessed
1561 * for inactivity.
1563 if (nt != NULL) {
1564 IEEE80211_NODE_LOCK(nt);
1565 ieee80211_node_reclaim(nt, in);
1566 IEEE80211_NODE_UNLOCK(nt);
1567 } else {
1568 ieee80211_free_node(in);
1573 * Initialize a node table with specified name, inactivity timer value
1574 * and callback inactivity timeout function. Associate the node table
1575 * with interface softc, ic.
1577 static void
1578 ieee80211_node_table_init(ieee80211com_t *ic, ieee80211_node_table_t *nt,
1579 const char *name, int inact, int keyixmax,
1580 void (*timeout)(ieee80211_node_table_t *))
1582 int i;
1584 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_init():"
1585 "%s table, inact %d\n", name, inact);
1587 nt->nt_ic = ic;
1588 nt->nt_name = name;
1589 nt->nt_inact_timer = 0;
1590 nt->nt_inact_init = inact;
1591 nt->nt_timeout = timeout;
1592 nt->nt_keyixmax = keyixmax;
1593 nt->nt_scangen = 1;
1594 mutex_init(&nt->nt_scanlock, NULL, MUTEX_DRIVER, NULL);
1595 mutex_init(&nt->nt_nodelock, NULL, MUTEX_DRIVER, NULL);
1597 list_create(&nt->nt_node, sizeof (ieee80211_node_t),
1598 offsetof(ieee80211_node_t, in_node));
1599 for (i = 0; i < IEEE80211_NODE_HASHSIZE; i++) {
1600 list_create(&nt->nt_hash[i], sizeof (ieee80211_node_t),
1601 offsetof(ieee80211_node_t, in_hash));
1606 * Reset a node table. Clean its inactivity timer and call
1607 * ieee80211_free_allnodes_locked() to free all nodes in the
1608 * node table.
1610 void
1611 ieee80211_node_table_reset(ieee80211_node_table_t *nt)
1613 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_reset(): "
1614 "%s table\n", nt->nt_name);
1616 IEEE80211_NODE_LOCK(nt);
1617 nt->nt_inact_timer = 0;
1618 ieee80211_free_allnodes_locked(nt);
1619 IEEE80211_NODE_UNLOCK(nt);
1623 * Destroy a node table. Free all nodes in the node table.
1624 * This function is usually called by node detach function.
1626 static void
1627 ieee80211_node_table_cleanup(ieee80211_node_table_t *nt)
1629 ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_cleanup(): "
1630 "%s table\n", nt->nt_name);
1632 IEEE80211_NODE_LOCK(nt);
1633 ieee80211_free_allnodes_locked(nt);
1634 IEEE80211_NODE_UNLOCK(nt);
1635 mutex_destroy(&nt->nt_nodelock);
1636 mutex_destroy(&nt->nt_scanlock);