0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
19d332fefbc61327bb6187d0eb818629f3b52c6ffei feng - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Use is subject to license terms.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Copyright (c) 2001 Atsushi Onoe
19d332fefbc61327bb6187d0eb818629f3b52c6ffei feng - Sun Microsystems - Beijing China * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * All rights reserved.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Redistribution and use in source and binary forms, with or without
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * modification, are permitted provided that the following conditions
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * are met:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * 1. Redistributions of source code must retain the above copyright
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * notice, this list of conditions and the following disclaimer.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * 2. Redistributions in binary form must reproduce the above copyright
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * notice, this list of conditions and the following disclaimer in the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * documentation and/or other materials provided with the distribution.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * 3. The name of the author may not be used to endorse or promote products
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * derived from this software without specific prior written permission.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Alternatively, this software may be distributed under the terms of the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * GNU General Public License ("GPL") version 2 as published by the Free
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Software Foundation.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Node management routines
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#include "net80211_impl.h"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic ieee80211_node_t *ieee80211_node_alloc(ieee80211com_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_node_cleanup(ieee80211_node_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_node_free(ieee80211_node_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic uint8_t ieee80211_node_getrssi(const ieee80211_node_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_setup_node(ieee80211com_t *, ieee80211_node_table_t *,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *, const uint8_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_node_reclaim(ieee80211_node_table_t *,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_free_node_locked(ieee80211_node_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_free_allnodes(ieee80211_node_table_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_node_leave(ieee80211com_t *, ieee80211_node_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_timeout_scan_candidates(ieee80211_node_table_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_timeout_stations(ieee80211_node_table_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_node_table_init(ieee80211com_t *,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *, const char *, int, int,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc void (*timeout)(ieee80211_node_table_t *));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void ieee80211_node_table_cleanup(ieee80211_node_table_t *);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * association failures before ignored
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The failure may be caused by the response frame is lost for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * environmental reason. So Try associate more than once before
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ignore the node
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#define IEEE80211_STA_FAILS_MAX 2
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Initialize node database management callbacks for the interface.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This function is called by ieee80211_attach(). These callback
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * functions may be overridden in special circumstances, as long as
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * as this is done after calling ieee80211_attach() and prior to any
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * other call which may allocate a node
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_attach(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_impl *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_alloc = ieee80211_node_alloc;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_free = ieee80211_node_free;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_cleanup = ieee80211_node_cleanup;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_getrssi = ieee80211_node_getrssi;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* default station inactivity timer setings */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_inact_init = IEEE80211_INACT_INIT;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_inact_assoc = IEEE80211_INACT_ASSOC;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_inact_run = IEEE80211_INACT_RUN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_inact_probe = IEEE80211_INACT_PROBE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Initialize node databases and the ic_bss node element.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_lateattach(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Calculate ic_tim_bitmap size in bytes
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * IEEE80211_AID_MAX defines maximum bits in ic_tim_bitmap
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_tim_len = howmany(IEEE80211_AID_MAX, 8) * sizeof (uint8_t);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_init(ic, &ic->ic_sta, "station",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_INACT_INIT, IEEE80211_WEP_NKID,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_timeout_stations);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_init(ic, &ic->ic_scan, "scan",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_INACT_SCAN, 0, ieee80211_timeout_scan_candidates);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_reset_bss(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Destroy all node databases and is usually called during device detach
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_detach(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* Node Detach */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_bss != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(ic->ic_bss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_bss = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_cleanup(&ic->ic_scan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_cleanup(&ic->ic_sta);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Increase a node's reference count
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Return pointer to the node
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_ref_node(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_incref(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Dexrease a node's reference count
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_unref_node(ieee80211_node_t **in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_decref(*in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *in = NULL; /* guard against use */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Mark ports authorized for data traffic. This function is usually
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * used by 802.1x authenticator.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_authorize(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = in->in_ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_flags |= IEEE80211_NODE_AUTH;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact_reload = im->im_inact_run;
19d332fefbc61327bb6187d0eb818629f3b52c6ffei feng - Sun Microsystems - Beijing China in->in_inact = in->in_inact_reload;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Mark ports unauthorized for data traffic. This function is usually
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * used by 802.1x authenticator.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_unauthorize(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_flags &= ~IEEE80211_NODE_AUTH;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Set/change the channel. The rate set is also updated as
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * to insure a consistent view by drivers.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_setchan(ieee80211com_t *ic, ieee80211_node_t *in,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_channel *chan)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (chan == IEEE80211_CHAN_ANYC)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc chan = ic->ic_curchan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_chan = chan;
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (IEEE80211_IS_CHAN_HT(chan)) {
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang /*
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang * Gotta be careful here; the rate set returned by
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang * ieee80211_get_suprates is actually any HT rate
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang * set so blindly copying it will be bad. We must
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang * install the legacy rate est in ni_rates and the
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang * HT rate set in ni_htrates.
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang */
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang in->in_htrates = *ieee80211_get_suphtrates(ic, chan);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang }
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang in->in_rates = *ieee80211_get_suprates(ic, chan);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang /* in->in_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Initialize the channel set to scan based on the available channels
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and the current PHY mode.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_reset_scan(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) memset(im->im_chan_scan, 0, sizeof (im->im_chan_scan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_setbit(im->im_chan_scan,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_chan2ieee(ic, ic->ic_des_chan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(ic->ic_chan_active, im->im_chan_scan,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx sizeof (ic->ic_chan_active));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_reset_scan(): "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "start chan %u\n", ieee80211_chan2ieee(ic, ic->ic_curchan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Begin an active scan. Initialize the node cache. The scan
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * begins on the next radio channel by calling ieee80211_next_scan().
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The actual scanning is not automated. The driver itself
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * only handles setting the radio frequency and stepping through
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the channels.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_begin_scan(ieee80211com_t *ic, boolean_t reset)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode != IEEE80211_M_HOSTAP)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_ASCAN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_SCAN,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "begin %s scan in %s mode on channel %u\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_phymode_name[ic->ic_curmode],
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_chan2ieee(ic, ic->ic_curchan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Clear scan state and flush any previously seen AP's.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_reset_scan(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (reset)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_allnodes(&ic->ic_scan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_SCAN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* Scan the next channel. */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_next_scan(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Switch to the next channel marked for scanning.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * A driver is expected to first call ieee80211_begin_scan(),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * to initialize the node cache, then set the radio channel
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * on the device. And then after a certain time has elapsed,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * call ieee80211_next_scan() to move to the next channel.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Typically, a timeout routine is used to automate this process.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_next_scan(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_channel *chan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Insure any previous mgt frame timeouts don't fire.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This assumes the driver does the right thing in
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * flushing anything queued in the driver and below.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_mgt_timer = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc chan = ic->ic_curchan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc do {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (++chan > &ic->ic_sup_channels[IEEE80211_CHAN_MAX])
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc chan = &ic->ic_sup_channels[0];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_isset(im->im_chan_scan,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_chan2ieee(ic, chan))) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_clrbit(im->im_chan_scan,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_chan2ieee(ic, chan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_SCAN,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "ieee80211_next_scan: chan %d->%d\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_chan2ieee(ic, ic->ic_curchan),
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_chan2ieee(ic, chan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curchan = chan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * drivers should do this as needed,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * for now maintain compatibility
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_bss->in_rates =
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } while (chan != ic->ic_curchan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_end_scan(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Copy useful state from node obss into nbss.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_copy_bss(ieee80211_node_t *nbss, const ieee80211_node_t *obss)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* propagate useful state */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nbss->in_authmode = obss->in_authmode;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nbss->in_txpower = obss->in_txpower;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nbss->in_vlan = obss->in_vlan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Setup the net80211 specific portion of an interface's softc, ic,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * for use in IBSS mode
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_create_ibss(ieee80211com_t *ic, struct ieee80211_channel *chan)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK_ASSERT(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_create_ibss: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "creating ibss\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Create the station/neighbor table. Note that for adhoc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * mode we make the initial inactivity timer longer since
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * we create nodes only through discovery and they typically
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * are long-lived associations.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt = &ic->ic_sta;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_name = "neighbor";
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_init = im->im_inact_run;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_alloc_node(ic, &ic->ic_sta, ic->ic_macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_err("ieee80211_create_ibss(): alloc node failed\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_esslen = ic->ic_des_esslen;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) memcpy(in->in_essid, ic->ic_des_essid, in->in_esslen);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_copy_bss(in, ic->ic_bss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_intval = ic->ic_bintval;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_PRIVACY)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo |= IEEE80211_CAPINFO_PRIVACY;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_phytype == IEEE80211_T_FH) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fhdwell = 200;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fhindex = 1;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (ic->ic_opmode) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_IBSS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_SIBSS;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo |= IEEE80211_CAPINFO_IBSS;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_DESBSSID)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_des_bssid);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_bssid[0] |= 0x02; /* local bit for IBSS */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_AHDEMO:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_DESBSSID)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_des_bssid);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) memset(in->in_bssid, 0, IEEE80211_ADDR_LEN);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_err("ieee80211_create_ibss(): "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "wrong opmode %u to creat IBSS, abort\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ic->ic_opmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Fix the channel and related attributes.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_setchan(ic, in, chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curchan = chan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curmode = ieee80211_chan2mode(ic, chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Do mode-specific rate setup.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_setbasicrates(&in->in_rates, ic->ic_curmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_sta_join(ic, ieee80211_ref_node(in));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_reset_bss(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *obss;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
19d332fefbc61327bb6187d0eb818629f3b52c6ffei feng - Sun Microsystems - Beijing China ieee80211_node_table_reset(&ic->ic_sta);
19d332fefbc61327bb6187d0eb818629f3b52c6ffei feng - Sun Microsystems - Beijing China ieee80211_reset_erp(ic);
19d332fefbc61327bb6187d0eb818629f3b52c6ffei feng - Sun Microsystems - Beijing China
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_alloc_node(ic, &ic->ic_scan, ic->ic_macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ASSERT(in != NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc obss = ic->ic_bss;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_bss = ieee80211_ref_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (obss != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_copy_bss(in, obss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_intval = ic->ic_bintval;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(obss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic int
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_match_bss(ieee80211com_t *ic, ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t rate;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int fail;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_isclr(ic->ic_chan_active,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_chan2ieee(ic, in->in_chan))) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADCHAN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_chan != ic->ic_des_chan) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADCHAN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_IBSS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(in->in_capinfo & IEEE80211_CAPINFO_IBSS))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADOPMODE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(in->in_capinfo & IEEE80211_CAPINFO_ESS))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADOPMODE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_PRIVACY) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(in->in_capinfo & IEEE80211_CAPINFO_PRIVACY))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADPRIVACY;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADPRIVACY;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang rate = ieee80211_fix_rate(in, &in->in_rates,
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (rate & IEEE80211_RATE_BASIC)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADRATE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_des_esslen != 0 &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (in->in_esslen != ic->ic_des_esslen ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc memcmp(in->in_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADESSID;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !IEEE80211_ADDR_EQ(ic->ic_des_bssid, in->in_bssid)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_BADBSSID;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_fails >= IEEE80211_STA_FAILS_MAX)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fail |= IEEE80211_NODEFAIL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (fail);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#define IEEE80211_MAXRATE(_rs) \
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ((_rs).ir_rates[(_rs).ir_nrates - 1] & IEEE80211_RATE_VAL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Compare the capabilities of node a with node b and decide which is
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * more desirable (return b if b is considered better than a). Note
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * that we assume compatibility/usability has already been checked
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * so we don't need to (e.g. validate whether privacy is supported).
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Used to select the best scan candidate for association in a BSS.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Return desired node
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic ieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_compare(ieee80211com_t *ic, ieee80211_node_t *a,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *b)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t maxa;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t maxb;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t rssia;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t rssib;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* privacy support preferred */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !(b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (a);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (b);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* compare count of previous failures */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (b->in_fails != a->in_fails)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return ((a->in_fails > b->in_fails) ? b : a);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rssia = ic->ic_node_getrssi(a);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rssib = ic->ic_node_getrssi(b);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ABS(rssib - rssia) < IEEE80211_RSSI_CMP_THRESHOLD) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* best/max rate preferred if signal level close enough */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc maxa = IEEE80211_MAXRATE(a->in_rates);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc maxb = IEEE80211_MAXRATE(b->in_rates);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (maxa != maxb)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return ((maxb > maxa) ? b : a);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* for now just prefer 5Ghz band to all other bands */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (IEEE80211_IS_CHAN_5GHZ(a->in_chan) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !IEEE80211_IS_CHAN_5GHZ(b->in_chan)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (a);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!IEEE80211_IS_CHAN_5GHZ(a->in_chan) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_IS_CHAN_5GHZ(b->in_chan)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (b);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* all things being equal, compare signal level */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return ((rssib > rssia) ? b : a);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Mark an ongoing scan stopped.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_cancel_scan(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_cancel_scan()"
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "end %s scan\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc cv_broadcast(&((ieee80211_impl_t *)ic->ic_private)->im_scan_cv);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Complete a scan of potential channels. It is called by
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_next_scan() when the state machine has performed
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * a full cycle of scaning on all available radio channels.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_end_scan() will inspect the node cache for suitable
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * APs found during scaning, and associate with one, should
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the parameters of the node match those of the configuration
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * requested from userland.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_end_scan(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt = &ic->ic_scan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *selbs;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_cancel_scan(ic);
a399b7655a1d835aa8606c2b29e4e777baac8635zf /* notify SCAN done */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_notify(ic, EVENT_SCAN_RESULTS);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Automatic sequencing; look for a candidate and
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * if found join the network.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: unlocked read should be ok */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_head(&nt->nt_node);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (in == NULL && (ic->ic_flags & IEEE80211_F_WPA) == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_end_scan: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "no scan candidate\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc notfound:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_IBSS &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (ic->ic_flags & IEEE80211_F_IBSSON) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_des_esslen != 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_create_ibss(ic, ic->ic_ibss_chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Reset the list of channels to scan and start again.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_reset_scan(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_next_scan(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (ic->ic_flags & IEEE80211_F_SCANONLY ||
a399b7655a1d835aa8606c2b29e4e777baac8635zf ic->ic_flags & IEEE80211_F_WPA) { /* scan only */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags &= ~IEEE80211_F_SCANONLY;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc selbs = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_fails >= IEEE80211_STA_FAILS_MAX) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *tmpin = in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The configuration of the access points may change
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * during my scan. So delete the entry for the AP
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and retry to associate if there is another beacon.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_next(&nt->nt_node, tmpin);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_reclaim(nt, tmpin);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc continue;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh /*
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh * It's possible at some special moments, the in_chan will
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh * be none. Need to skip the null node.
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh */
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh if (in->in_chan == IEEE80211_CHAN_ANYC) {
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh in = list_next(&nt->nt_node, in);
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh continue;
e919bf2527d9be309ffa7a8e1e613bed177e7c24eh }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_match_bss(ic, in) == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (selbs == NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc selbs = in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc selbs = ieee80211_node_compare(ic, selbs, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_next(&nt->nt_node, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (selbs != NULL) /* grab ref while dropping lock */
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) ieee80211_ref_node(selbs);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (selbs == NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto notfound;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_sta_join(ic, selbs);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Handle 802.11 ad hoc network merge. The convention, set by the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Wireless Ethernet Compatibility Alliance (WECA), is that an 802.11
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * station will change its BSSID to match the "oldest" 802.11 ad hoc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * network, on the same channel, that has the station's desired SSID.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The "oldest" 802.11 network sends beacons with the greatest TSF
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * timestamp.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The caller is assumed to validate TSF's before attempting a merge.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Return B_TRUE if the BSSID changed, B_FALSE otherwise.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcboolean_t
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_ibss_merge(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = in->in_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == ic->ic_bss ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_EQ(in->in_bssid, ic->ic_bss->in_bssid)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* unchanged, nothing to do */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (B_FALSE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_match_bss(ic, in) != 0) { /* capabilities mismatch */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_ibss_merge: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx " merge failed, capabilities mismatch\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (B_FALSE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_ibss_merge: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "new bssid %s: %s preamble, %s slot time%s\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_macaddr_sprintf(in->in_bssid),
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx (ic->ic_flags & IEEE80211_F_SHSLOT) ? "short" : "long",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx (ic->ic_flags&IEEE80211_F_USEPROT) ? ", protection" : "");
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_sta_join(ic, ieee80211_ref_node(in));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (B_TRUE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang/*
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang * Change the bss channel.
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang */
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fangvoid
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fangieee80211_setcurchan(ieee80211com_t *ic, struct ieee80211_channel *c)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang{
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ic->ic_curchan = c;
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ic->ic_curmode = ieee80211_chan2mode(ic, ic->ic_curchan);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (ic->ic_set_channel != NULL)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ic->ic_set_channel(ic);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang}
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Join the specified IBSS/BSS network. The node is assumed to
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * be passed in with a held reference.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_sta_join(ieee80211com_t *ic, ieee80211_node_t *selbs)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *obss;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_IBSS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Delete unusable rates; we've already checked
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * that the negotiated rate set is acceptable.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang (void) ieee80211_fix_rate(selbs, &selbs->in_rates,
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang IEEE80211_F_DODEL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Fillin the neighbor table
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt = &ic->ic_sta;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_name = "neighbor";
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_init = im->im_inact_run;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Committed to selbs, setup state.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc obss = ic->ic_bss;
a399b7655a1d835aa8606c2b29e4e777baac8635zf ic->ic_bss = selbs; /* caller assumed to bump refcnt */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (obss != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_copy_bss(selbs, obss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(obss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curmode = ieee80211_chan2mode(ic, selbs->in_chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curchan = selbs->in_chan;
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ic->ic_phytype = selbs->in_phytype;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Set the erp state (mostly the slot time) to deal with
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the auto-select case; this should be redundant if the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * mode is locked.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_reset_erp(ic);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ieee80211_wme_initparams(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Leave the specified IBSS/BSS network. The node is assumed to
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * be passed in with a held reference.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_sta_leave(ieee80211com_t *ic, ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_cleanup(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_notify_node_leave(ic, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Allocate a node. This is the default callback function for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ic_node_alloc. This function may be overridden by the driver
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * to allocate device specific node structure.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/* ARGSUSED */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic ieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_alloc(ieee80211com_t *ic)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (kmem_zalloc(sizeof (ieee80211_node_t), KM_SLEEP));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Cleanup a node, free any memory associated with the node.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This is the default callback function for ic_node_cleanup
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and may be overridden by the driver.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_cleanup(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_associd = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rssi = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rstamp = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_challenge != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc kmem_free(in->in_challenge, IEEE80211_CHALLENGE_LEN);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_challenge = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_rxfrag != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc freemsg(in->in_rxfrag);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxfrag = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Free a node. This is the default callback function for ic_node_free
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and may be overridden by the driver to free memory used by device
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * specific node structure
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_free(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = in->in_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_cleanup(in);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (in->in_wpa_ie != NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_free(in->in_wpa_ie);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (in->in_wme_ie != NULL)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ieee80211_free(in->in_wme_ie);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (in->in_htcap_ie != NULL)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ieee80211_free(in->in_htcap_ie);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc kmem_free(in, sizeof (ieee80211_node_t));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Get a node current RSSI value. This is the default callback function
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * for ic_node_getrssi and may be overridden by the driver to provide
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * device specific RSSI calculation algorithm.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic uint8_t
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_getrssi(const ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in->in_rssi);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/* Free fragment if not needed anymore */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcnode_cleanfrag(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc clock_t ticks;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ticks = ddi_get_lbolt();
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_rxfrag != NULL && ticks > (in->in_rxfragstamp + hz)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc freemsg(in->in_rxfrag);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxfrag = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Setup a node. Initialize the node with specified macaddr. Associate
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * with the interface softc, ic, and add it to the specified node
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * database.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_setup_node(ieee80211com_t *ic, ieee80211_node_table_t *nt,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in, const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int32_t hash;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_setup_node(): "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "%p<%s> in %s table\n", in,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_macaddr_sprintf(macaddr),
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx (nt != NULL) ? nt->nt_name : "NULL");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_ic = ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_macaddr, macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc hash = ieee80211_node_hash(macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_initref(in); /* mark referenced */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_authmode = IEEE80211_AUTH_OPEN;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_txpower = ic->ic_txpowlimit; /* max power */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_chan = IEEE80211_CHAN_ANYC;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact_reload = IEEE80211_INACT_INIT;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact = in->in_inact_reload;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_crypto_resetkey(ic, &in->in_ucastkey, IEEE80211_KEYIX_NONE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (nt != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_insert_tail(&nt->nt_node, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_insert_tail(&nt->nt_hash[hash], in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_table = nt;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact_reload = nt->nt_inact_init;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Allocates and initialize a node with specified MAC address.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Associate the node with the interface ic. If the allocation
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * is successful, the node structure is initialized by
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_setup_node(); otherwise, NULL is returned
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_alloc_node(ieee80211com_t *ic, ieee80211_node_table_t *nt,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ic->ic_node_alloc(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_setup_node(ic, nt, in, macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Craft a temporary node suitable for sending a management frame
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * to the specified station. We craft only as much state as we
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * need to do the work since the node will be immediately reclaimed
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * once the send completes.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_tmp_node(ieee80211com_t *ic, const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ic->ic_node_alloc(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_tmp_node: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "%p<%s>\n", in, ieee80211_macaddr_sprintf(macaddr));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_macaddr, macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_bss->in_bssid);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_initref(in); /* mark referenced */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_txpower = ic->ic_bss->in_txpower;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: required by ieee80211_fix_rate */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_setchan(ic, in, ic->ic_bss->in_chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_crypto_resetkey(ic, &in->in_ucastkey,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_KEYIX_NONE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_table = NULL; /* NB: pedantic */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_ic = ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_dup_bss() is similar to ieee80211_alloc_node(),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * but is instead used to create a node database entry for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the specified BSSID. If the allocation is successful, the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * node is initialized, otherwise, NULL is returned.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_dup_bss(ieee80211_node_table_t *nt, const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = nt->nt_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_alloc_node(ic, nt, macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Inherit from ic_bss.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_copy_bss(in, ic->ic_bss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, ic->ic_bss->in_bssid);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_setchan(ic, in, ic->ic_bss->in_chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Iterate through the node table, searching for a node entry which
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * matches macaddr. If the entry is found, its reference count is
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * incremented, and a pointer to the node is returned; otherwise,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NULL will be returned.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The node table lock is acquired by the caller.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic ieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_find_node_locked(ieee80211_node_table_t *nt, const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int hash;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ASSERT(IEEE80211_NODE_IS_LOCKED(nt));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc hash = ieee80211_node_hash(macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_head(&nt->nt_hash[hash]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (ieee80211_ref_node(in)); /* mark referenced */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_next(&nt->nt_hash[hash], in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Iterate through the node table, searching for a node entry
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * which match specified mac address.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Return NULL if no matching node found.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_find_node(ieee80211_node_table_t *nt, const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_find_node_locked(nt, macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Like find but search based on the ssid too.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zfieee80211_node_t *
a399b7655a1d835aa8606c2b29e4e777baac8635zfieee80211_find_node_with_ssid(ieee80211_node_table_t *nt,
a399b7655a1d835aa8606c2b29e4e777baac8635zf const uint8_t *macaddr, uint32_t ssidlen, const uint8_t *ssid)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_node_t *in;
a399b7655a1d835aa8606c2b29e4e777baac8635zf int hash;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf IEEE80211_NODE_LOCK(nt);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf hash = ieee80211_node_hash(macaddr);
a399b7655a1d835aa8606c2b29e4e777baac8635zf in = list_head(&nt->nt_hash[hash]);
a399b7655a1d835aa8606c2b29e4e777baac8635zf while (in != NULL) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr) &&
a399b7655a1d835aa8606c2b29e4e777baac8635zf in->in_esslen == ssidlen &&
a399b7655a1d835aa8606c2b29e4e777baac8635zf memcmp(in->in_essid, ssid, ssidlen) == 0)
a399b7655a1d835aa8606c2b29e4e777baac8635zf break;
a399b7655a1d835aa8606c2b29e4e777baac8635zf in = list_next(&nt->nt_hash[hash], in);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (in != NULL) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) ieee80211_ref_node(in); /* mark referenced */
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf IEEE80211_NODE_UNLOCK(nt);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (in);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Fake up a node; this handles node discovery in adhoc mode.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Note that for the driver's benefit we treat this like an
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * association so the driver has an opportunity to setup it's
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * private state.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_fakeup_adhoc_node(ieee80211_node_table_t *nt, const uint8_t *macaddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = nt->nt_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_fakeup_adhoc_node: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "mac<%s>\n", ieee80211_macaddr_sprintf(macaddr));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_dup_bss(nt, macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* no rate negotiation; just dup */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rates = ic->ic_bss->in_rates;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_node_newassoc != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_newassoc(in, 1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_authorize(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void
a399b7655a1d835aa8606c2b29e4e777baac8635zfieee80211_saveie(uint8_t **iep, const uint8_t *ie)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf uint_t ielen = ie[1]+2;
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Record information element for later use.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (*iep == NULL || (*iep)[1] != ie[1]) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (*iep != NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_free(*iep);
a399b7655a1d835aa8606c2b29e4e777baac8635zf *iep = ieee80211_malloc(ielen);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (*iep != NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf (void) memcpy(*iep, ie, ielen);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void
a399b7655a1d835aa8606c2b29e4e777baac8635zfsaveie(uint8_t **iep, const uint8_t *ie)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
3a1a8936dac0ebe7e956fa122b0b0d15e62d4108zf if (ie == NULL) {
3a1a8936dac0ebe7e956fa122b0b0d15e62d4108zf if (*iep != NULL)
3a1a8936dac0ebe7e956fa122b0b0d15e62d4108zf ieee80211_free(*iep);
a399b7655a1d835aa8606c2b29e4e777baac8635zf *iep = NULL;
3a1a8936dac0ebe7e956fa122b0b0d15e62d4108zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf else
a399b7655a1d835aa8606c2b29e4e777baac8635zf ieee80211_saveie(iep, ie);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Process a beacon or probe response frame.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_add_scan(ieee80211com_t *ic, const struct ieee80211_scanparams *sp,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc const struct ieee80211_frame *wh, int subtype, int rssi, int rstamp)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt = &ic->ic_scan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc boolean_t newnode = B_FALSE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx in = ieee80211_find_node(nt, wh->i_addr3);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Create a new entry.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx in = ieee80211_alloc_node(ic, nt, wh->i_addr3);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_add_scan: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "alloc node failed\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * inherit from ic_bss.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_copy_bss(in, ic->ic_bss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_setchan(ic, in, ic->ic_curchan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc newnode = B_TRUE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* ap beaconing multiple ssid w/ same bssid */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * sp->ssid[0] - element ID
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * sp->ssid[1] - length
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * sp->ssid[2]... - ssid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (sp->ssid[1] != 0 &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_esslen == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_esslen = sp->ssid[1];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bzero(in->in_essid, sizeof (in->in_essid));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(sp->ssid + 2, in->in_essid, sp->ssid[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, wh->i_addr3);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rssi = (uint8_t)rssi;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rstamp = rstamp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(sp->tstamp, in->in_tstamp.data, sizeof (in->in_tstamp));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_intval = sp->bintval;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo = sp->capinfo;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_chan = &ic->ic_sup_channels[sp->chan];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_phytype = sp->phytype;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fhdwell = sp->fhdwell;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fhindex = sp->fhindex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_erp = sp->erp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (sp->tim != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_tim_ie *ie;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ie = (struct ieee80211_tim_ie *)sp->tim;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_dtim_count = ie->tim_count;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_dtim_period = ie->tim_period;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Record the byte offset from the mac header to
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the start of the TIM information element for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * use by hardware and/or to speedup software
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * processing of beacon frames.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_tim_off = sp->timoff;
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Record optional information elements that might be
a399b7655a1d835aa8606c2b29e4e777baac8635zf * used by applications or drivers.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang saveie(&in->in_wme_ie, sp->wme);
a399b7655a1d835aa8606c2b29e4e777baac8635zf saveie(&in->in_wpa_ie, sp->wpa);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang saveie(&in->in_htcap_ie, sp->htcap);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang /* parsed in ieee80211_sta_join() */
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (sp->htcap != NULL)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ieee80211_parse_htcap(in, in->in_htcap_ie);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: must be after in_chan is setup */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) ieee80211_setup_rates(in, sp->rates, sp->xrates,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_F_DOSORT);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!newnode)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Initialize/update an ad-hoc node with contents from a received
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * beacon frame.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_init_neighbor(ieee80211_node_t *in, const struct ieee80211_frame *wh,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc const struct ieee80211_scanparams *sp)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_esslen = sp->ssid[1];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) memcpy(in->in_essid, sp->ssid + 2, sp->ssid[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_COPY(in->in_bssid, wh->i_addr3);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) memcpy(in->in_tstamp.data, sp->tstamp, sizeof (in->in_tstamp));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_intval = sp->bintval;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo = sp->capinfo;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_chan = in->in_ic->ic_curchan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fhdwell = sp->fhdwell;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fhindex = sp->fhindex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_erp = sp->erp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_tim_off = sp->timoff;
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (sp->wme != NULL)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ieee80211_saveie(&in->in_wme_ie, sp->wme);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: must be after in_chan is setup */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) ieee80211_setup_rates(in, sp->rates, sp->xrates,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_F_DOSORT);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Do node discovery in adhoc mode on receipt of a beacon
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * or probe response frame. Note that for the driver's
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * benefit we we treat this like an association so the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * driver has an opportuinty to setup it's private state.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_add_neighbor(ieee80211com_t *ic, const struct ieee80211_frame *wh,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc const struct ieee80211_scanparams *sp)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_init_neighbor(in, wh, sp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_node_newassoc != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_newassoc(in, 1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang#define IEEE80211_IS_CTL(wh) \
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang#define IEEE80211_IS_PSPOLL(wh) \
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang IEEE80211_FC0_SUBTYPE_PS_POLL)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang#define IEEE80211_IS_BAR(wh) \
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang IEEE80211_FC0_SUBTYPE_BAR)
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Locate the node for sender, track state, and then pass the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * (referenced) node up to the 802.11 layer for its use. We
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * are required to pass some node so we fall back to ic_bss
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * when this frame is from an unknown sender. The 802.11 layer
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * knows this means the sender wasn't in the node table and
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * acts accordingly.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_find_rxnode(ieee80211com_t *ic, const struct ieee80211_frame *wh)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* may want scanned nodes in the neighbor table for adhoc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (ic->ic_flags & IEEE80211_F_SCAN)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt = &ic->ic_scan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt = &ic->ic_sta;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang if (IEEE80211_IS_CTL(wh) &&
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang !IEEE80211_IS_PSPOLL(wh) && !IEEE80211_IS_BAR(wh))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_find_node_locked(nt, wh->i_addr1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_find_node_locked(nt, wh->i_addr2);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_ref_node(ic->ic_bss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang#undef IEEE80211_IS_BAR
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang#undef IEEE80211_IS_PSPOLL
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang#undef IEEE80211_IS_CTL
e2cf88ac9d753a00c17aa235f6afdc76574fe3a6Quaker Fang
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Return a reference to the appropriate node for sending
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * a data frame. This handles node discovery in adhoc networks.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_find_txnode(ieee80211com_t *ic, const uint8_t *daddr)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt = &ic->ic_sta;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The destination address should be in the node table
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * unless this is a multicast/broadcast frame. We can
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * also optimize station mode operation, all frames go
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * to the bss node.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(daddr))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_ref_node(ic->ic_bss);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_find_node_locked(nt, daddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_IBSS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * In adhoc mode cons up a node for the destination.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Note that we need an additional reference for the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * caller to be consistent with
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_find_node_locked
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * can't hold lock across ieee80211_dup_bss 'cuz of
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * recursive locking
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_fakeup_adhoc_node(nt, daddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) ieee80211_ref_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_OUTPUT,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "ieee80211_find_txnode: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "[%s] no node, discard frame\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_macaddr_sprintf(daddr));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Remove a node from the node database entries and free memory
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * associated with the node. The node table lock is acquired by
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the caller.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_free_node_locked(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = in->in_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt = in->in_table;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int32_t hash;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (nt != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc hash = ieee80211_node_hash(in->in_macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_remove(&nt->nt_hash[hash], in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_remove(&nt->nt_node, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_node_free(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Remove a node from the node database entries and free any
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * memory associated with the node.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This method can be overridden in ieee80211_attach()
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_free_node(ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt = in->in_table;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (nt != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_node_decref_nv(in) == 0)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node_locked(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (nt != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Reclaim a node. If this is the last reference count then
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * do the normal free work. Otherwise remove it from the node
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * table and mark it gone by clearing the back-reference.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_reclaim(ieee80211_node_table_t *nt, ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int32_t hash;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK_ASSERT(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "node_reclaim: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx " remove %p<%s> from %s table, refcnt %d\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx in, ieee80211_macaddr_sprintf(in->in_macaddr), nt->nt_name,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_node_refcnt(in));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_node_decref_nv(in) != 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Clear any entry in the unicast key mapping table.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * We need to do it here so rx lookups don't find it
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * in the mapping table even if it's not in the hash
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * table. We cannot depend on the mapping table entry
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * being cleared because the node may not be free'd.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc hash = ieee80211_node_hash(in->in_macaddr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_remove(&nt->nt_hash[hash], in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_remove(&nt->nt_node, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_table = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node_locked(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Iterate through the node list and reclaim all node in the node table.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The node table lock is acquired by the caller
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_free_allnodes_locked(ieee80211_node_table_t *nt)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_free_allnodes_locked(): "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "free all nodes in %s table\n", nt->nt_name);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_head(&nt->nt_node);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_reclaim(nt, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_head(&nt->nt_node);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_reset_erp(nt->nt_ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Iterate through the node list, calling ieee80211_node_reclaim() for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * all nodes associated with the interface.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_free_allnodes(ieee80211_node_table_t *nt)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_allnodes_locked(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Timeout entries in the scan cache. This is the timeout callback
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * function of node table ic_scan which is called when the inactivity
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * timer expires.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_timeout_scan_candidates(ieee80211_node_table_t *nt)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = nt->nt_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ic->ic_bss;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc node_cleanfrag(in); /* Free fragment if not needed */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_timer = IEEE80211_INACT_WAIT;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Timeout inactive stations and do related housekeeping.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Note that we cannot hold the node lock while sending a
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * frame as this would lead to a LOR. Instead we use a
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * generation number to mark nodes that we've scanned and
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * drop the lock and restart a scan if we have to time out
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * a node. Since we are single-threaded by virtue of
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * controlling the inactivity timer we can be sure this will
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * process each node only once.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_timeout_stations(ieee80211_node_table_t *nt)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211com_t *ic = nt->nt_ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint32_t gen;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc boolean_t isadhoc;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK_ASSERT(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS ||
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ic->ic_opmode == IEEE80211_M_AHDEMO);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SCAN_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc gen = ++nt->nt_scangen;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcrestart:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc for (in = list_head(&nt->nt_node); in != NULL;
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx in = list_next(&nt->nt_node, in)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_scangen == gen) /* previously handled */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc continue;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_scangen = gen;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc node_cleanfrag(in); /* free fragment if not needed */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Special case ourself; we may be idle for extended periods
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * of time and regardless reclaiming our state is wrong.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == ic->ic_bss)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc continue;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact--;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_associd != 0 || isadhoc) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Probe the station before time it out. We
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * send a null data frame which may not be
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * uinversally supported by drivers (need it
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * for ps-poll support so it should be...).
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (0 < in->in_inact &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact <= im->im_inact_probe) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "net80211: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "probe station due to inactivity\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) ieee80211_send_nulldata(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto restart;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_inact <= 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "net80211: "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "station timed out due to inact (refcnt %u)\n",
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx ieee80211_node_refcnt(in));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Send a deauthenticate frame and drop the station.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This is somewhat complicated due to reference counts
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and locking. At this point a station will typically
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * have a reference count of 1. ieee80211_node_leave
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * will do a "free" of the node which will drop the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * reference count. But in the meantime a reference
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * wil be held by the deauth frame. The actual reclaim
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * of the node will happen either after the tx is
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * completed or by ieee80211_node_leave.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Separately we must drop the node lock before sending
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * in case the driver takes a lock, as this will result
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * in LOR between the node lock and the driver lock.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_associd != 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SEND_MGMT(ic, in,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_FC0_SUBTYPE_DEAUTH,
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx IEEE80211_REASON_AUTH_EXPIRE);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_leave(ic, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto restart;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SCAN_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_timer = IEEE80211_INACT_WAIT;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Call the user-defined call back function for all nodes in
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the node cache. The callback is invoked with the user-supplied
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * value and a pointer to the current node.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_iterate_nodes(ieee80211_node_table_t *nt, ieee80211_iter_func *f,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc void *arg)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_t *in;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_head(&nt->nt_node);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (in != NULL) {
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx if (in->in_chan == IEEE80211_CHAN_ANYC) {
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx in = list_next(&nt->nt_node, in);
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx continue;
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) ieee80211_ref_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (*f)(arg, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = list_next(&nt->nt_node, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Handle bookkeeping for station deauthentication/disassociation
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * when operating as an ap.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_leave(ieee80211com_t *ic, ieee80211_node_t *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_table_t *nt = in->in_table;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ASSERT(ic->ic_opmode == IEEE80211_M_IBSS);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Remove the node from any table it's recorded in and
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * drop the caller's reference. Removal from the table
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * is important to insure the node is not reprocessed
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * for inactivity.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (nt != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_node_reclaim(nt, in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Initialize a node table with specified name, inactivity timer value
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and callback inactivity timeout function. Associate the node table
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * with interface softc, ic.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_table_init(ieee80211com_t *ic, ieee80211_node_table_t *nt,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc const char *name, int inact, int keyixmax,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc void (*timeout)(ieee80211_node_table_t *))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int i;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_init():"
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "%s table, inact %d\n", name, inact);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_ic = ic;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_name = name;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_timer = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_init = inact;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_timeout = timeout;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_keyixmax = keyixmax;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_scangen = 1;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mutex_init(&nt->nt_scanlock, NULL, MUTEX_DRIVER, NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mutex_init(&nt->nt_nodelock, NULL, MUTEX_DRIVER, NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_create(&nt->nt_node, sizeof (ieee80211_node_t),
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx offsetof(ieee80211_node_t, in_node));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc for (i = 0; i < IEEE80211_NODE_HASHSIZE; i++) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc list_create(&nt->nt_hash[i], sizeof (ieee80211_node_t),
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx offsetof(ieee80211_node_t, in_hash));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Reset a node table. Clean its inactivity timer and call
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_free_allnodes_locked() to free all nodes in the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * node table.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_table_reset(ieee80211_node_table_t *nt)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_reset(): "
239e91abc172c1397b1e94869c5d0e8ab67bfc22hx "%s table\n", nt->nt_name);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nt->nt_inact_timer = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_allnodes_locked(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Destroy a node table. Free all nodes in the node table.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This function is usually called by node detach function.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_node_table_cleanup(ieee80211_node_table_t *nt)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_NODE, "ieee80211_node_table_cleanup(): "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "%s table\n", nt->nt_name);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_allnodes_locked(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(nt);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mutex_destroy(&nt->nt_nodelock);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mutex_destroy(&nt->nt_scanlock);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}