ieee80211_node.c revision 172062
1116742Ssam/*-
2116904Ssam * Copyright (c) 2001 Atsushi Onoe
3170360Ssam * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
4116742Ssam * All rights reserved.
5116742Ssam *
6116742Ssam * Redistribution and use in source and binary forms, with or without
7116742Ssam * modification, are permitted provided that the following conditions
8116742Ssam * are met:
9116742Ssam * 1. Redistributions of source code must retain the above copyright
10116904Ssam *    notice, this list of conditions and the following disclaimer.
11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright
12116904Ssam *    notice, this list of conditions and the following disclaimer in the
13116904Ssam *    documentation and/or other materials provided with the distribution.
14116742Ssam *
15116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25116742Ssam */
26116742Ssam
27116742Ssam#include <sys/cdefs.h>
28116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_node.c 172062 2007-09-06 00:04:36Z sam $");
29116742Ssam
30116742Ssam#include <sys/param.h>
31116742Ssam#include <sys/systm.h>
32116742Ssam#include <sys/mbuf.h>
33116742Ssam#include <sys/malloc.h>
34116742Ssam#include <sys/kernel.h>
35138568Ssam
36116742Ssam#include <sys/socket.h>
37116742Ssam
38116742Ssam#include <net/if.h>
39116742Ssam#include <net/if_media.h>
40116742Ssam#include <net/ethernet.h>
41116742Ssam
42116742Ssam#include <net80211/ieee80211_var.h>
43116742Ssam
44116742Ssam#include <net/bpf.h>
45116742Ssam
46147221Ssam/*
47147221Ssam * Association id's are managed with a bit vector.
48147221Ssam */
49147221Ssam#define	IEEE80211_AID_SET(b, w) \
50147221Ssam	((w)[IEEE80211_AID(b) / 32] |= (1 << (IEEE80211_AID(b) % 32)))
51147221Ssam#define	IEEE80211_AID_CLR(b, w) \
52147221Ssam	((w)[IEEE80211_AID(b) / 32] &= ~(1 << (IEEE80211_AID(b) % 32)))
53147221Ssam#define	IEEE80211_AID_ISSET(b, w) \
54147221Ssam	((w)[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32)))
55147221Ssam
56159139Sdds#ifdef IEEE80211_DEBUG_REFCNT
57159139Sdds#define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line
58159139Sdds#else
59159139Sdds#define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__
60159139Sdds#endif
61159139Sdds
62170530Ssamstatic int ieee80211_sta_join1(struct ieee80211_node *);
63170530Ssam
64138568Ssamstatic struct ieee80211_node *node_alloc(struct ieee80211_node_table *);
65138568Ssamstatic void node_cleanup(struct ieee80211_node *);
66138568Ssamstatic void node_free(struct ieee80211_node *);
67170530Ssamstatic int8_t node_getrssi(const struct ieee80211_node *);
68170530Ssamstatic void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *);
69116742Ssam
70138568Ssamstatic void ieee80211_setup_node(struct ieee80211_node_table *,
71170530Ssam		struct ieee80211_node *, const uint8_t *);
72138568Ssamstatic void _ieee80211_free_node(struct ieee80211_node *);
73120104Ssam
74138568Ssamstatic void ieee80211_node_table_init(struct ieee80211com *ic,
75148863Ssam	struct ieee80211_node_table *nt, const char *name,
76170530Ssam	int inact, int keymaxix);
77170530Ssamstatic void ieee80211_node_table_reset(struct ieee80211_node_table *);
78138568Ssamstatic void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
79138568Ssam
80127876SsamMALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
81120481Ssam
82116742Ssamvoid
83138568Ssamieee80211_node_attach(struct ieee80211com *ic)
84116742Ssam{
85116742Ssam
86138568Ssam	ic->ic_node_alloc = node_alloc;
87138568Ssam	ic->ic_node_free = node_free;
88138568Ssam	ic->ic_node_cleanup = node_cleanup;
89138568Ssam	ic->ic_node_getrssi = node_getrssi;
90170530Ssam	ic->ic_node_getsignal = node_getsignal;
91138568Ssam
92138568Ssam	/* default station inactivity timer setings */
93138568Ssam	ic->ic_inact_init = IEEE80211_INACT_INIT;
94138568Ssam	ic->ic_inact_auth = IEEE80211_INACT_AUTH;
95138568Ssam	ic->ic_inact_run = IEEE80211_INACT_RUN;
96138568Ssam	ic->ic_inact_probe = IEEE80211_INACT_PROBE;
97138568Ssam
98170530Ssam	callout_init(&ic->ic_inact, CALLOUT_MPSAFE);
99170530Ssam
100148863Ssam	/* NB: driver should override */
101148863Ssam	ic->ic_max_aid = IEEE80211_AID_DEF;
102172062Ssam
103172062Ssam	ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */
104148863Ssam}
105148863Ssam
106148863Ssamvoid
107148863Ssamieee80211_node_lateattach(struct ieee80211com *ic)
108148863Ssam{
109148863Ssam	struct ieee80211_rsnparms *rsn;
110148863Ssam
111148863Ssam	if (ic->ic_max_aid > IEEE80211_AID_MAX)
112138568Ssam		ic->ic_max_aid = IEEE80211_AID_MAX;
113170530Ssam	MALLOC(ic->ic_aid_bitmap, uint32_t *,
114170530Ssam		howmany(ic->ic_max_aid, 32) * sizeof(uint32_t),
115170530Ssam		M_80211_NODE, M_NOWAIT | M_ZERO);
116138568Ssam	if (ic->ic_aid_bitmap == NULL) {
117138568Ssam		/* XXX no way to recover */
118138568Ssam		printf("%s: no memory for AID bitmap!\n", __func__);
119138568Ssam		ic->ic_max_aid = 0;
120138568Ssam	}
121138568Ssam
122148863Ssam	ieee80211_node_table_init(ic, &ic->ic_sta, "station",
123170530Ssam		IEEE80211_INACT_INIT, ic->ic_crypto.cs_max_keyix);
124118887Ssam
125148863Ssam	ieee80211_reset_bss(ic);
126138568Ssam	/*
127138568Ssam	 * Setup "global settings" in the bss node so that
128138568Ssam	 * each new station automatically inherits them.
129138568Ssam	 */
130148863Ssam	rsn = &ic->ic_bss->ni_rsn;
131138568Ssam	/* WEP, TKIP, and AES-CCM are always supported */
132138568Ssam	rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_WEP;
133138568Ssam	rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_TKIP;
134138568Ssam	rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_CCM;
135138568Ssam	if (ic->ic_caps & IEEE80211_C_AES)
136138568Ssam		rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_OCB;
137138568Ssam	if (ic->ic_caps & IEEE80211_C_CKIP)
138138568Ssam		rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_CKIP;
139138568Ssam	/*
140138568Ssam	 * Default unicast cipher to WEP for 802.1x use.  If
141138568Ssam	 * WPA is enabled the management code will set these
142138568Ssam	 * values to reflect.
143138568Ssam	 */
144138568Ssam	rsn->rsn_ucastcipher = IEEE80211_CIPHER_WEP;
145138568Ssam	rsn->rsn_ucastkeylen = 104 / NBBY;
146138568Ssam	/*
147138568Ssam	 * WPA says the multicast cipher is the lowest unicast
148138568Ssam	 * cipher supported.  But we skip WEP which would
149138568Ssam	 * otherwise be used based on this criteria.
150138568Ssam	 */
151138568Ssam	rsn->rsn_mcastcipher = IEEE80211_CIPHER_TKIP;
152138568Ssam	rsn->rsn_mcastkeylen = 128 / NBBY;
153138568Ssam
154138568Ssam	/*
155138568Ssam	 * We support both WPA-PSK and 802.1x; the one used
156138568Ssam	 * is determined by the authentication mode and the
157138568Ssam	 * setting of the PSK state.
158138568Ssam	 */
159138568Ssam	rsn->rsn_keymgmtset = WPA_ASE_8021X_UNSPEC | WPA_ASE_8021X_PSK;
160138568Ssam	rsn->rsn_keymgmt = WPA_ASE_8021X_PSK;
161138568Ssam
162148863Ssam	ic->ic_auth = ieee80211_authenticator_get(ic->ic_bss->ni_authmode);
163116742Ssam}
164116742Ssam
165116742Ssamvoid
166138568Ssamieee80211_node_detach(struct ieee80211com *ic)
167116742Ssam{
168116742Ssam
169138568Ssam	if (ic->ic_bss != NULL) {
170138568Ssam		ieee80211_free_node(ic->ic_bss);
171138568Ssam		ic->ic_bss = NULL;
172138568Ssam	}
173140753Ssam	ieee80211_node_table_cleanup(&ic->ic_sta);
174138568Ssam	if (ic->ic_aid_bitmap != NULL) {
175170530Ssam		FREE(ic->ic_aid_bitmap, M_80211_NODE);
176138568Ssam		ic->ic_aid_bitmap = NULL;
177138568Ssam	}
178116742Ssam}
179116742Ssam
180138568Ssam/*
181138568Ssam * Port authorize/unauthorize interfaces for use by an authenticator.
182138568Ssam */
183138568Ssam
184138568Ssamvoid
185148302Ssamieee80211_node_authorize(struct ieee80211_node *ni)
186138568Ssam{
187148302Ssam	struct ieee80211com *ic = ni->ni_ic;
188148302Ssam
189138568Ssam	ni->ni_flags |= IEEE80211_NODE_AUTH;
190139528Ssam	ni->ni_inact_reload = ic->ic_inact_run;
191172062Ssam	ni->ni_inact = ni->ni_inact_reload;
192138568Ssam}
193138568Ssam
194138568Ssamvoid
195148302Ssamieee80211_node_unauthorize(struct ieee80211_node *ni)
196138568Ssam{
197138568Ssam	ni->ni_flags &= ~IEEE80211_NODE_AUTH;
198172062Ssam	ni->ni_inact_reload = ic->ic_inact_auth;
199172062Ssam	if (ni->ni_inact > ni->ni_inact_reload)
200172062Ssam		ni->ni_inact = ni->ni_inact_reload;
201138568Ssam}
202138568Ssam
203116742Ssam/*
204138568Ssam * Set/change the channel.  The rate set is also updated as
205138568Ssam * to insure a consistent view by drivers.
206138568Ssam */
207153351Ssamstatic void
208170530Ssamieee80211_node_set_chan(struct ieee80211com *ic, struct ieee80211_node *ni)
209138568Ssam{
210170530Ssam	struct ieee80211_channel *chan = ic->ic_bsschan;
211170530Ssam
212170530Ssam#if 0
213170530Ssam	KASSERT(chan != IEEE80211_CHAN_ANYC, ("bss channel not setup"));
214170530Ssam#else
215153351Ssam	if (chan == IEEE80211_CHAN_ANYC)	/* XXX while scanning */
216153351Ssam		chan = ic->ic_curchan;
217170530Ssam#endif
218138568Ssam	ni->ni_chan = chan;
219170530Ssam	if (IEEE80211_IS_CHAN_HT(chan)) {
220170530Ssam		/*
221170530Ssam		 * XXX Gotta be careful here; the rate set returned by
222170530Ssam		 * ieee80211_get_suprates is actually any HT rate
223170530Ssam		 * set so blindly copying it will be bad.  We must
224170530Ssam		 * install the legacy rate est in ni_rates and the
225170530Ssam		 * HT rate set in ni_htrates.
226170530Ssam		 */
227170530Ssam		ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan);
228170530Ssam	}
229165569Ssam	ni->ni_rates = *ieee80211_get_suprates(ic, chan);
230138568Ssam}
231138568Ssam
232138568Ssam/*
233156358Ssam * Probe the curent channel, if allowed, while scanning.
234156358Ssam * If the channel is not marked passive-only then send
235156358Ssam * a probe request immediately.  Otherwise mark state and
236156358Ssam * listen for beacons on the channel; if we receive something
237156358Ssam * then we'll transmit a probe request.
238156358Ssam */
239156358Ssamvoid
240156358Ssamieee80211_probe_curchan(struct ieee80211com *ic, int force)
241156358Ssam{
242156358Ssam	struct ifnet *ifp = ic->ic_ifp;
243156358Ssam
244156358Ssam	if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 || force) {
245156358Ssam		/*
246156358Ssam		 * XXX send both broadcast+directed probe request
247156358Ssam		 */
248156358Ssam		ieee80211_send_probereq(ic->ic_bss,
249156358Ssam			ic->ic_myaddr, ifp->if_broadcastaddr,
250156358Ssam			ifp->if_broadcastaddr,
251170530Ssam			ic->ic_des_ssid[0].ssid, ic->ic_des_ssid[0].len,
252156358Ssam			ic->ic_opt_ie, ic->ic_opt_ie_len);
253156358Ssam	} else
254156358Ssam		ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN;
255156358Ssam}
256156358Ssam
257141658Ssamstatic __inline void
258141658Ssamcopy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss)
259141658Ssam{
260141658Ssam	/* propagate useful state */
261141658Ssam	nbss->ni_authmode = obss->ni_authmode;
262141658Ssam	nbss->ni_txpower = obss->ni_txpower;
263141658Ssam	nbss->ni_vlan = obss->ni_vlan;
264141658Ssam	nbss->ni_rsn = obss->ni_rsn;
265141658Ssam	/* XXX statistics? */
266141658Ssam}
267141658Ssam
268116742Ssamvoid
269116742Ssamieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
270116742Ssam{
271140753Ssam	struct ieee80211_node_table *nt;
272116742Ssam	struct ieee80211_node *ni;
273116742Ssam
274138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
275138568Ssam		"%s: creating ibss\n", __func__);
276138568Ssam
277138568Ssam	/*
278138568Ssam	 * Create the station/neighbor table.  Note that for adhoc
279138568Ssam	 * mode we make the initial inactivity timer longer since
280138568Ssam	 * we create nodes only through discovery and they typically
281138568Ssam	 * are long-lived associations.
282138568Ssam	 */
283140753Ssam	nt = &ic->ic_sta;
284140753Ssam	IEEE80211_NODE_LOCK(nt);
285140753Ssam	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
286140753Ssam		nt->nt_name = "station";
287140753Ssam		nt->nt_inact_init = ic->ic_inact_init;
288140753Ssam	} else {
289140753Ssam		nt->nt_name = "neighbor";
290140753Ssam		nt->nt_inact_init = ic->ic_inact_run;
291140753Ssam	}
292140753Ssam	IEEE80211_NODE_UNLOCK(nt);
293140753Ssam
294148863Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr);
295140753Ssam	if (ni == NULL) {
296140753Ssam		/* XXX recovery? */
297138568Ssam		return;
298138568Ssam	}
299116742Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
300170530Ssam	ni->ni_esslen = ic->ic_des_ssid[0].len;
301170530Ssam	memcpy(ni->ni_essid, ic->ic_des_ssid[0].ssid, ni->ni_esslen);
302170530Ssam	if (ic->ic_bss != NULL)
303170530Ssam		copy_bss(ni, ic->ic_bss);
304148843Ssam	ni->ni_intval = ic->ic_bintval;
305138568Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY)
306116742Ssam		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
307116742Ssam	if (ic->ic_phytype == IEEE80211_T_FH) {
308116742Ssam		ni->ni_fhdwell = 200;	/* XXX */
309116742Ssam		ni->ni_fhindex = 1;
310116742Ssam	}
311138568Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
312138568Ssam		ic->ic_flags |= IEEE80211_F_SIBSS;
313138568Ssam		ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS;	/* XXX */
314143300Ssam		if (ic->ic_flags & IEEE80211_F_DESBSSID)
315143300Ssam			IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
316167282Ssam		else {
317167282Ssam			get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN);
318167282Ssam			/* clear group bit, add local bit */
319167282Ssam			ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02;
320167282Ssam		}
321153403Ssam	} else if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
322153403Ssam		if (ic->ic_flags & IEEE80211_F_DESBSSID)
323153403Ssam			IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
324153403Ssam		else
325153403Ssam			memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
326138568Ssam	}
327138568Ssam	/*
328138568Ssam	 * Fix the channel and related attributes.
329138568Ssam	 */
330170530Ssam	ic->ic_bsschan = chan;
331170530Ssam	ieee80211_node_set_chan(ic, ni);
332170530Ssam	ic->ic_curmode = ieee80211_chan2mode(chan);
333138568Ssam	/*
334138568Ssam	 * Do mode-specific rate setup.
335138568Ssam	 */
336170530Ssam	if (IEEE80211_IS_CHAN_FULL(chan)) {
337170530Ssam		if (IEEE80211_IS_CHAN_ANYG(chan)) {
338170530Ssam			/*
339170530Ssam			 * Use a mixed 11b/11g rate set.
340170530Ssam			 */
341170530Ssam			ieee80211_set11gbasicrates(&ni->ni_rates,
342170530Ssam				IEEE80211_MODE_11G);
343170530Ssam		} else if (IEEE80211_IS_CHAN_B(chan)) {
344170530Ssam			/*
345170530Ssam			 * Force pure 11b rate set.
346170530Ssam			 */
347170530Ssam			ieee80211_set11gbasicrates(&ni->ni_rates,
348170530Ssam				IEEE80211_MODE_11B);
349170530Ssam		}
350170530Ssam	}
351138568Ssam
352170530Ssam	(void) ieee80211_sta_join1(ieee80211_ref_node(ni));
353116742Ssam}
354116742Ssam
355170530Ssam/*
356170530Ssam * Reset bss state on transition to the INIT state.
357170530Ssam * Clear any stations from the table (they have been
358170530Ssam * deauth'd) and reset the bss node (clears key, rate
359170530Ssam * etc. state).
360170530Ssam */
361138568Ssamvoid
362138568Ssamieee80211_reset_bss(struct ieee80211com *ic)
363138568Ssam{
364138568Ssam	struct ieee80211_node *ni, *obss;
365138568Ssam
366170530Ssam	callout_drain(&ic->ic_inact);
367140753Ssam	ieee80211_node_table_reset(&ic->ic_sta);
368170530Ssam	ieee80211_reset_erp(ic);
369140753Ssam
370170530Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr);
371138568Ssam	KASSERT(ni != NULL, ("unable to setup inital BSS node"));
372138568Ssam	obss = ic->ic_bss;
373138568Ssam	ic->ic_bss = ieee80211_ref_node(ni);
374141658Ssam	if (obss != NULL) {
375141658Ssam		copy_bss(ni, obss);
376148843Ssam		ni->ni_intval = ic->ic_bintval;
377138568Ssam		ieee80211_free_node(obss);
378141658Ssam	}
379138568Ssam}
380138568Ssam
381170530Ssamstatic int
382170530Ssammatch_ssid(const struct ieee80211_node *ni,
383170530Ssam	int nssid, const struct ieee80211_scan_ssid ssids[])
384170530Ssam{
385170530Ssam	int i;
386148432Ssam
387170530Ssam	for (i = 0; i < nssid; i++) {
388170530Ssam		if (ni->ni_esslen == ssids[i].len &&
389170530Ssam		     memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0)
390170530Ssam			return 1;
391170530Ssam	}
392170530Ssam	return 0;
393170530Ssam}
394170530Ssam
395170530Ssam/*
396170530Ssam * Test a node for suitability/compatibility.
397170530Ssam */
398127767Ssamstatic int
399170530Ssamcheck_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
400127767Ssam{
401170530Ssam        uint8_t rate;
402170530Ssam
403170530Ssam	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
404170530Ssam		return 0;
405170530Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
406170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
407170530Ssam			return 0;
408170530Ssam	} else {
409170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
410170530Ssam			return 0;
411170530Ssam	}
412170530Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
413170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
414170530Ssam			return 0;
415170530Ssam	} else {
416170530Ssam		/* XXX does this mean privacy is supported or required? */
417170530Ssam		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
418170530Ssam			return 0;
419170530Ssam	}
420170530Ssam	rate = ieee80211_fix_rate(ni, &ni->ni_rates,
421170530Ssam	    IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
422170530Ssam	if (rate & IEEE80211_RATE_BASIC)
423170530Ssam		return 0;
424170530Ssam	if (ic->ic_des_nssid != 0 &&
425170530Ssam	    !match_ssid(ni, ic->ic_des_nssid, ic->ic_des_ssid))
426170530Ssam		return 0;
427170530Ssam	if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
428170530Ssam	    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
429170530Ssam		return 0;
430170530Ssam	return 1;
431170530Ssam}
432170530Ssam
433170530Ssam#ifdef IEEE80211_DEBUG
434170530Ssam/*
435170530Ssam * Display node suitability/compatibility.
436170530Ssam */
437170530Ssamstatic void
438170530Ssamcheck_bss_debug(struct ieee80211com *ic, struct ieee80211_node *ni)
439170530Ssam{
440170530Ssam        uint8_t rate;
441127767Ssam        int fail;
442127767Ssam
443127767Ssam	fail = 0;
444127767Ssam	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
445127767Ssam		fail |= 0x01;
446127767Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
447127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
448127767Ssam			fail |= 0x02;
449127767Ssam	} else {
450127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
451127767Ssam			fail |= 0x02;
452127767Ssam	}
453138568Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
454127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
455127767Ssam			fail |= 0x04;
456127767Ssam	} else {
457127767Ssam		/* XXX does this mean privacy is supported or required? */
458127767Ssam		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
459127767Ssam			fail |= 0x04;
460127767Ssam	}
461167442Ssam	rate = ieee80211_fix_rate(ni, &ni->ni_rates,
462165887Ssam	     IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
463127767Ssam	if (rate & IEEE80211_RATE_BASIC)
464127767Ssam		fail |= 0x08;
465170530Ssam	if (ic->ic_des_nssid != 0 &&
466170530Ssam	    !match_ssid(ni, ic->ic_des_nssid, ic->ic_des_ssid))
467127767Ssam		fail |= 0x10;
468127767Ssam	if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
469127767Ssam	    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
470127767Ssam		fail |= 0x20;
471127767Ssam
472170530Ssam	printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr));
473170530Ssam	printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' ');
474170530Ssam	printf(" %3d%c",
475170530Ssam	    ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' ');
476170530Ssam	printf(" %+4d", ni->ni_rssi);
477170530Ssam	printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
478170530Ssam	    fail & 0x08 ? '!' : ' ');
479170530Ssam	printf(" %4s%c",
480170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
481170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
482170530Ssam	    "????",
483170530Ssam	    fail & 0x02 ? '!' : ' ');
484170530Ssam	printf(" %3s%c ",
485170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?  "wep" : "no",
486170530Ssam	    fail & 0x04 ? '!' : ' ');
487170530Ssam	ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
488170530Ssam	printf("%s\n", fail & 0x10 ? "!" : "");
489138568Ssam}
490170530Ssam#endif /* IEEE80211_DEBUG */
491138568Ssam
492138568Ssam/*
493138568Ssam * Handle 802.11 ad hoc network merge.  The
494138568Ssam * convention, set by the Wireless Ethernet Compatibility Alliance
495138568Ssam * (WECA), is that an 802.11 station will change its BSSID to match
496138568Ssam * the "oldest" 802.11 ad hoc network, on the same channel, that
497138568Ssam * has the station's desired SSID.  The "oldest" 802.11 network
498138568Ssam * sends beacons with the greatest TSF timestamp.
499138568Ssam *
500138568Ssam * The caller is assumed to validate TSF's before attempting a merge.
501138568Ssam *
502138568Ssam * Return !0 if the BSSID changed, 0 otherwise.
503138568Ssam */
504138568Ssamint
505148306Ssamieee80211_ibss_merge(struct ieee80211_node *ni)
506138568Ssam{
507148306Ssam	struct ieee80211com *ic = ni->ni_ic;
508138568Ssam
509140453Ssam	if (ni == ic->ic_bss ||
510140453Ssam	    IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
511138568Ssam		/* unchanged, nothing to do */
512138568Ssam		return 0;
513138568Ssam	}
514170530Ssam	if (!check_bss(ic, ni)) {
515170530Ssam		/* capabilities mismatch */
516138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
517138568Ssam		    "%s: merge failed, capabilities mismatch\n", __func__);
518170530Ssam#ifdef IEEE80211_DEBUG
519170530Ssam		if (ieee80211_msg_assoc(ic))
520170530Ssam			check_bss_debug(ic, ni);
521170530Ssam#endif
522138568Ssam		ic->ic_stats.is_ibss_capmismatch++;
523138568Ssam		return 0;
524138568Ssam	}
525138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
526138568Ssam		"%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
527138568Ssam		ether_sprintf(ni->ni_bssid),
528138568Ssam		ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
529138568Ssam		ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
530138568Ssam		ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
531138568Ssam	);
532170530Ssam	return ieee80211_sta_join1(ieee80211_ref_node(ni));
533138568Ssam}
534138568Ssam
535138568Ssam/*
536138568Ssam * Join the specified IBSS/BSS network.  The node is assumed to
537138568Ssam * be passed in with a held reference.
538138568Ssam */
539170530Ssamstatic int
540170530Ssamieee80211_sta_join1(struct ieee80211_node *selbs)
541138568Ssam{
542170530Ssam	struct ieee80211com *ic = selbs->ni_ic;
543138568Ssam	struct ieee80211_node *obss;
544170530Ssam	int canreassoc;
545138568Ssam
546116742Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
547140753Ssam		struct ieee80211_node_table *nt;
548138568Ssam		/*
549140753Ssam		 * Fillin the neighbor table; it will already
550139521Ssam		 * exist if we are simply switching mastership.
551140753Ssam		 * XXX ic_sta always setup so this is unnecessary?
552127772Ssam		 */
553140753Ssam		nt = &ic->ic_sta;
554140753Ssam		IEEE80211_NODE_LOCK(nt);
555140753Ssam		nt->nt_name = "neighbor";
556140753Ssam		nt->nt_inact_init = ic->ic_inact_run;
557140753Ssam		IEEE80211_NODE_UNLOCK(nt);
558138568Ssam	}
559138568Ssam
560138568Ssam	/*
561138568Ssam	 * Committed to selbs, setup state.
562138568Ssam	 */
563138568Ssam	obss = ic->ic_bss;
564170530Ssam	/*
565170530Ssam	 * Check if old+new node have the same address in which
566170530Ssam	 * case we can reassociate when operating in sta mode.
567170530Ssam	 */
568170530Ssam	canreassoc = (obss != NULL &&
569170530Ssam		ic->ic_state == IEEE80211_S_RUN &&
570170530Ssam		IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr));
571140753Ssam	ic->ic_bss = selbs;		/* NB: caller assumed to bump refcnt */
572153352Ssam	if (obss != NULL) {
573153352Ssam		copy_bss(selbs, obss);
574138568Ssam		ieee80211_free_node(obss);
575153352Ssam	}
576165887Ssam
577138568Ssam	/*
578165887Ssam	 * Delete unusable rates; we've already checked
579165887Ssam	 * that the negotiated rate set is acceptable.
580165887Ssam	 */
581167442Ssam	ieee80211_fix_rate(ic->ic_bss, &ic->ic_bss->ni_rates,
582167442Ssam		IEEE80211_F_DODEL | IEEE80211_F_JOIN);
583165887Ssam
584170530Ssam	ic->ic_bsschan = selbs->ni_chan;
585170530Ssam	ic->ic_curchan = ic->ic_bsschan;
586170530Ssam	ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
587170530Ssam	ic->ic_set_channel(ic);
588165887Ssam	/*
589138568Ssam	 * Set the erp state (mostly the slot time) to deal with
590138568Ssam	 * the auto-select case; this should be redundant if the
591138568Ssam	 * mode is locked.
592138568Ssam	 */
593138568Ssam	ieee80211_reset_erp(ic);
594138568Ssam	ieee80211_wme_initparams(ic);
595140753Ssam
596170530Ssam	if (ic->ic_opmode == IEEE80211_M_STA) {
597170530Ssam		if (canreassoc) {
598170530Ssam			/* Reassociate */
599170530Ssam			ieee80211_new_state(ic, IEEE80211_S_ASSOC, 1);
600170530Ssam		} else {
601170530Ssam			/*
602170530Ssam			 * Act as if we received a DEAUTH frame in case we
603170530Ssam			 * are invoked from the RUN state.  This will cause
604170530Ssam			 * us to try to re-authenticate if we are operating
605170530Ssam			 * as a station.
606170530Ssam			 */
607170530Ssam			ieee80211_new_state(ic, IEEE80211_S_AUTH,
608170530Ssam				IEEE80211_FC0_SUBTYPE_DEAUTH);
609170530Ssam		}
610170530Ssam	} else
611117811Ssam		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
612138568Ssam	return 1;
613116742Ssam}
614116742Ssam
615170530Ssamint
616170530Ssamieee80211_sta_join(struct ieee80211com *ic,
617170530Ssam	const struct ieee80211_scan_entry *se)
618170530Ssam{
619170530Ssam	struct ieee80211_node *ni;
620170530Ssam
621170530Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, se->se_macaddr);
622170530Ssam	if (ni == NULL) {
623170530Ssam		/* XXX msg */
624170530Ssam		return 0;
625170530Ssam	}
626170530Ssam	/*
627170530Ssam	 * Expand scan state into node's format.
628170530Ssam	 * XXX may not need all this stuff
629170530Ssam	 */
630170530Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid);
631170530Ssam	ni->ni_esslen = se->se_ssid[1];
632170530Ssam	memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen);
633170530Ssam	ni->ni_rstamp = se->se_rstamp;
634170530Ssam	ni->ni_tstamp.tsf = se->se_tstamp.tsf;
635170530Ssam	ni->ni_intval = se->se_intval;
636170530Ssam	ni->ni_capinfo = se->se_capinfo;
637170530Ssam	/* XXX shift to 11n channel if htinfo present */
638170530Ssam	ni->ni_chan = se->se_chan;
639170530Ssam	ni->ni_timoff = se->se_timoff;
640170530Ssam	ni->ni_fhdwell = se->se_fhdwell;
641170530Ssam	ni->ni_fhindex = se->se_fhindex;
642170530Ssam	ni->ni_erp = se->se_erp;
643170530Ssam	ni->ni_rssi = se->se_rssi;
644170530Ssam	ni->ni_noise = se->se_noise;
645170530Ssam	if (se->se_htcap_ie != NULL)
646170530Ssam		ieee80211_ht_node_init(ni, se->se_htcap_ie);
647170530Ssam	if (se->se_htinfo_ie != NULL)
648170530Ssam		ieee80211_parse_htinfo(ni, se->se_htinfo_ie);
649170530Ssam	if (se->se_wpa_ie != NULL)
650170530Ssam		ieee80211_saveie(&ni->ni_wpa_ie, se->se_wpa_ie);
651170530Ssam	if (se->se_rsn_ie != NULL)
652170530Ssam		ieee80211_saveie(&ni->ni_rsn_ie, se->se_rsn_ie);
653170530Ssam	if (se->se_wme_ie != NULL)
654170530Ssam		ieee80211_saveie(&ni->ni_wme_ie, se->se_wme_ie);
655170530Ssam	if (se->se_ath_ie != NULL)
656170530Ssam		ieee80211_saveath(ni, se->se_ath_ie);
657170530Ssam
658170530Ssam	ic->ic_dtim_period = se->se_dtimperiod;
659170530Ssam	ic->ic_dtim_count = 0;
660170530Ssam
661170530Ssam	/* NB: must be after ni_chan is setup */
662170530Ssam	ieee80211_setup_rates(ni, se->se_rates, se->se_xrates,
663170530Ssam		IEEE80211_F_DOSORT);
664170530Ssam	if (se->se_htcap_ie != NULL)
665170530Ssam		ieee80211_setup_htrates(ni, se->se_htcap_ie, IEEE80211_F_JOIN);
666170530Ssam	if (se->se_htinfo_ie != NULL)
667170530Ssam		ieee80211_setup_basic_htrates(ni, se->se_htinfo_ie);
668170530Ssam
669170530Ssam	return ieee80211_sta_join1(ieee80211_ref_node(ni));
670170530Ssam}
671170530Ssam
672138568Ssam/*
673138568Ssam * Leave the specified IBSS/BSS network.  The node is assumed to
674138568Ssam * be passed in with a held reference.
675138568Ssam */
676138568Ssamvoid
677138568Ssamieee80211_sta_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
678138568Ssam{
679138568Ssam	ic->ic_node_cleanup(ni);
680138568Ssam	ieee80211_notify_node_leave(ic, ni);
681138568Ssam}
682138568Ssam
683116742Ssamstatic struct ieee80211_node *
684138568Ssamnode_alloc(struct ieee80211_node_table *nt)
685116742Ssam{
686127768Ssam	struct ieee80211_node *ni;
687138568Ssam
688127768Ssam	MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node),
689127768Ssam		M_80211_NODE, M_NOWAIT | M_ZERO);
690127768Ssam	return ni;
691116742Ssam}
692116742Ssam
693138568Ssam/*
694138568Ssam * Reclaim any resources in a node and reset any critical
695138568Ssam * state.  Typically nodes are free'd immediately after,
696138568Ssam * but in some cases the storage may be reused so we need
697138568Ssam * to insure consistent state (should probably fix that).
698138568Ssam */
699116742Ssamstatic void
700138568Ssamnode_cleanup(struct ieee80211_node *ni)
701116742Ssam{
702138568Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
703138568Ssam	struct ieee80211com *ic = ni->ni_ic;
704170530Ssam	int i;
705138568Ssam
706138568Ssam	/* NB: preserve ni_table */
707138568Ssam	if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) {
708138568Ssam		ic->ic_ps_sta--;
709138568Ssam		ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
710138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
711138568Ssam		    "[%s] power save mode off, %u sta's in ps mode\n",
712138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_ps_sta);
713138568Ssam	}
714147788Ssam	/*
715147788Ssam	 * Clear AREF flag that marks the authorization refcnt bump
716147788Ssam	 * has happened.  This is probably not needed as the node
717147788Ssam	 * should always be removed from the table so not found but
718147788Ssam	 * do it just in case.
719147788Ssam	 */
720147788Ssam	ni->ni_flags &= ~IEEE80211_NODE_AREF;
721138568Ssam
722138568Ssam	/*
723138568Ssam	 * Drain power save queue and, if needed, clear TIM.
724138568Ssam	 */
725170530Ssam	if (ieee80211_node_saveq_drain(ni) != 0 && ic->ic_set_tim != NULL)
726148304Ssam		ic->ic_set_tim(ni, 0);
727138568Ssam
728138568Ssam	ni->ni_associd = 0;
729138568Ssam	if (ni->ni_challenge != NULL) {
730170530Ssam		FREE(ni->ni_challenge, M_80211_NODE);
731138568Ssam		ni->ni_challenge = NULL;
732138568Ssam	}
733138568Ssam	/*
734138568Ssam	 * Preserve SSID, WPA, and WME ie's so the bss node is
735138568Ssam	 * reusable during a re-auth/re-assoc state transition.
736138568Ssam	 * If we remove these data they will not be recreated
737138568Ssam	 * because they come from a probe-response or beacon frame
738138568Ssam	 * which cannot be expected prior to the association-response.
739138568Ssam	 * This should not be an issue when operating in other modes
740138568Ssam	 * as stations leaving always go through a full state transition
741138568Ssam	 * which will rebuild this state.
742138568Ssam	 *
743138568Ssam	 * XXX does this leave us open to inheriting old state?
744138568Ssam	 */
745138568Ssam	for (i = 0; i < N(ni->ni_rxfrag); i++)
746138568Ssam		if (ni->ni_rxfrag[i] != NULL) {
747138568Ssam			m_freem(ni->ni_rxfrag[i]);
748138568Ssam			ni->ni_rxfrag[i] = NULL;
749138568Ssam		}
750148863Ssam	/*
751148863Ssam	 * Must be careful here to remove any key map entry w/o a LOR.
752148863Ssam	 */
753148863Ssam	ieee80211_node_delucastkey(ni);
754138568Ssam#undef N
755116742Ssam}
756116742Ssam
757116742Ssamstatic void
758138568Ssamnode_free(struct ieee80211_node *ni)
759116742Ssam{
760138568Ssam	struct ieee80211com *ic = ni->ni_ic;
761138568Ssam
762138568Ssam	ic->ic_node_cleanup(ni);
763138568Ssam	if (ni->ni_wpa_ie != NULL)
764170530Ssam		FREE(ni->ni_wpa_ie, M_80211_NODE);
765170530Ssam	if (ni->ni_rsn_ie != NULL)
766170530Ssam		FREE(ni->ni_rsn_ie, M_80211_NODE);
767138568Ssam	if (ni->ni_wme_ie != NULL)
768170530Ssam		FREE(ni->ni_wme_ie, M_80211_NODE);
769170530Ssam	if (ni->ni_ath_ie != NULL)
770170530Ssam		FREE(ni->ni_ath_ie, M_80211_NODE);
771138568Ssam	IEEE80211_NODE_SAVEQ_DESTROY(ni);
772138568Ssam	FREE(ni, M_80211_NODE);
773116742Ssam}
774116742Ssam
775170530Ssamstatic int8_t
776138568Ssamnode_getrssi(const struct ieee80211_node *ni)
777120104Ssam{
778120104Ssam	return ni->ni_rssi;
779120104Ssam}
780120104Ssam
781116742Ssamstatic void
782170530Ssamnode_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
783170530Ssam{
784170530Ssam	*rssi = ni->ni_rssi;
785170530Ssam	*noise = ni->ni_noise;
786170530Ssam}
787170530Ssam
788170530Ssamstatic void
789138568Ssamieee80211_setup_node(struct ieee80211_node_table *nt,
790170530Ssam	struct ieee80211_node *ni, const uint8_t *macaddr)
791116742Ssam{
792138568Ssam	struct ieee80211com *ic = nt->nt_ic;
793116742Ssam	int hash;
794116742Ssam
795138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
796140766Ssam		"%s %p<%s> in %s table\n", __func__, ni,
797138568Ssam		ether_sprintf(macaddr), nt->nt_name);
798138568Ssam
799116742Ssam	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
800116742Ssam	hash = IEEE80211_NODE_HASH(macaddr);
801138568Ssam	ieee80211_node_initref(ni);		/* mark referenced */
802138568Ssam	ni->ni_chan = IEEE80211_CHAN_ANYC;
803138568Ssam	ni->ni_authmode = IEEE80211_AUTH_OPEN;
804138568Ssam	ni->ni_txpower = ic->ic_txpowlimit;	/* max power */
805138568Ssam	ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE);
806139528Ssam	ni->ni_inact_reload = nt->nt_inact_init;
807139528Ssam	ni->ni_inact = ni->ni_inact_reload;
808170530Ssam	ni->ni_ath_defkeyix = 0x7fff;
809138568Ssam	IEEE80211_NODE_SAVEQ_INIT(ni, "unknown");
810138568Ssam
811138568Ssam	IEEE80211_NODE_LOCK(nt);
812138568Ssam	TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
813138568Ssam	LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
814138568Ssam	ni->ni_table = nt;
815138568Ssam	ni->ni_ic = ic;
816138568Ssam	IEEE80211_NODE_UNLOCK(nt);
817116742Ssam}
818116742Ssam
819116742Ssamstruct ieee80211_node *
820170530Ssamieee80211_alloc_node(struct ieee80211_node_table *nt, const uint8_t *macaddr)
821116742Ssam{
822138568Ssam	struct ieee80211com *ic = nt->nt_ic;
823138568Ssam	struct ieee80211_node *ni;
824138568Ssam
825138568Ssam	ni = ic->ic_node_alloc(nt);
826116742Ssam	if (ni != NULL)
827138568Ssam		ieee80211_setup_node(nt, ni, macaddr);
828127769Ssam	else
829127769Ssam		ic->ic_stats.is_rx_nodealloc++;
830116742Ssam	return ni;
831116742Ssam}
832116742Ssam
833148777Ssam/*
834148777Ssam * Craft a temporary node suitable for sending a management frame
835148777Ssam * to the specified station.  We craft only as much state as we
836148777Ssam * need to do the work since the node will be immediately reclaimed
837148777Ssam * once the send completes.
838148777Ssam */
839116742Ssamstruct ieee80211_node *
840170530Ssamieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr)
841148777Ssam{
842148777Ssam	struct ieee80211_node *ni;
843148777Ssam
844148777Ssam	ni = ic->ic_node_alloc(&ic->ic_sta);
845148777Ssam	if (ni != NULL) {
846148777Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
847148777Ssam			"%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr));
848148777Ssam
849148777Ssam		IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
850148777Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
851148777Ssam		ieee80211_node_initref(ni);		/* mark referenced */
852148777Ssam		ni->ni_txpower = ic->ic_bss->ni_txpower;
853148777Ssam		/* NB: required by ieee80211_fix_rate */
854170530Ssam		ieee80211_node_set_chan(ic, ni);
855148777Ssam		ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey,
856148777Ssam			IEEE80211_KEYIX_NONE);
857148777Ssam		/* XXX optimize away */
858148777Ssam		IEEE80211_NODE_SAVEQ_INIT(ni, "unknown");
859148777Ssam
860148777Ssam		ni->ni_table = NULL;		/* NB: pedantic */
861148777Ssam		ni->ni_ic = ic;
862148777Ssam	} else {
863148777Ssam		/* XXX msg */
864148777Ssam		ic->ic_stats.is_rx_nodealloc++;
865148777Ssam	}
866148777Ssam	return ni;
867148777Ssam}
868148777Ssam
869148777Ssamstruct ieee80211_node *
870170530Ssamieee80211_dup_bss(struct ieee80211_node_table *nt, const uint8_t *macaddr)
871116742Ssam{
872138568Ssam	struct ieee80211com *ic = nt->nt_ic;
873138568Ssam	struct ieee80211_node *ni;
874138568Ssam
875138568Ssam	ni = ic->ic_node_alloc(nt);
876116742Ssam	if (ni != NULL) {
877138568Ssam		ieee80211_setup_node(nt, ni, macaddr);
878127770Ssam		/*
879127770Ssam		 * Inherit from ic_bss.
880127770Ssam		 */
881138568Ssam		ni->ni_authmode = ic->ic_bss->ni_authmode;
882138568Ssam		ni->ni_txpower = ic->ic_bss->ni_txpower;
883138568Ssam		ni->ni_vlan = ic->ic_bss->ni_vlan;	/* XXX?? */
884127770Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
885170530Ssam		ieee80211_node_set_chan(ic, ni);
886138568Ssam		ni->ni_rsn = ic->ic_bss->ni_rsn;
887127770Ssam	} else
888127770Ssam		ic->ic_stats.is_rx_nodealloc++;
889116742Ssam	return ni;
890116742Ssam}
891116742Ssam
892127772Ssamstatic struct ieee80211_node *
893138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
894138568Ssam_ieee80211_find_node_debug(struct ieee80211_node_table *nt,
895170530Ssam	const uint8_t *macaddr, const char *func, int line)
896138568Ssam#else
897138568Ssam_ieee80211_find_node(struct ieee80211_node_table *nt,
898170530Ssam	const uint8_t *macaddr)
899138568Ssam#endif
900116742Ssam{
901116742Ssam	struct ieee80211_node *ni;
902116742Ssam	int hash;
903116742Ssam
904138568Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
905127772Ssam
906116742Ssam	hash = IEEE80211_NODE_HASH(macaddr);
907138568Ssam	LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
908116742Ssam		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
909138568Ssam			ieee80211_ref_node(ni);	/* mark referenced */
910138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
911138568Ssam			IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
912140766Ssam			    "%s (%s:%u) %p<%s> refcnt %d\n", __func__,
913140766Ssam			    func, line,
914140766Ssam			    ni, ether_sprintf(ni->ni_macaddr),
915140766Ssam			    ieee80211_node_refcnt(ni));
916138568Ssam#endif
917127772Ssam			return ni;
918116742Ssam		}
919116742Ssam	}
920127772Ssam	return NULL;
921127772Ssam}
922138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
923138568Ssam#define	_ieee80211_find_node(nt, mac) \
924138568Ssam	_ieee80211_find_node_debug(nt, mac, func, line)
925138568Ssam#endif
926127772Ssam
927127772Ssamstruct ieee80211_node *
928138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
929138568Ssamieee80211_find_node_debug(struct ieee80211_node_table *nt,
930170530Ssam	const uint8_t *macaddr, const char *func, int line)
931138568Ssam#else
932170530Ssamieee80211_find_node(struct ieee80211_node_table *nt, const uint8_t *macaddr)
933138568Ssam#endif
934127772Ssam{
935127772Ssam	struct ieee80211_node *ni;
936127772Ssam
937138568Ssam	IEEE80211_NODE_LOCK(nt);
938138568Ssam	ni = _ieee80211_find_node(nt, macaddr);
939138568Ssam	IEEE80211_NODE_UNLOCK(nt);
940116742Ssam	return ni;
941116742Ssam}
942116742Ssam
943116742Ssam/*
944138568Ssam * Fake up a node; this handles node discovery in adhoc mode.
945138568Ssam * Note that for the driver's benefit we we treat this like
946138568Ssam * an association so the driver has an opportunity to setup
947138568Ssam * it's private state.
948138568Ssam */
949138568Ssamstruct ieee80211_node *
950138568Ssamieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt,
951170530Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
952138568Ssam{
953138568Ssam	struct ieee80211com *ic = nt->nt_ic;
954138568Ssam	struct ieee80211_node *ni;
955138568Ssam
956153073Ssam	IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
957153073Ssam	    "%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
958138568Ssam	ni = ieee80211_dup_bss(nt, macaddr);
959138568Ssam	if (ni != NULL) {
960138568Ssam		/* XXX no rate negotiation; just dup */
961138568Ssam		ni->ni_rates = ic->ic_bss->ni_rates;
962139524Ssam		if (ic->ic_newassoc != NULL)
963148307Ssam			ic->ic_newassoc(ni, 1);
964153404Ssam		if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
965153404Ssam			/*
966170530Ssam			 * In adhoc demo mode there are no management
967170530Ssam			 * frames to use to discover neighbor capabilities,
968170530Ssam			 * so blindly propagate the local configuration
969170530Ssam			 * so we can do interesting things (e.g. use
970170530Ssam			 * WME to disable ACK's).
971153404Ssam			 */
972153404Ssam			if (ic->ic_flags & IEEE80211_F_WME)
973153404Ssam				ni->ni_flags |= IEEE80211_NODE_QOS;
974170530Ssam			if (ic->ic_flags & IEEE80211_F_FF)
975170530Ssam				ni->ni_flags |= IEEE80211_NODE_FF;
976153404Ssam		}
977170530Ssam		/* XXX not right for 802.1x/WPA */
978170530Ssam		ieee80211_node_authorize(ni);
979138568Ssam	}
980138568Ssam	return ni;
981138568Ssam}
982138568Ssam
983148936Ssamvoid
984153073Ssamieee80211_init_neighbor(struct ieee80211_node *ni,
985153073Ssam	const struct ieee80211_frame *wh,
986153073Ssam	const struct ieee80211_scanparams *sp)
987153073Ssam{
988153073Ssam	ni->ni_esslen = sp->ssid[1];
989153073Ssam	memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
990153073Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
991153073Ssam	memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp));
992153073Ssam	ni->ni_intval = sp->bintval;
993153073Ssam	ni->ni_capinfo = sp->capinfo;
994153073Ssam	ni->ni_chan = ni->ni_ic->ic_curchan;
995153073Ssam	ni->ni_fhdwell = sp->fhdwell;
996153073Ssam	ni->ni_fhindex = sp->fhindex;
997153073Ssam	ni->ni_erp = sp->erp;
998153073Ssam	ni->ni_timoff = sp->timoff;
999153073Ssam	if (sp->wme != NULL)
1000153073Ssam		ieee80211_saveie(&ni->ni_wme_ie, sp->wme);
1001153073Ssam	if (sp->wpa != NULL)
1002153073Ssam		ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa);
1003170530Ssam	if (sp->rsn != NULL)
1004170530Ssam		ieee80211_saveie(&ni->ni_rsn_ie, sp->rsn);
1005170530Ssam	if (sp->ath != NULL)
1006170530Ssam		ieee80211_saveath(ni, sp->ath);
1007153073Ssam
1008153073Ssam	/* NB: must be after ni_chan is setup */
1009165887Ssam	ieee80211_setup_rates(ni, sp->rates, sp->xrates,
1010165887Ssam		IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1011165887Ssam		IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1012153073Ssam}
1013153073Ssam
1014148936Ssam/*
1015148936Ssam * Do node discovery in adhoc mode on receipt of a beacon
1016148936Ssam * or probe response frame.  Note that for the driver's
1017148936Ssam * benefit we we treat this like an association so the
1018148936Ssam * driver has an opportunity to setup it's private state.
1019148936Ssam */
1020148936Ssamstruct ieee80211_node *
1021148936Ssamieee80211_add_neighbor(struct ieee80211com *ic,
1022148936Ssam	const struct ieee80211_frame *wh,
1023148936Ssam	const struct ieee80211_scanparams *sp)
1024148936Ssam{
1025148936Ssam	struct ieee80211_node *ni;
1026148936Ssam
1027153073Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1028153073Ssam	    "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
1029148936Ssam	ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */
1030148936Ssam	if (ni != NULL) {
1031153073Ssam		ieee80211_init_neighbor(ni, wh, sp);
1032148936Ssam		if (ic->ic_newassoc != NULL)
1033148936Ssam			ic->ic_newassoc(ni, 1);
1034148936Ssam		/* XXX not right for 802.1x/WPA */
1035148936Ssam		ieee80211_node_authorize(ni);
1036148936Ssam	}
1037148936Ssam	return ni;
1038148936Ssam}
1039148936Ssam
1040148863Ssam#define	IS_CTL(wh) \
1041148863Ssam	((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
1042148863Ssam#define	IS_PSPOLL(wh) \
1043148863Ssam	((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
1044170530Ssam#define	IS_BAR(wh) \
1045170530Ssam	((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_BAR)
1046170530Ssam
1047138568Ssam/*
1048138568Ssam * Locate the node for sender, track state, and then pass the
1049138568Ssam * (referenced) node up to the 802.11 layer for its use.  We
1050138568Ssam * are required to pass some node so we fall back to ic_bss
1051138568Ssam * when this frame is from an unknown sender.  The 802.11 layer
1052138568Ssam * knows this means the sender wasn't in the node table and
1053138568Ssam * acts accordingly.
1054138568Ssam */
1055138568Ssamstruct ieee80211_node *
1056138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1057138568Ssamieee80211_find_rxnode_debug(struct ieee80211com *ic,
1058138568Ssam	const struct ieee80211_frame_min *wh, const char *func, int line)
1059138568Ssam#else
1060138568Ssamieee80211_find_rxnode(struct ieee80211com *ic,
1061138568Ssam	const struct ieee80211_frame_min *wh)
1062138568Ssam#endif
1063138568Ssam{
1064138568Ssam	struct ieee80211_node_table *nt;
1065138568Ssam	struct ieee80211_node *ni;
1066138568Ssam
1067138568Ssam	/* XXX check ic_bss first in station mode */
1068138568Ssam	/* XXX 4-address frames? */
1069170530Ssam	nt = &ic->ic_sta;
1070138568Ssam	IEEE80211_NODE_LOCK(nt);
1071170530Ssam	if (IS_CTL(wh) && !IS_PSPOLL(wh) && !IS_BAR(wh) /*&& !IS_RTS(ah)*/)
1072138568Ssam		ni = _ieee80211_find_node(nt, wh->i_addr1);
1073138568Ssam	else
1074138568Ssam		ni = _ieee80211_find_node(nt, wh->i_addr2);
1075148863Ssam	if (ni == NULL)
1076148863Ssam		ni = ieee80211_ref_node(ic->ic_bss);
1077138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1078138568Ssam
1079148863Ssam	return ni;
1080148863Ssam}
1081148863Ssam
1082148863Ssam/*
1083148863Ssam * Like ieee80211_find_rxnode but use the supplied h/w
1084148863Ssam * key index as a hint to locate the node in the key
1085148863Ssam * mapping table.  If an entry is present at the key
1086148863Ssam * index we return it; otherwise do a normal lookup and
1087148863Ssam * update the mapping table if the station has a unicast
1088148863Ssam * key assigned to it.
1089148863Ssam */
1090148863Ssamstruct ieee80211_node *
1091148863Ssam#ifdef IEEE80211_DEBUG_REFCNT
1092148863Ssamieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic,
1093148863Ssam	const struct ieee80211_frame_min *wh, ieee80211_keyix keyix,
1094148863Ssam	const char *func, int line)
1095148863Ssam#else
1096148863Ssamieee80211_find_rxnode_withkey(struct ieee80211com *ic,
1097148863Ssam	const struct ieee80211_frame_min *wh, ieee80211_keyix keyix)
1098148863Ssam#endif
1099148863Ssam{
1100148863Ssam	struct ieee80211_node_table *nt;
1101148863Ssam	struct ieee80211_node *ni;
1102148863Ssam
1103170530Ssam	nt = &ic->ic_sta;
1104148863Ssam	IEEE80211_NODE_LOCK(nt);
1105148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax)
1106148863Ssam		ni = nt->nt_keyixmap[keyix];
1107148863Ssam	else
1108148863Ssam		ni = NULL;
1109148863Ssam	if (ni == NULL) {
1110170530Ssam		if (IS_CTL(wh) && !IS_PSPOLL(wh) && !IS_BAR(wh) /*&& !IS_RTS(ah)*/)
1111148863Ssam			ni = _ieee80211_find_node(nt, wh->i_addr1);
1112148863Ssam		else
1113148863Ssam			ni = _ieee80211_find_node(nt, wh->i_addr2);
1114148863Ssam		if (ni == NULL)
1115148863Ssam			ni = ieee80211_ref_node(ic->ic_bss);
1116148863Ssam		if (nt->nt_keyixmap != NULL) {
1117148863Ssam			/*
1118148863Ssam			 * If the station has a unicast key cache slot
1119148863Ssam			 * assigned update the key->node mapping table.
1120148863Ssam			 */
1121148863Ssam			keyix = ni->ni_ucastkey.wk_rxkeyix;
1122148863Ssam			/* XXX can keyixmap[keyix] != NULL? */
1123148863Ssam			if (keyix < nt->nt_keyixmax &&
1124148863Ssam			    nt->nt_keyixmap[keyix] == NULL) {
1125148863Ssam				IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1126148863Ssam				    "%s: add key map entry %p<%s> refcnt %d\n",
1127148863Ssam				    __func__, ni, ether_sprintf(ni->ni_macaddr),
1128148863Ssam				    ieee80211_node_refcnt(ni)+1);
1129148863Ssam				nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni);
1130148863Ssam			}
1131148863Ssam		}
1132170530Ssam	} else
1133148863Ssam		ieee80211_ref_node(ni);
1134148863Ssam	IEEE80211_NODE_UNLOCK(nt);
1135148863Ssam
1136148863Ssam	return ni;
1137148863Ssam}
1138170530Ssam#undef IS_BAR
1139138568Ssam#undef IS_PSPOLL
1140138568Ssam#undef IS_CTL
1141138568Ssam
1142138568Ssam/*
1143127772Ssam * Return a reference to the appropriate node for sending
1144127772Ssam * a data frame.  This handles node discovery in adhoc networks.
1145127772Ssam */
1146127772Ssamstruct ieee80211_node *
1147138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1148170530Ssamieee80211_find_txnode_debug(struct ieee80211com *ic, const uint8_t *macaddr,
1149138568Ssam	const char *func, int line)
1150138568Ssam#else
1151170530Ssamieee80211_find_txnode(struct ieee80211com *ic, const uint8_t *macaddr)
1152138568Ssam#endif
1153127772Ssam{
1154140753Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1155127772Ssam	struct ieee80211_node *ni;
1156127772Ssam
1157127772Ssam	/*
1158127772Ssam	 * The destination address should be in the node table
1159148863Ssam	 * unless this is a multicast/broadcast frame.  We can
1160148863Ssam	 * also optimize station mode operation, all frames go
1161148863Ssam	 * to the bss node.
1162127772Ssam	 */
1163127772Ssam	/* XXX can't hold lock across dup_bss 'cuz of recursive locking */
1164138568Ssam	IEEE80211_NODE_LOCK(nt);
1165148863Ssam	if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
1166148863Ssam		ni = ieee80211_ref_node(ic->ic_bss);
1167158121Ssam	else {
1168148863Ssam		ni = _ieee80211_find_node(nt, macaddr);
1169158121Ssam		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1170158121Ssam		    (ni != NULL && ni->ni_associd == 0)) {
1171158121Ssam			/*
1172158121Ssam			 * Station is not associated; don't permit the
1173158121Ssam			 * data frame to be sent by returning NULL.  This
1174158121Ssam			 * is kinda a kludge but the least intrusive way
1175158121Ssam			 * to add this check into all drivers.
1176158121Ssam			 */
1177158121Ssam			ieee80211_unref_node(&ni);	/* NB: null's ni */
1178158121Ssam		}
1179158121Ssam	}
1180138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1181138568Ssam
1182138568Ssam	if (ni == NULL) {
1183138568Ssam		if (ic->ic_opmode == IEEE80211_M_IBSS ||
1184140497Ssam		    ic->ic_opmode == IEEE80211_M_AHDEMO) {
1185140497Ssam			/*
1186140497Ssam			 * In adhoc mode cons up a node for the destination.
1187140497Ssam			 * Note that we need an additional reference for the
1188140497Ssam			 * caller to be consistent with _ieee80211_find_node.
1189140497Ssam			 */
1190138568Ssam			ni = ieee80211_fakeup_adhoc_node(nt, macaddr);
1191140497Ssam			if (ni != NULL)
1192140497Ssam				(void) ieee80211_ref_node(ni);
1193140497Ssam		} else {
1194138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
1195138568Ssam				"[%s] no node, discard frame (%s)\n",
1196138568Ssam				ether_sprintf(macaddr), __func__);
1197138568Ssam			ic->ic_stats.is_tx_nonode++;
1198127772Ssam		}
1199127772Ssam	}
1200127772Ssam	return ni;
1201127772Ssam}
1202127772Ssam
1203127772Ssam/*
1204138568Ssam * Like find but search based on the ssid too.
1205138568Ssam */
1206138568Ssamstruct ieee80211_node *
1207138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1208138568Ssamieee80211_find_node_with_ssid_debug(struct ieee80211_node_table *nt,
1209170530Ssam	const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid,
1210138568Ssam	const char *func, int line)
1211138568Ssam#else
1212138568Ssamieee80211_find_node_with_ssid(struct ieee80211_node_table *nt,
1213170530Ssam	const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid)
1214138568Ssam#endif
1215138568Ssam{
1216147118Ssam#define	MATCH_SSID(ni, ssid, ssidlen) \
1217147118Ssam	(ni->ni_esslen == ssidlen && memcmp(ni->ni_essid, ssid, ssidlen) == 0)
1218170530Ssam	static const uint8_t zeromac[IEEE80211_ADDR_LEN];
1219138568Ssam	struct ieee80211_node *ni;
1220138568Ssam	int hash;
1221138568Ssam
1222138568Ssam	IEEE80211_NODE_LOCK(nt);
1223147118Ssam	/*
1224147118Ssam	 * A mac address that is all zero means match only the ssid;
1225147118Ssam	 * otherwise we must match both.
1226147118Ssam	 */
1227147118Ssam	if (IEEE80211_ADDR_EQ(macaddr, zeromac)) {
1228147118Ssam		TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1229147118Ssam			if (MATCH_SSID(ni, ssid, ssidlen))
1230147118Ssam				break;
1231147118Ssam		}
1232147118Ssam	} else {
1233147118Ssam		hash = IEEE80211_NODE_HASH(macaddr);
1234147118Ssam		LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
1235147118Ssam			if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) &&
1236147118Ssam			    MATCH_SSID(ni, ssid, ssidlen))
1237147118Ssam				break;
1238147118Ssam		}
1239147118Ssam	}
1240147118Ssam	if (ni != NULL) {
1241147118Ssam		ieee80211_ref_node(ni);	/* mark referenced */
1242170530Ssam		IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
1243159139Sdds		     REFCNT_LOC, ni, ether_sprintf(ni->ni_macaddr),
1244147118Ssam		     ieee80211_node_refcnt(ni));
1245138568Ssam	}
1246138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1247138568Ssam	return ni;
1248147118Ssam#undef MATCH_SSID
1249138568Ssam}
1250138568Ssam
1251116742Ssamstatic void
1252138568Ssam_ieee80211_free_node(struct ieee80211_node *ni)
1253116742Ssam{
1254138568Ssam	struct ieee80211com *ic = ni->ni_ic;
1255138568Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1256119150Ssam
1257138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1258140766Ssam		"%s %p<%s> in %s table\n", __func__, ni,
1259140766Ssam		ether_sprintf(ni->ni_macaddr),
1260138568Ssam		nt != NULL ? nt->nt_name : "<gone>");
1261138568Ssam
1262138568Ssam	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
1263138568Ssam	if (nt != NULL) {
1264138568Ssam		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
1265138568Ssam		LIST_REMOVE(ni, ni_hash);
1266138568Ssam	}
1267138568Ssam	ic->ic_node_free(ni);
1268116742Ssam}
1269116742Ssam
1270116742Ssamvoid
1271138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1272138568Ssamieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line)
1273138568Ssam#else
1274138568Ssamieee80211_free_node(struct ieee80211_node *ni)
1275138568Ssam#endif
1276116742Ssam{
1277138568Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1278119150Ssam
1279138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1280140454Ssam	IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1281140766Ssam		"%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
1282138568Ssam		 ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1);
1283138568Ssam#endif
1284148863Ssam	if (nt != NULL) {
1285148863Ssam		IEEE80211_NODE_LOCK(nt);
1286148863Ssam		if (ieee80211_node_dectestref(ni)) {
1287148863Ssam			/*
1288148863Ssam			 * Last reference, reclaim state.
1289148863Ssam			 */
1290138568Ssam			_ieee80211_free_node(ni);
1291148863Ssam		} else if (ieee80211_node_refcnt(ni) == 1 &&
1292148863Ssam		    nt->nt_keyixmap != NULL) {
1293148863Ssam			ieee80211_keyix keyix;
1294148863Ssam			/*
1295148863Ssam			 * Check for a last reference in the key mapping table.
1296148863Ssam			 */
1297148863Ssam			keyix = ni->ni_ucastkey.wk_rxkeyix;
1298148863Ssam			if (keyix < nt->nt_keyixmax &&
1299148863Ssam			    nt->nt_keyixmap[keyix] == ni) {
1300148863Ssam				IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1301148863Ssam				    "%s: %p<%s> clear key map entry", __func__,
1302148863Ssam				    ni, ether_sprintf(ni->ni_macaddr));
1303148863Ssam				nt->nt_keyixmap[keyix] = NULL;
1304148863Ssam				ieee80211_node_decref(ni); /* XXX needed? */
1305148863Ssam				_ieee80211_free_node(ni);
1306148863Ssam			}
1307148863Ssam		}
1308148863Ssam		IEEE80211_NODE_UNLOCK(nt);
1309148863Ssam	} else {
1310148863Ssam		if (ieee80211_node_dectestref(ni))
1311138568Ssam			_ieee80211_free_node(ni);
1312116742Ssam	}
1313116742Ssam}
1314116742Ssam
1315138568Ssam/*
1316148863Ssam * Reclaim a unicast key and clear any key cache state.
1317148863Ssam */
1318148863Ssamint
1319148863Ssamieee80211_node_delucastkey(struct ieee80211_node *ni)
1320148863Ssam{
1321148863Ssam	struct ieee80211com *ic = ni->ni_ic;
1322148863Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1323148863Ssam	struct ieee80211_node *nikey;
1324148863Ssam	ieee80211_keyix keyix;
1325148863Ssam	int isowned, status;
1326148863Ssam
1327148863Ssam	/*
1328148863Ssam	 * NB: We must beware of LOR here; deleting the key
1329148863Ssam	 * can cause the crypto layer to block traffic updates
1330148863Ssam	 * which can generate a LOR against the node table lock;
1331148863Ssam	 * grab it here and stash the key index for our use below.
1332148863Ssam	 *
1333148863Ssam	 * Must also beware of recursion on the node table lock.
1334148863Ssam	 * When called from node_cleanup we may already have
1335148863Ssam	 * the node table lock held.  Unfortunately there's no
1336148863Ssam	 * way to separate out this path so we must do this
1337148863Ssam	 * conditionally.
1338148863Ssam	 */
1339148863Ssam	isowned = IEEE80211_NODE_IS_LOCKED(nt);
1340148863Ssam	if (!isowned)
1341148863Ssam		IEEE80211_NODE_LOCK(nt);
1342148863Ssam	keyix = ni->ni_ucastkey.wk_rxkeyix;
1343148863Ssam	status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
1344148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) {
1345148863Ssam		nikey = nt->nt_keyixmap[keyix];
1346148863Ssam		nt->nt_keyixmap[keyix] = NULL;;
1347148863Ssam	} else
1348148863Ssam		nikey = NULL;
1349148863Ssam	if (!isowned)
1350148863Ssam		IEEE80211_NODE_UNLOCK(&ic->ic_sta);
1351148863Ssam
1352148863Ssam	if (nikey != NULL) {
1353148863Ssam		KASSERT(nikey == ni,
1354148863Ssam			("key map out of sync, ni %p nikey %p", ni, nikey));
1355148863Ssam		IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1356148863Ssam			"%s: delete key map entry %p<%s> refcnt %d\n",
1357148863Ssam			__func__, ni, ether_sprintf(ni->ni_macaddr),
1358148863Ssam			ieee80211_node_refcnt(ni)-1);
1359148863Ssam		ieee80211_free_node(ni);
1360148863Ssam	}
1361148863Ssam	return status;
1362148863Ssam}
1363148863Ssam
1364148863Ssam/*
1365138568Ssam * Reclaim a node.  If this is the last reference count then
1366138568Ssam * do the normal free work.  Otherwise remove it from the node
1367138568Ssam * table and mark it gone by clearing the back-reference.
1368138568Ssam */
1369138568Ssamstatic void
1370138568Ssamnode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
1371116742Ssam{
1372148863Ssam	ieee80211_keyix keyix;
1373138568Ssam
1374148863Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
1375148863Ssam
1376140766Ssam	IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1377140766Ssam		"%s: remove %p<%s> from %s table, refcnt %d\n",
1378140766Ssam		__func__, ni, ether_sprintf(ni->ni_macaddr),
1379140766Ssam		nt->nt_name, ieee80211_node_refcnt(ni)-1);
1380148863Ssam	/*
1381148863Ssam	 * Clear any entry in the unicast key mapping table.
1382148863Ssam	 * We need to do it here so rx lookups don't find it
1383148863Ssam	 * in the mapping table even if it's not in the hash
1384148863Ssam	 * table.  We cannot depend on the mapping table entry
1385148863Ssam	 * being cleared because the node may not be free'd.
1386148863Ssam	 */
1387148863Ssam	keyix = ni->ni_ucastkey.wk_rxkeyix;
1388148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
1389148863Ssam	    nt->nt_keyixmap[keyix] == ni) {
1390148863Ssam		IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1391148863Ssam			"%s: %p<%s> clear key map entry\n",
1392148863Ssam			__func__, ni, ether_sprintf(ni->ni_macaddr));
1393148863Ssam		nt->nt_keyixmap[keyix] = NULL;
1394148863Ssam		ieee80211_node_decref(ni);	/* NB: don't need free */
1395148863Ssam	}
1396138568Ssam	if (!ieee80211_node_dectestref(ni)) {
1397138568Ssam		/*
1398138568Ssam		 * Other references are present, just remove the
1399138568Ssam		 * node from the table so it cannot be found.  When
1400138568Ssam		 * the references are dropped storage will be
1401140753Ssam		 * reclaimed.
1402138568Ssam		 */
1403138568Ssam		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
1404138568Ssam		LIST_REMOVE(ni, ni_hash);
1405138568Ssam		ni->ni_table = NULL;		/* clear reference */
1406138568Ssam	} else
1407138568Ssam		_ieee80211_free_node(ni);
1408138568Ssam}
1409138568Ssam
1410138568Ssamstatic void
1411138568Ssamieee80211_free_allnodes_locked(struct ieee80211_node_table *nt)
1412138568Ssam{
1413138568Ssam	struct ieee80211com *ic = nt->nt_ic;
1414116742Ssam	struct ieee80211_node *ni;
1415116742Ssam
1416138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1417138568Ssam		"%s: free all nodes in %s table\n", __func__, nt->nt_name);
1418138568Ssam
1419138568Ssam	while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) {
1420138568Ssam		if (ni->ni_associd != 0) {
1421138568Ssam			if (ic->ic_auth->ia_node_leave != NULL)
1422138568Ssam				ic->ic_auth->ia_node_leave(ic, ni);
1423138568Ssam			IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
1424138568Ssam		}
1425138568Ssam		node_reclaim(nt, ni);
1426138568Ssam	}
1427116742Ssam}
1428116742Ssam
1429120483Ssam/*
1430138568Ssam * Timeout inactive stations and do related housekeeping.
1431138568Ssam * Note that we cannot hold the node lock while sending a
1432138568Ssam * frame as this would lead to a LOR.  Instead we use a
1433138568Ssam * generation number to mark nodes that we've scanned and
1434138568Ssam * drop the lock and restart a scan if we have to time out
1435138568Ssam * a node.  Since we are single-threaded by virtue of
1436120483Ssam * controlling the inactivity timer we can be sure this will
1437120483Ssam * process each node only once.
1438120483Ssam */
1439138568Ssamstatic void
1440138568Ssamieee80211_timeout_stations(struct ieee80211_node_table *nt)
1441116742Ssam{
1442138568Ssam	struct ieee80211com *ic = nt->nt_ic;
1443120483Ssam	struct ieee80211_node *ni;
1444138568Ssam	u_int gen;
1445148320Ssam	int isadhoc;
1446116742Ssam
1447148320Ssam	isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS ||
1448148320Ssam		   ic->ic_opmode == IEEE80211_M_AHDEMO);
1449138568Ssam	IEEE80211_SCAN_LOCK(nt);
1450154532Ssam	gen = ++nt->nt_scangen;
1451120483Ssamrestart:
1452138568Ssam	IEEE80211_NODE_LOCK(nt);
1453138568Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1454120483Ssam		if (ni->ni_scangen == gen)	/* previously handled */
1455120483Ssam			continue;
1456120483Ssam		ni->ni_scangen = gen;
1457138568Ssam		/*
1458147788Ssam		 * Ignore entries for which have yet to receive an
1459147788Ssam		 * authentication frame.  These are transient and
1460147788Ssam		 * will be reclaimed when the last reference to them
1461147788Ssam		 * goes away (when frame xmits complete).
1462147788Ssam		 */
1463170530Ssam		if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
1464170530Ssam		     ic->ic_opmode == IEEE80211_M_STA) &&
1465148323Ssam		    (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
1466147788Ssam			continue;
1467147788Ssam		/*
1468138568Ssam		 * Free fragment if not needed anymore
1469138568Ssam		 * (last fragment older than 1s).
1470138568Ssam		 * XXX doesn't belong here
1471138568Ssam		 */
1472138568Ssam		if (ni->ni_rxfrag[0] != NULL &&
1473138568Ssam		    ticks > ni->ni_rxfragstamp + hz) {
1474138568Ssam			m_freem(ni->ni_rxfrag[0]);
1475138568Ssam			ni->ni_rxfrag[0] = NULL;
1476138568Ssam		}
1477172062Ssam		if (ni->ni_inact > 0)
1478172062Ssam			ni->ni_inact--;
1479140498Ssam		/*
1480140498Ssam		 * Special case ourself; we may be idle for extended periods
1481140498Ssam		 * of time and regardless reclaiming our state is wrong.
1482140498Ssam		 */
1483140498Ssam		if (ni == ic->ic_bss)
1484140498Ssam			continue;
1485148320Ssam		if (ni->ni_associd != 0 || isadhoc) {
1486119150Ssam			/*
1487170530Ssam			 * Age frames on the power save queue.
1488138568Ssam			 */
1489170530Ssam			if (ieee80211_node_saveq_age(ni) != 0 &&
1490170530Ssam			    IEEE80211_NODE_SAVEQ_QLEN(ni) == 0 &&
1491170530Ssam			    ic->ic_set_tim != NULL)
1492170530Ssam				ic->ic_set_tim(ni, 0);
1493138568Ssam			/*
1494138568Ssam			 * Probe the station before time it out.  We
1495138568Ssam			 * send a null data frame which may not be
1496138568Ssam			 * universally supported by drivers (need it
1497138568Ssam			 * for ps-poll support so it should be...).
1498170530Ssam			 *
1499170530Ssam			 * XXX don't probe the station unless we've
1500170530Ssam			 *     received a frame from them (and have
1501170530Ssam			 *     some idea of the rates they are capable
1502170530Ssam			 *     of); this will get fixed more properly
1503170530Ssam			 *     soon with better handling of the rate set.
1504138568Ssam			 */
1505172062Ssam			if ((ic->ic_flags_ext & IEEE80211_FEXT_INACT) &&
1506172062Ssam			    (0 < ni->ni_inact &&
1507172062Ssam			     ni->ni_inact <= ic->ic_inact_probe) &&
1508170530Ssam			    ni->ni_rates.rs_nrates != 0) {
1509148320Ssam				IEEE80211_NOTE(ic,
1510148320Ssam				    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
1511148320Ssam				    ni, "%s",
1512148320Ssam				    "probe station due to inactivity");
1513148582Ssam				/*
1514148582Ssam				 * Grab a reference before unlocking the table
1515148582Ssam				 * so the node cannot be reclaimed before we
1516148582Ssam				 * send the frame. ieee80211_send_nulldata
1517148582Ssam				 * understands we've done this and reclaims the
1518148582Ssam				 * ref for us as needed.
1519148582Ssam				 */
1520148582Ssam				ieee80211_ref_node(ni);
1521138568Ssam				IEEE80211_NODE_UNLOCK(nt);
1522148301Ssam				ieee80211_send_nulldata(ni);
1523138568Ssam				/* XXX stat? */
1524138568Ssam				goto restart;
1525138568Ssam			}
1526138568Ssam		}
1527172062Ssam		if ((ic->ic_flags_ext & IEEE80211_FEXT_INACT) &&
1528172062Ssam		    ni->ni_inact <= 0) {
1529148320Ssam			IEEE80211_NOTE(ic,
1530148320Ssam			    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
1531148320Ssam			    "station timed out due to inactivity "
1532148320Ssam			    "(refcnt %u)", ieee80211_node_refcnt(ni));
1533138568Ssam			/*
1534138568Ssam			 * Send a deauthenticate frame and drop the station.
1535138568Ssam			 * This is somewhat complicated due to reference counts
1536138568Ssam			 * and locking.  At this point a station will typically
1537138568Ssam			 * have a reference count of 1.  ieee80211_node_leave
1538138568Ssam			 * will do a "free" of the node which will drop the
1539138568Ssam			 * reference count.  But in the meantime a reference
1540138568Ssam			 * wil be held by the deauth frame.  The actual reclaim
1541138568Ssam			 * of the node will happen either after the tx is
1542138568Ssam			 * completed or by ieee80211_node_leave.
1543120483Ssam			 *
1544138568Ssam			 * Separately we must drop the node lock before sending
1545170530Ssam			 * in case the driver takes a lock, as this can result
1546170530Ssam			 * in a LOR between the node lock and the driver lock.
1547119150Ssam			 */
1548138568Ssam			IEEE80211_NODE_UNLOCK(nt);
1549138568Ssam			if (ni->ni_associd != 0) {
1550138568Ssam				IEEE80211_SEND_MGMT(ic, ni,
1551138568Ssam				    IEEE80211_FC0_SUBTYPE_DEAUTH,
1552138568Ssam				    IEEE80211_REASON_AUTH_EXPIRE);
1553138568Ssam			}
1554138568Ssam			ieee80211_node_leave(ic, ni);
1555121180Ssam			ic->ic_stats.is_node_timeout++;
1556120483Ssam			goto restart;
1557120483Ssam		}
1558116742Ssam	}
1559138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1560138568Ssam
1561138568Ssam	IEEE80211_SCAN_UNLOCK(nt);
1562170530Ssam}
1563138568Ssam
1564170530Ssamvoid
1565170530Ssamieee80211_node_timeout(void *arg)
1566170530Ssam{
1567170530Ssam	struct ieee80211com *ic = arg;
1568170530Ssam
1569170530Ssam	ieee80211_scan_timeout(ic);
1570170530Ssam	ieee80211_timeout_stations(&ic->ic_sta);
1571170530Ssam
1572170530Ssam	callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
1573170530Ssam		ieee80211_node_timeout, ic);
1574116742Ssam}
1575116742Ssam
1576116742Ssamvoid
1577138568Ssamieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg)
1578116742Ssam{
1579116742Ssam	struct ieee80211_node *ni;
1580138568Ssam	u_int gen;
1581116742Ssam
1582138568Ssam	IEEE80211_SCAN_LOCK(nt);
1583154532Ssam	gen = ++nt->nt_scangen;
1584138568Ssamrestart:
1585138568Ssam	IEEE80211_NODE_LOCK(nt);
1586138568Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1587138568Ssam		if (ni->ni_scangen != gen) {
1588138568Ssam			ni->ni_scangen = gen;
1589138568Ssam			(void) ieee80211_ref_node(ni);
1590138568Ssam			IEEE80211_NODE_UNLOCK(nt);
1591138568Ssam			(*f)(arg, ni);
1592138568Ssam			ieee80211_free_node(ni);
1593138568Ssam			goto restart;
1594138568Ssam		}
1595138568Ssam	}
1596138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1597138568Ssam
1598138568Ssam	IEEE80211_SCAN_UNLOCK(nt);
1599116742Ssam}
1600138568Ssam
1601138568Ssamvoid
1602138568Ssamieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
1603138568Ssam{
1604138568Ssam	printf("0x%p: mac %s refcnt %d\n", ni,
1605138568Ssam		ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
1606138568Ssam	printf("\tscangen %u authmode %u flags 0x%x\n",
1607138568Ssam		ni->ni_scangen, ni->ni_authmode, ni->ni_flags);
1608138568Ssam	printf("\tassocid 0x%x txpower %u vlan %u\n",
1609138568Ssam		ni->ni_associd, ni->ni_txpower, ni->ni_vlan);
1610138568Ssam	printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n",
1611167439Ssam		ni->ni_txseqs[IEEE80211_NONQOS_TID],
1612167439Ssam		ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT,
1613167439Ssam		ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK,
1614138568Ssam		ni->ni_rxfragstamp);
1615170530Ssam	printf("\trstamp %u rssi %d noise %d intval %u capinfo 0x%x\n",
1616170530Ssam		ni->ni_rstamp, ni->ni_rssi, ni->ni_noise,
1617170530Ssam		ni->ni_intval, ni->ni_capinfo);
1618138568Ssam	printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n",
1619138568Ssam		ether_sprintf(ni->ni_bssid),
1620138568Ssam		ni->ni_esslen, ni->ni_essid,
1621138568Ssam		ni->ni_chan->ic_freq, ni->ni_chan->ic_flags);
1622138568Ssam	printf("\tfails %u inact %u txrate %u\n",
1623138568Ssam		ni->ni_fails, ni->ni_inact, ni->ni_txrate);
1624170530Ssam	printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n",
1625170530Ssam		ni->ni_htcap, ni->ni_htparam,
1626170530Ssam		ni->ni_htctlchan, ni->ni_ht2ndchan);
1627170530Ssam	printf("\thtopmode %x htstbc %x chw %u\n",
1628170530Ssam		ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw);
1629138568Ssam}
1630138568Ssam
1631138568Ssamvoid
1632138568Ssamieee80211_dump_nodes(struct ieee80211_node_table *nt)
1633138568Ssam{
1634138568Ssam	ieee80211_iterate_nodes(nt,
1635138568Ssam		(ieee80211_iter_func *) ieee80211_dump_node, nt);
1636138568Ssam}
1637138568Ssam
1638138568Ssam/*
1639138568Ssam * Handle a station joining an 11g network.
1640138568Ssam */
1641138568Ssamstatic void
1642138568Ssamieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
1643138568Ssam{
1644138568Ssam
1645138568Ssam	/*
1646138568Ssam	 * Station isn't capable of short slot time.  Bump
1647138568Ssam	 * the count of long slot time stations and disable
1648138568Ssam	 * use of short slot time.  Note that the actual switch
1649138568Ssam	 * over to long slot time use may not occur until the
1650138568Ssam	 * next beacon transmission (per sec. 7.3.1.4 of 11g).
1651138568Ssam	 */
1652138568Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
1653138568Ssam		ic->ic_longslotsta++;
1654138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1655138568Ssam		    "[%s] station needs long slot time, count %d\n",
1656138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_longslotsta);
1657138568Ssam		/* XXX vap's w/ conflicting needs won't work */
1658170530Ssam		if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) {
1659170530Ssam			/*
1660170530Ssam			 * Don't force slot time when switched to turbo
1661170530Ssam			 * mode as non-ERP stations won't be present; this
1662170530Ssam			 * need only be done when on the normal G channel.
1663170530Ssam			 */
1664170530Ssam			ieee80211_set_shortslottime(ic, 0);
1665170530Ssam		}
1666138568Ssam	}
1667138568Ssam	/*
1668138568Ssam	 * If the new station is not an ERP station
1669138568Ssam	 * then bump the counter and enable protection
1670138568Ssam	 * if configured.
1671138568Ssam	 */
1672138568Ssam	if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) {
1673138568Ssam		ic->ic_nonerpsta++;
1674138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1675138568Ssam		    "[%s] station is !ERP, %d non-ERP stations associated\n",
1676138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_nonerpsta);
1677138568Ssam		/*
1678138568Ssam		 * If protection is configured, enable it.
1679138568Ssam		 */
1680138568Ssam		if (ic->ic_protmode != IEEE80211_PROT_NONE) {
1681138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1682138568Ssam			    "%s: enable use of protection\n", __func__);
1683138568Ssam			ic->ic_flags |= IEEE80211_F_USEPROT;
1684138568Ssam		}
1685138568Ssam		/*
1686138568Ssam		 * If station does not support short preamble
1687138568Ssam		 * then we must enable use of Barker preamble.
1688138568Ssam		 */
1689138568Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
1690138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1691138568Ssam			    "[%s] station needs long preamble\n",
1692138568Ssam			    ether_sprintf(ni->ni_macaddr));
1693138568Ssam			ic->ic_flags |= IEEE80211_F_USEBARKER;
1694138568Ssam			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
1695138568Ssam		}
1696153973Ssam		if (ic->ic_nonerpsta == 1)
1697153973Ssam			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
1698138568Ssam	} else
1699138568Ssam		ni->ni_flags |= IEEE80211_NODE_ERP;
1700138568Ssam}
1701138568Ssam
1702138568Ssamvoid
1703138568Ssamieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp)
1704138568Ssam{
1705138568Ssam	int newassoc;
1706138568Ssam
1707138568Ssam	if (ni->ni_associd == 0) {
1708170530Ssam		uint16_t aid;
1709138568Ssam
1710138568Ssam		/*
1711138568Ssam		 * It would be good to search the bitmap
1712138568Ssam		 * more efficiently, but this will do for now.
1713138568Ssam		 */
1714138568Ssam		for (aid = 1; aid < ic->ic_max_aid; aid++) {
1715138568Ssam			if (!IEEE80211_AID_ISSET(aid,
1716138568Ssam			    ic->ic_aid_bitmap))
1717138568Ssam				break;
1718138568Ssam		}
1719138568Ssam		if (aid >= ic->ic_max_aid) {
1720138568Ssam			IEEE80211_SEND_MGMT(ic, ni, resp,
1721138568Ssam			    IEEE80211_REASON_ASSOC_TOOMANY);
1722138568Ssam			ieee80211_node_leave(ic, ni);
1723138568Ssam			return;
1724138568Ssam		}
1725138568Ssam		ni->ni_associd = aid | 0xc000;
1726138568Ssam		IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
1727138568Ssam		ic->ic_sta_assoc++;
1728138568Ssam		newassoc = 1;
1729170530Ssam		if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
1730170530Ssam		    IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
1731138568Ssam			ieee80211_node_join_11g(ic, ni);
1732138568Ssam	} else
1733138568Ssam		newassoc = 0;
1734138568Ssam
1735138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG,
1736170530Ssam	    "[%s] station %sassociated at aid %d: %s preamble, %s slot time%s%s%s%s%s\n",
1737139523Ssam	    ether_sprintf(ni->ni_macaddr), newassoc ? "" : "re",
1738139523Ssam	    IEEE80211_NODE_AID(ni),
1739139523Ssam	    ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
1740139523Ssam	    ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long",
1741139523Ssam	    ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "",
1742170530Ssam	    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
1743170530Ssam	    ni->ni_flags & IEEE80211_NODE_HT ?
1744170530Ssam		(ni->ni_chw == 20 ? ", HT20" : ", HT40") : "",
1745170530Ssam	    IEEE80211_ATH_CAP(ic, ni, IEEE80211_NODE_FF) ?
1746170530Ssam		", fast-frames" : "",
1747170530Ssam	    IEEE80211_ATH_CAP(ic, ni, IEEE80211_NODE_TURBOP) ?
1748170530Ssam		", turbo" : ""
1749139523Ssam	);
1750138568Ssam
1751138568Ssam	/* give driver a chance to setup state like ni_txrate */
1752139524Ssam	if (ic->ic_newassoc != NULL)
1753148307Ssam		ic->ic_newassoc(ni, newassoc);
1754138568Ssam	IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
1755138568Ssam	/* tell the authenticator about new station */
1756138568Ssam	if (ic->ic_auth->ia_node_join != NULL)
1757138568Ssam		ic->ic_auth->ia_node_join(ic, ni);
1758138568Ssam	ieee80211_notify_node_join(ic, ni, newassoc);
1759138568Ssam}
1760138568Ssam
1761138568Ssam/*
1762138568Ssam * Handle a station leaving an 11g network.
1763138568Ssam */
1764138568Ssamstatic void
1765138568Ssamieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
1766138568Ssam{
1767138568Ssam
1768170530Ssam	KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan),
1769170530Ssam	     ("not in 11g, bss %u:0x%x, curmode %u", ic->ic_bsschan->ic_freq,
1770170530Ssam	      ic->ic_bsschan->ic_flags, ic->ic_curmode));
1771138568Ssam
1772138568Ssam	/*
1773138568Ssam	 * If a long slot station do the slot time bookkeeping.
1774138568Ssam	 */
1775138568Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
1776138568Ssam		KASSERT(ic->ic_longslotsta > 0,
1777138568Ssam		    ("bogus long slot station count %d", ic->ic_longslotsta));
1778138568Ssam		ic->ic_longslotsta--;
1779138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1780138568Ssam		    "[%s] long slot time station leaves, count now %d\n",
1781138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_longslotsta);
1782138568Ssam		if (ic->ic_longslotsta == 0) {
1783138568Ssam			/*
1784138568Ssam			 * Re-enable use of short slot time if supported
1785138568Ssam			 * and not operating in IBSS mode (per spec).
1786138568Ssam			 */
1787138568Ssam			if ((ic->ic_caps & IEEE80211_C_SHSLOT) &&
1788138568Ssam			    ic->ic_opmode != IEEE80211_M_IBSS) {
1789138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1790138568Ssam				    "%s: re-enable use of short slot time\n",
1791138568Ssam				    __func__);
1792138568Ssam				ieee80211_set_shortslottime(ic, 1);
1793138568Ssam			}
1794138568Ssam		}
1795138568Ssam	}
1796138568Ssam	/*
1797138568Ssam	 * If a non-ERP station do the protection-related bookkeeping.
1798138568Ssam	 */
1799138568Ssam	if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
1800138568Ssam		KASSERT(ic->ic_nonerpsta > 0,
1801138568Ssam		    ("bogus non-ERP station count %d", ic->ic_nonerpsta));
1802138568Ssam		ic->ic_nonerpsta--;
1803138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1804138568Ssam		    "[%s] non-ERP station leaves, count now %d\n",
1805138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_nonerpsta);
1806138568Ssam		if (ic->ic_nonerpsta == 0) {
1807138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1808138568Ssam				"%s: disable use of protection\n", __func__);
1809138568Ssam			ic->ic_flags &= ~IEEE80211_F_USEPROT;
1810138568Ssam			/* XXX verify mode? */
1811138568Ssam			if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
1812138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1813138568Ssam				    "%s: re-enable use of short preamble\n",
1814138568Ssam				    __func__);
1815138568Ssam				ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
1816138568Ssam				ic->ic_flags &= ~IEEE80211_F_USEBARKER;
1817138568Ssam			}
1818153973Ssam			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
1819138568Ssam		}
1820138568Ssam	}
1821138568Ssam}
1822138568Ssam
1823138568Ssam/*
1824138568Ssam * Handle bookkeeping for station deauthentication/disassociation
1825138568Ssam * when operating as an ap.
1826138568Ssam */
1827138568Ssamvoid
1828138568Ssamieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
1829138568Ssam{
1830140499Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1831138568Ssam
1832138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG,
1833138568Ssam	    "[%s] station with aid %d leaves\n",
1834138568Ssam	    ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_AID(ni));
1835138568Ssam
1836170530Ssam	KASSERT(ic->ic_opmode != IEEE80211_M_STA,
1837138568Ssam		("unexpected operating mode %u", ic->ic_opmode));
1838138568Ssam	/*
1839138568Ssam	 * If node wasn't previously associated all
1840138568Ssam	 * we need to do is reclaim the reference.
1841138568Ssam	 */
1842138568Ssam	/* XXX ibss mode bypasses 11g and notification */
1843138568Ssam	if (ni->ni_associd == 0)
1844138568Ssam		goto done;
1845138568Ssam	/*
1846138568Ssam	 * Tell the authenticator the station is leaving.
1847138568Ssam	 * Note that we must do this before yanking the
1848138568Ssam	 * association id as the authenticator uses the
1849138568Ssam	 * associd to locate it's state block.
1850138568Ssam	 */
1851138568Ssam	if (ic->ic_auth->ia_node_leave != NULL)
1852138568Ssam		ic->ic_auth->ia_node_leave(ic, ni);
1853138568Ssam	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
1854138568Ssam	ni->ni_associd = 0;
1855138568Ssam	ic->ic_sta_assoc--;
1856138568Ssam
1857170530Ssam	if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
1858170530Ssam	    IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
1859138568Ssam		ieee80211_node_leave_11g(ic, ni);
1860138568Ssam	/*
1861138568Ssam	 * Cleanup station state.  In particular clear various
1862138568Ssam	 * state that might otherwise be reused if the node
1863138568Ssam	 * is reused before the reference count goes to zero
1864138568Ssam	 * (and memory is reclaimed).
1865138568Ssam	 */
1866138568Ssam	ieee80211_sta_leave(ic, ni);
1867138568Ssamdone:
1868140499Ssam	/*
1869140499Ssam	 * Remove the node from any table it's recorded in and
1870140499Ssam	 * drop the caller's reference.  Removal from the table
1871140499Ssam	 * is important to insure the node is not reprocessed
1872140499Ssam	 * for inactivity.
1873140499Ssam	 */
1874140499Ssam	if (nt != NULL) {
1875140499Ssam		IEEE80211_NODE_LOCK(nt);
1876140499Ssam		node_reclaim(nt, ni);
1877140499Ssam		IEEE80211_NODE_UNLOCK(nt);
1878140499Ssam	} else
1879140499Ssam		ieee80211_free_node(ni);
1880138568Ssam}
1881138568Ssam
1882170530Ssamint8_t
1883138568Ssamieee80211_getrssi(struct ieee80211com *ic)
1884138568Ssam{
1885138568Ssam#define	NZ(x)	((x) == 0 ? 1 : (x))
1886140753Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1887170530Ssam	int rssi_samples;
1888170530Ssam	int32_t rssi_total;
1889138568Ssam	struct ieee80211_node *ni;
1890138568Ssam
1891138568Ssam	rssi_total = 0;
1892138568Ssam	rssi_samples = 0;
1893138568Ssam	switch (ic->ic_opmode) {
1894138568Ssam	case IEEE80211_M_IBSS:		/* average of all ibss neighbors */
1895138568Ssam	case IEEE80211_M_AHDEMO:	/* average of all neighbors */
1896138568Ssam	case IEEE80211_M_HOSTAP:	/* average of all associated stations */
1897138568Ssam		/* XXX locking */
1898140753Ssam		TAILQ_FOREACH(ni, &nt->nt_node, ni_list)
1899170530Ssam			if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
1900170530Ssam			    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS)) {
1901170530Ssam				int8_t rssi = ic->ic_node_getrssi(ni);
1902170530Ssam				if (rssi != 0) {
1903170530Ssam					rssi_samples++;
1904170530Ssam					rssi_total += rssi;
1905170530Ssam				}
1906138568Ssam			}
1907138568Ssam		break;
1908138568Ssam	case IEEE80211_M_MONITOR:	/* XXX */
1909138568Ssam	case IEEE80211_M_STA:		/* use stats from associated ap */
1910138568Ssam	default:
1911138568Ssam		if (ic->ic_bss != NULL)
1912138568Ssam			rssi_total = ic->ic_node_getrssi(ic->ic_bss);
1913138568Ssam		rssi_samples = 1;
1914138568Ssam		break;
1915138568Ssam	}
1916138568Ssam	return rssi_total / NZ(rssi_samples);
1917138568Ssam#undef NZ
1918138568Ssam}
1919138568Ssam
1920170530Ssamvoid
1921170530Ssamieee80211_getsignal(struct ieee80211com *ic, int8_t *rssi, int8_t *noise)
1922138568Ssam{
1923138568Ssam
1924170530Ssam	if (ic->ic_bss == NULL)		/* NB: shouldn't happen */
1925170530Ssam		return;
1926170530Ssam	ic->ic_node_getsignal(ic->ic_bss, rssi, noise);
1927170530Ssam	/* for non-station mode return avg'd rssi accounting */
1928170530Ssam	if (ic->ic_opmode != IEEE80211_M_STA)
1929170530Ssam		*rssi = ieee80211_getrssi(ic);
1930138568Ssam}
1931138568Ssam
1932138568Ssam/*
1933138568Ssam * Node table support.
1934138568Ssam */
1935138568Ssam
1936138568Ssamstatic void
1937138568Ssamieee80211_node_table_init(struct ieee80211com *ic,
1938138568Ssam	struct ieee80211_node_table *nt,
1939170530Ssam	const char *name, int inact, int keyixmax)
1940138568Ssam{
1941138568Ssam
1942138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1943138568Ssam		"%s %s table, inact %u\n", __func__, name, inact);
1944138568Ssam
1945138568Ssam	nt->nt_ic = ic;
1946138568Ssam	/* XXX need unit */
1947138568Ssam	IEEE80211_NODE_LOCK_INIT(nt, ic->ic_ifp->if_xname);
1948138568Ssam	IEEE80211_SCAN_LOCK_INIT(nt, ic->ic_ifp->if_xname);
1949138568Ssam	TAILQ_INIT(&nt->nt_node);
1950138568Ssam	nt->nt_name = name;
1951138568Ssam	nt->nt_scangen = 1;
1952138568Ssam	nt->nt_inact_init = inact;
1953148863Ssam	nt->nt_keyixmax = keyixmax;
1954148863Ssam	if (nt->nt_keyixmax > 0) {
1955148863Ssam		MALLOC(nt->nt_keyixmap, struct ieee80211_node **,
1956148863Ssam			keyixmax * sizeof(struct ieee80211_node *),
1957148863Ssam			M_80211_NODE, M_NOWAIT | M_ZERO);
1958148863Ssam		if (nt->nt_keyixmap == NULL)
1959148863Ssam			if_printf(ic->ic_ifp,
1960148863Ssam			    "Cannot allocate key index map with %u entries\n",
1961148863Ssam			    keyixmax);
1962148863Ssam	} else
1963148863Ssam		nt->nt_keyixmap = NULL;
1964138568Ssam}
1965138568Ssam
1966170530Ssamstatic void
1967138568Ssamieee80211_node_table_reset(struct ieee80211_node_table *nt)
1968138568Ssam{
1969138568Ssam
1970138568Ssam	IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
1971138568Ssam		"%s %s table\n", __func__, nt->nt_name);
1972138568Ssam
1973138568Ssam	IEEE80211_NODE_LOCK(nt);
1974138568Ssam	ieee80211_free_allnodes_locked(nt);
1975138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1976138568Ssam}
1977138568Ssam
1978138568Ssamstatic void
1979138568Ssamieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
1980138568Ssam{
1981138568Ssam
1982138568Ssam	IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
1983138568Ssam		"%s %s table\n", __func__, nt->nt_name);
1984138568Ssam
1985148863Ssam	IEEE80211_NODE_LOCK(nt);
1986138568Ssam	ieee80211_free_allnodes_locked(nt);
1987148863Ssam	if (nt->nt_keyixmap != NULL) {
1988148863Ssam		/* XXX verify all entries are NULL */
1989148863Ssam		int i;
1990148863Ssam		for (i = 0; i < nt->nt_keyixmax; i++)
1991148863Ssam			if (nt->nt_keyixmap[i] != NULL)
1992148863Ssam				printf("%s: %s[%u] still active\n", __func__,
1993148863Ssam					nt->nt_name, i);
1994148863Ssam		FREE(nt->nt_keyixmap, M_80211_NODE);
1995148863Ssam		nt->nt_keyixmap = NULL;
1996148863Ssam	}
1997138568Ssam	IEEE80211_SCAN_LOCK_DESTROY(nt);
1998138568Ssam	IEEE80211_NODE_LOCK_DESTROY(nt);
1999138568Ssam}
2000