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