ieee80211_node.c revision 172063
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 172063 2007-09-06 00:08:02Z 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{
197172063Ssam	struct ieee80211com *ic = ni->ni_ic;
198172063Ssam
199138568Ssam	ni->ni_flags &= ~IEEE80211_NODE_AUTH;
200172062Ssam	ni->ni_inact_reload = ic->ic_inact_auth;
201172062Ssam	if (ni->ni_inact > ni->ni_inact_reload)
202172062Ssam		ni->ni_inact = ni->ni_inact_reload;
203138568Ssam}
204138568Ssam
205116742Ssam/*
206138568Ssam * Set/change the channel.  The rate set is also updated as
207138568Ssam * to insure a consistent view by drivers.
208138568Ssam */
209153351Ssamstatic void
210170530Ssamieee80211_node_set_chan(struct ieee80211com *ic, struct ieee80211_node *ni)
211138568Ssam{
212170530Ssam	struct ieee80211_channel *chan = ic->ic_bsschan;
213170530Ssam
214170530Ssam#if 0
215170530Ssam	KASSERT(chan != IEEE80211_CHAN_ANYC, ("bss channel not setup"));
216170530Ssam#else
217153351Ssam	if (chan == IEEE80211_CHAN_ANYC)	/* XXX while scanning */
218153351Ssam		chan = ic->ic_curchan;
219170530Ssam#endif
220138568Ssam	ni->ni_chan = chan;
221170530Ssam	if (IEEE80211_IS_CHAN_HT(chan)) {
222170530Ssam		/*
223170530Ssam		 * XXX Gotta be careful here; the rate set returned by
224170530Ssam		 * ieee80211_get_suprates is actually any HT rate
225170530Ssam		 * set so blindly copying it will be bad.  We must
226170530Ssam		 * install the legacy rate est in ni_rates and the
227170530Ssam		 * HT rate set in ni_htrates.
228170530Ssam		 */
229170530Ssam		ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan);
230170530Ssam	}
231165569Ssam	ni->ni_rates = *ieee80211_get_suprates(ic, chan);
232138568Ssam}
233138568Ssam
234138568Ssam/*
235156358Ssam * Probe the curent channel, if allowed, while scanning.
236156358Ssam * If the channel is not marked passive-only then send
237156358Ssam * a probe request immediately.  Otherwise mark state and
238156358Ssam * listen for beacons on the channel; if we receive something
239156358Ssam * then we'll transmit a probe request.
240156358Ssam */
241156358Ssamvoid
242156358Ssamieee80211_probe_curchan(struct ieee80211com *ic, int force)
243156358Ssam{
244156358Ssam	struct ifnet *ifp = ic->ic_ifp;
245156358Ssam
246156358Ssam	if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 || force) {
247156358Ssam		/*
248156358Ssam		 * XXX send both broadcast+directed probe request
249156358Ssam		 */
250156358Ssam		ieee80211_send_probereq(ic->ic_bss,
251156358Ssam			ic->ic_myaddr, ifp->if_broadcastaddr,
252156358Ssam			ifp->if_broadcastaddr,
253170530Ssam			ic->ic_des_ssid[0].ssid, ic->ic_des_ssid[0].len,
254156358Ssam			ic->ic_opt_ie, ic->ic_opt_ie_len);
255156358Ssam	} else
256156358Ssam		ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN;
257156358Ssam}
258156358Ssam
259141658Ssamstatic __inline void
260141658Ssamcopy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss)
261141658Ssam{
262141658Ssam	/* propagate useful state */
263141658Ssam	nbss->ni_authmode = obss->ni_authmode;
264141658Ssam	nbss->ni_txpower = obss->ni_txpower;
265141658Ssam	nbss->ni_vlan = obss->ni_vlan;
266141658Ssam	nbss->ni_rsn = obss->ni_rsn;
267141658Ssam	/* XXX statistics? */
268141658Ssam}
269141658Ssam
270116742Ssamvoid
271116742Ssamieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
272116742Ssam{
273140753Ssam	struct ieee80211_node_table *nt;
274116742Ssam	struct ieee80211_node *ni;
275116742Ssam
276138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
277138568Ssam		"%s: creating ibss\n", __func__);
278138568Ssam
279138568Ssam	/*
280138568Ssam	 * Create the station/neighbor table.  Note that for adhoc
281138568Ssam	 * mode we make the initial inactivity timer longer since
282138568Ssam	 * we create nodes only through discovery and they typically
283138568Ssam	 * are long-lived associations.
284138568Ssam	 */
285140753Ssam	nt = &ic->ic_sta;
286140753Ssam	IEEE80211_NODE_LOCK(nt);
287140753Ssam	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
288140753Ssam		nt->nt_name = "station";
289140753Ssam		nt->nt_inact_init = ic->ic_inact_init;
290140753Ssam	} else {
291140753Ssam		nt->nt_name = "neighbor";
292140753Ssam		nt->nt_inact_init = ic->ic_inact_run;
293140753Ssam	}
294140753Ssam	IEEE80211_NODE_UNLOCK(nt);
295140753Ssam
296148863Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr);
297140753Ssam	if (ni == NULL) {
298140753Ssam		/* XXX recovery? */
299138568Ssam		return;
300138568Ssam	}
301116742Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
302170530Ssam	ni->ni_esslen = ic->ic_des_ssid[0].len;
303170530Ssam	memcpy(ni->ni_essid, ic->ic_des_ssid[0].ssid, ni->ni_esslen);
304170530Ssam	if (ic->ic_bss != NULL)
305170530Ssam		copy_bss(ni, ic->ic_bss);
306148843Ssam	ni->ni_intval = ic->ic_bintval;
307138568Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY)
308116742Ssam		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
309116742Ssam	if (ic->ic_phytype == IEEE80211_T_FH) {
310116742Ssam		ni->ni_fhdwell = 200;	/* XXX */
311116742Ssam		ni->ni_fhindex = 1;
312116742Ssam	}
313138568Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
314138568Ssam		ic->ic_flags |= IEEE80211_F_SIBSS;
315138568Ssam		ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS;	/* XXX */
316143300Ssam		if (ic->ic_flags & IEEE80211_F_DESBSSID)
317143300Ssam			IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
318167282Ssam		else {
319167282Ssam			get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN);
320167282Ssam			/* clear group bit, add local bit */
321167282Ssam			ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02;
322167282Ssam		}
323153403Ssam	} else if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
324153403Ssam		if (ic->ic_flags & IEEE80211_F_DESBSSID)
325153403Ssam			IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
326153403Ssam		else
327153403Ssam			memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
328138568Ssam	}
329138568Ssam	/*
330138568Ssam	 * Fix the channel and related attributes.
331138568Ssam	 */
332170530Ssam	ic->ic_bsschan = chan;
333170530Ssam	ieee80211_node_set_chan(ic, ni);
334170530Ssam	ic->ic_curmode = ieee80211_chan2mode(chan);
335138568Ssam	/*
336138568Ssam	 * Do mode-specific rate setup.
337138568Ssam	 */
338170530Ssam	if (IEEE80211_IS_CHAN_FULL(chan)) {
339170530Ssam		if (IEEE80211_IS_CHAN_ANYG(chan)) {
340170530Ssam			/*
341170530Ssam			 * Use a mixed 11b/11g rate set.
342170530Ssam			 */
343170530Ssam			ieee80211_set11gbasicrates(&ni->ni_rates,
344170530Ssam				IEEE80211_MODE_11G);
345170530Ssam		} else if (IEEE80211_IS_CHAN_B(chan)) {
346170530Ssam			/*
347170530Ssam			 * Force pure 11b rate set.
348170530Ssam			 */
349170530Ssam			ieee80211_set11gbasicrates(&ni->ni_rates,
350170530Ssam				IEEE80211_MODE_11B);
351170530Ssam		}
352170530Ssam	}
353138568Ssam
354170530Ssam	(void) ieee80211_sta_join1(ieee80211_ref_node(ni));
355116742Ssam}
356116742Ssam
357170530Ssam/*
358170530Ssam * Reset bss state on transition to the INIT state.
359170530Ssam * Clear any stations from the table (they have been
360170530Ssam * deauth'd) and reset the bss node (clears key, rate
361170530Ssam * etc. state).
362170530Ssam */
363138568Ssamvoid
364138568Ssamieee80211_reset_bss(struct ieee80211com *ic)
365138568Ssam{
366138568Ssam	struct ieee80211_node *ni, *obss;
367138568Ssam
368170530Ssam	callout_drain(&ic->ic_inact);
369140753Ssam	ieee80211_node_table_reset(&ic->ic_sta);
370170530Ssam	ieee80211_reset_erp(ic);
371140753Ssam
372170530Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr);
373138568Ssam	KASSERT(ni != NULL, ("unable to setup inital BSS node"));
374138568Ssam	obss = ic->ic_bss;
375138568Ssam	ic->ic_bss = ieee80211_ref_node(ni);
376141658Ssam	if (obss != NULL) {
377141658Ssam		copy_bss(ni, obss);
378148843Ssam		ni->ni_intval = ic->ic_bintval;
379138568Ssam		ieee80211_free_node(obss);
380141658Ssam	}
381138568Ssam}
382138568Ssam
383170530Ssamstatic int
384170530Ssammatch_ssid(const struct ieee80211_node *ni,
385170530Ssam	int nssid, const struct ieee80211_scan_ssid ssids[])
386170530Ssam{
387170530Ssam	int i;
388148432Ssam
389170530Ssam	for (i = 0; i < nssid; i++) {
390170530Ssam		if (ni->ni_esslen == ssids[i].len &&
391170530Ssam		     memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0)
392170530Ssam			return 1;
393170530Ssam	}
394170530Ssam	return 0;
395170530Ssam}
396170530Ssam
397170530Ssam/*
398170530Ssam * Test a node for suitability/compatibility.
399170530Ssam */
400127767Ssamstatic int
401170530Ssamcheck_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
402127767Ssam{
403170530Ssam        uint8_t rate;
404170530Ssam
405170530Ssam	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
406170530Ssam		return 0;
407170530Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
408170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
409170530Ssam			return 0;
410170530Ssam	} else {
411170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
412170530Ssam			return 0;
413170530Ssam	}
414170530Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
415170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
416170530Ssam			return 0;
417170530Ssam	} else {
418170530Ssam		/* XXX does this mean privacy is supported or required? */
419170530Ssam		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
420170530Ssam			return 0;
421170530Ssam	}
422170530Ssam	rate = ieee80211_fix_rate(ni, &ni->ni_rates,
423170530Ssam	    IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
424170530Ssam	if (rate & IEEE80211_RATE_BASIC)
425170530Ssam		return 0;
426170530Ssam	if (ic->ic_des_nssid != 0 &&
427170530Ssam	    !match_ssid(ni, ic->ic_des_nssid, ic->ic_des_ssid))
428170530Ssam		return 0;
429170530Ssam	if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
430170530Ssam	    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
431170530Ssam		return 0;
432170530Ssam	return 1;
433170530Ssam}
434170530Ssam
435170530Ssam#ifdef IEEE80211_DEBUG
436170530Ssam/*
437170530Ssam * Display node suitability/compatibility.
438170530Ssam */
439170530Ssamstatic void
440170530Ssamcheck_bss_debug(struct ieee80211com *ic, struct ieee80211_node *ni)
441170530Ssam{
442170530Ssam        uint8_t rate;
443127767Ssam        int fail;
444127767Ssam
445127767Ssam	fail = 0;
446127767Ssam	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
447127767Ssam		fail |= 0x01;
448127767Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
449127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
450127767Ssam			fail |= 0x02;
451127767Ssam	} else {
452127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
453127767Ssam			fail |= 0x02;
454127767Ssam	}
455138568Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
456127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
457127767Ssam			fail |= 0x04;
458127767Ssam	} else {
459127767Ssam		/* XXX does this mean privacy is supported or required? */
460127767Ssam		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
461127767Ssam			fail |= 0x04;
462127767Ssam	}
463167442Ssam	rate = ieee80211_fix_rate(ni, &ni->ni_rates,
464165887Ssam	     IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
465127767Ssam	if (rate & IEEE80211_RATE_BASIC)
466127767Ssam		fail |= 0x08;
467170530Ssam	if (ic->ic_des_nssid != 0 &&
468170530Ssam	    !match_ssid(ni, ic->ic_des_nssid, ic->ic_des_ssid))
469127767Ssam		fail |= 0x10;
470127767Ssam	if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
471127767Ssam	    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
472127767Ssam		fail |= 0x20;
473127767Ssam
474170530Ssam	printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr));
475170530Ssam	printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' ');
476170530Ssam	printf(" %3d%c",
477170530Ssam	    ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' ');
478170530Ssam	printf(" %+4d", ni->ni_rssi);
479170530Ssam	printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
480170530Ssam	    fail & 0x08 ? '!' : ' ');
481170530Ssam	printf(" %4s%c",
482170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
483170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
484170530Ssam	    "????",
485170530Ssam	    fail & 0x02 ? '!' : ' ');
486170530Ssam	printf(" %3s%c ",
487170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?  "wep" : "no",
488170530Ssam	    fail & 0x04 ? '!' : ' ');
489170530Ssam	ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
490170530Ssam	printf("%s\n", fail & 0x10 ? "!" : "");
491138568Ssam}
492170530Ssam#endif /* IEEE80211_DEBUG */
493138568Ssam
494138568Ssam/*
495138568Ssam * Handle 802.11 ad hoc network merge.  The
496138568Ssam * convention, set by the Wireless Ethernet Compatibility Alliance
497138568Ssam * (WECA), is that an 802.11 station will change its BSSID to match
498138568Ssam * the "oldest" 802.11 ad hoc network, on the same channel, that
499138568Ssam * has the station's desired SSID.  The "oldest" 802.11 network
500138568Ssam * sends beacons with the greatest TSF timestamp.
501138568Ssam *
502138568Ssam * The caller is assumed to validate TSF's before attempting a merge.
503138568Ssam *
504138568Ssam * Return !0 if the BSSID changed, 0 otherwise.
505138568Ssam */
506138568Ssamint
507148306Ssamieee80211_ibss_merge(struct ieee80211_node *ni)
508138568Ssam{
509148306Ssam	struct ieee80211com *ic = ni->ni_ic;
510138568Ssam
511140453Ssam	if (ni == ic->ic_bss ||
512140453Ssam	    IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
513138568Ssam		/* unchanged, nothing to do */
514138568Ssam		return 0;
515138568Ssam	}
516170530Ssam	if (!check_bss(ic, ni)) {
517170530Ssam		/* capabilities mismatch */
518138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
519138568Ssam		    "%s: merge failed, capabilities mismatch\n", __func__);
520170530Ssam#ifdef IEEE80211_DEBUG
521170530Ssam		if (ieee80211_msg_assoc(ic))
522170530Ssam			check_bss_debug(ic, ni);
523170530Ssam#endif
524138568Ssam		ic->ic_stats.is_ibss_capmismatch++;
525138568Ssam		return 0;
526138568Ssam	}
527138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
528138568Ssam		"%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
529138568Ssam		ether_sprintf(ni->ni_bssid),
530138568Ssam		ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
531138568Ssam		ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
532138568Ssam		ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
533138568Ssam	);
534170530Ssam	return ieee80211_sta_join1(ieee80211_ref_node(ni));
535138568Ssam}
536138568Ssam
537138568Ssam/*
538138568Ssam * Join the specified IBSS/BSS network.  The node is assumed to
539138568Ssam * be passed in with a held reference.
540138568Ssam */
541170530Ssamstatic int
542170530Ssamieee80211_sta_join1(struct ieee80211_node *selbs)
543138568Ssam{
544170530Ssam	struct ieee80211com *ic = selbs->ni_ic;
545138568Ssam	struct ieee80211_node *obss;
546170530Ssam	int canreassoc;
547138568Ssam
548116742Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
549140753Ssam		struct ieee80211_node_table *nt;
550138568Ssam		/*
551140753Ssam		 * Fillin the neighbor table; it will already
552139521Ssam		 * exist if we are simply switching mastership.
553140753Ssam		 * XXX ic_sta always setup so this is unnecessary?
554127772Ssam		 */
555140753Ssam		nt = &ic->ic_sta;
556140753Ssam		IEEE80211_NODE_LOCK(nt);
557140753Ssam		nt->nt_name = "neighbor";
558140753Ssam		nt->nt_inact_init = ic->ic_inact_run;
559140753Ssam		IEEE80211_NODE_UNLOCK(nt);
560138568Ssam	}
561138568Ssam
562138568Ssam	/*
563138568Ssam	 * Committed to selbs, setup state.
564138568Ssam	 */
565138568Ssam	obss = ic->ic_bss;
566170530Ssam	/*
567170530Ssam	 * Check if old+new node have the same address in which
568170530Ssam	 * case we can reassociate when operating in sta mode.
569170530Ssam	 */
570170530Ssam	canreassoc = (obss != NULL &&
571170530Ssam		ic->ic_state == IEEE80211_S_RUN &&
572170530Ssam		IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr));
573140753Ssam	ic->ic_bss = selbs;		/* NB: caller assumed to bump refcnt */
574153352Ssam	if (obss != NULL) {
575153352Ssam		copy_bss(selbs, obss);
576138568Ssam		ieee80211_free_node(obss);
577153352Ssam	}
578165887Ssam
579138568Ssam	/*
580165887Ssam	 * Delete unusable rates; we've already checked
581165887Ssam	 * that the negotiated rate set is acceptable.
582165887Ssam	 */
583167442Ssam	ieee80211_fix_rate(ic->ic_bss, &ic->ic_bss->ni_rates,
584167442Ssam		IEEE80211_F_DODEL | IEEE80211_F_JOIN);
585165887Ssam
586170530Ssam	ic->ic_bsschan = selbs->ni_chan;
587170530Ssam	ic->ic_curchan = ic->ic_bsschan;
588170530Ssam	ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
589170530Ssam	ic->ic_set_channel(ic);
590165887Ssam	/*
591138568Ssam	 * Set the erp state (mostly the slot time) to deal with
592138568Ssam	 * the auto-select case; this should be redundant if the
593138568Ssam	 * mode is locked.
594138568Ssam	 */
595138568Ssam	ieee80211_reset_erp(ic);
596138568Ssam	ieee80211_wme_initparams(ic);
597140753Ssam
598170530Ssam	if (ic->ic_opmode == IEEE80211_M_STA) {
599170530Ssam		if (canreassoc) {
600170530Ssam			/* Reassociate */
601170530Ssam			ieee80211_new_state(ic, IEEE80211_S_ASSOC, 1);
602170530Ssam		} else {
603170530Ssam			/*
604170530Ssam			 * Act as if we received a DEAUTH frame in case we
605170530Ssam			 * are invoked from the RUN state.  This will cause
606170530Ssam			 * us to try to re-authenticate if we are operating
607170530Ssam			 * as a station.
608170530Ssam			 */
609170530Ssam			ieee80211_new_state(ic, IEEE80211_S_AUTH,
610170530Ssam				IEEE80211_FC0_SUBTYPE_DEAUTH);
611170530Ssam		}
612170530Ssam	} else
613117811Ssam		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
614138568Ssam	return 1;
615116742Ssam}
616116742Ssam
617170530Ssamint
618170530Ssamieee80211_sta_join(struct ieee80211com *ic,
619170530Ssam	const struct ieee80211_scan_entry *se)
620170530Ssam{
621170530Ssam	struct ieee80211_node *ni;
622170530Ssam
623170530Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, se->se_macaddr);
624170530Ssam	if (ni == NULL) {
625170530Ssam		/* XXX msg */
626170530Ssam		return 0;
627170530Ssam	}
628170530Ssam	/*
629170530Ssam	 * Expand scan state into node's format.
630170530Ssam	 * XXX may not need all this stuff
631170530Ssam	 */
632170530Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid);
633170530Ssam	ni->ni_esslen = se->se_ssid[1];
634170530Ssam	memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen);
635170530Ssam	ni->ni_rstamp = se->se_rstamp;
636170530Ssam	ni->ni_tstamp.tsf = se->se_tstamp.tsf;
637170530Ssam	ni->ni_intval = se->se_intval;
638170530Ssam	ni->ni_capinfo = se->se_capinfo;
639170530Ssam	/* XXX shift to 11n channel if htinfo present */
640170530Ssam	ni->ni_chan = se->se_chan;
641170530Ssam	ni->ni_timoff = se->se_timoff;
642170530Ssam	ni->ni_fhdwell = se->se_fhdwell;
643170530Ssam	ni->ni_fhindex = se->se_fhindex;
644170530Ssam	ni->ni_erp = se->se_erp;
645170530Ssam	ni->ni_rssi = se->se_rssi;
646170530Ssam	ni->ni_noise = se->se_noise;
647170530Ssam	if (se->se_htcap_ie != NULL)
648170530Ssam		ieee80211_ht_node_init(ni, se->se_htcap_ie);
649170530Ssam	if (se->se_htinfo_ie != NULL)
650170530Ssam		ieee80211_parse_htinfo(ni, se->se_htinfo_ie);
651170530Ssam	if (se->se_wpa_ie != NULL)
652170530Ssam		ieee80211_saveie(&ni->ni_wpa_ie, se->se_wpa_ie);
653170530Ssam	if (se->se_rsn_ie != NULL)
654170530Ssam		ieee80211_saveie(&ni->ni_rsn_ie, se->se_rsn_ie);
655170530Ssam	if (se->se_wme_ie != NULL)
656170530Ssam		ieee80211_saveie(&ni->ni_wme_ie, se->se_wme_ie);
657170530Ssam	if (se->se_ath_ie != NULL)
658170530Ssam		ieee80211_saveath(ni, se->se_ath_ie);
659170530Ssam
660170530Ssam	ic->ic_dtim_period = se->se_dtimperiod;
661170530Ssam	ic->ic_dtim_count = 0;
662170530Ssam
663170530Ssam	/* NB: must be after ni_chan is setup */
664170530Ssam	ieee80211_setup_rates(ni, se->se_rates, se->se_xrates,
665170530Ssam		IEEE80211_F_DOSORT);
666170530Ssam	if (se->se_htcap_ie != NULL)
667170530Ssam		ieee80211_setup_htrates(ni, se->se_htcap_ie, IEEE80211_F_JOIN);
668170530Ssam	if (se->se_htinfo_ie != NULL)
669170530Ssam		ieee80211_setup_basic_htrates(ni, se->se_htinfo_ie);
670170530Ssam
671170530Ssam	return ieee80211_sta_join1(ieee80211_ref_node(ni));
672170530Ssam}
673170530Ssam
674138568Ssam/*
675138568Ssam * Leave the specified IBSS/BSS network.  The node is assumed to
676138568Ssam * be passed in with a held reference.
677138568Ssam */
678138568Ssamvoid
679138568Ssamieee80211_sta_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
680138568Ssam{
681138568Ssam	ic->ic_node_cleanup(ni);
682138568Ssam	ieee80211_notify_node_leave(ic, ni);
683138568Ssam}
684138568Ssam
685116742Ssamstatic struct ieee80211_node *
686138568Ssamnode_alloc(struct ieee80211_node_table *nt)
687116742Ssam{
688127768Ssam	struct ieee80211_node *ni;
689138568Ssam
690127768Ssam	MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node),
691127768Ssam		M_80211_NODE, M_NOWAIT | M_ZERO);
692127768Ssam	return ni;
693116742Ssam}
694116742Ssam
695138568Ssam/*
696138568Ssam * Reclaim any resources in a node and reset any critical
697138568Ssam * state.  Typically nodes are free'd immediately after,
698138568Ssam * but in some cases the storage may be reused so we need
699138568Ssam * to insure consistent state (should probably fix that).
700138568Ssam */
701116742Ssamstatic void
702138568Ssamnode_cleanup(struct ieee80211_node *ni)
703116742Ssam{
704138568Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
705138568Ssam	struct ieee80211com *ic = ni->ni_ic;
706170530Ssam	int i;
707138568Ssam
708138568Ssam	/* NB: preserve ni_table */
709138568Ssam	if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) {
710138568Ssam		ic->ic_ps_sta--;
711138568Ssam		ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
712138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
713138568Ssam		    "[%s] power save mode off, %u sta's in ps mode\n",
714138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_ps_sta);
715138568Ssam	}
716147788Ssam	/*
717147788Ssam	 * Clear AREF flag that marks the authorization refcnt bump
718147788Ssam	 * has happened.  This is probably not needed as the node
719147788Ssam	 * should always be removed from the table so not found but
720147788Ssam	 * do it just in case.
721147788Ssam	 */
722147788Ssam	ni->ni_flags &= ~IEEE80211_NODE_AREF;
723138568Ssam
724138568Ssam	/*
725138568Ssam	 * Drain power save queue and, if needed, clear TIM.
726138568Ssam	 */
727170530Ssam	if (ieee80211_node_saveq_drain(ni) != 0 && ic->ic_set_tim != NULL)
728148304Ssam		ic->ic_set_tim(ni, 0);
729138568Ssam
730138568Ssam	ni->ni_associd = 0;
731138568Ssam	if (ni->ni_challenge != NULL) {
732170530Ssam		FREE(ni->ni_challenge, M_80211_NODE);
733138568Ssam		ni->ni_challenge = NULL;
734138568Ssam	}
735138568Ssam	/*
736138568Ssam	 * Preserve SSID, WPA, and WME ie's so the bss node is
737138568Ssam	 * reusable during a re-auth/re-assoc state transition.
738138568Ssam	 * If we remove these data they will not be recreated
739138568Ssam	 * because they come from a probe-response or beacon frame
740138568Ssam	 * which cannot be expected prior to the association-response.
741138568Ssam	 * This should not be an issue when operating in other modes
742138568Ssam	 * as stations leaving always go through a full state transition
743138568Ssam	 * which will rebuild this state.
744138568Ssam	 *
745138568Ssam	 * XXX does this leave us open to inheriting old state?
746138568Ssam	 */
747138568Ssam	for (i = 0; i < N(ni->ni_rxfrag); i++)
748138568Ssam		if (ni->ni_rxfrag[i] != NULL) {
749138568Ssam			m_freem(ni->ni_rxfrag[i]);
750138568Ssam			ni->ni_rxfrag[i] = NULL;
751138568Ssam		}
752148863Ssam	/*
753148863Ssam	 * Must be careful here to remove any key map entry w/o a LOR.
754148863Ssam	 */
755148863Ssam	ieee80211_node_delucastkey(ni);
756138568Ssam#undef N
757116742Ssam}
758116742Ssam
759116742Ssamstatic void
760138568Ssamnode_free(struct ieee80211_node *ni)
761116742Ssam{
762138568Ssam	struct ieee80211com *ic = ni->ni_ic;
763138568Ssam
764138568Ssam	ic->ic_node_cleanup(ni);
765138568Ssam	if (ni->ni_wpa_ie != NULL)
766170530Ssam		FREE(ni->ni_wpa_ie, M_80211_NODE);
767170530Ssam	if (ni->ni_rsn_ie != NULL)
768170530Ssam		FREE(ni->ni_rsn_ie, M_80211_NODE);
769138568Ssam	if (ni->ni_wme_ie != NULL)
770170530Ssam		FREE(ni->ni_wme_ie, M_80211_NODE);
771170530Ssam	if (ni->ni_ath_ie != NULL)
772170530Ssam		FREE(ni->ni_ath_ie, M_80211_NODE);
773138568Ssam	IEEE80211_NODE_SAVEQ_DESTROY(ni);
774138568Ssam	FREE(ni, M_80211_NODE);
775116742Ssam}
776116742Ssam
777170530Ssamstatic int8_t
778138568Ssamnode_getrssi(const struct ieee80211_node *ni)
779120104Ssam{
780120104Ssam	return ni->ni_rssi;
781120104Ssam}
782120104Ssam
783116742Ssamstatic void
784170530Ssamnode_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
785170530Ssam{
786170530Ssam	*rssi = ni->ni_rssi;
787170530Ssam	*noise = ni->ni_noise;
788170530Ssam}
789170530Ssam
790170530Ssamstatic void
791138568Ssamieee80211_setup_node(struct ieee80211_node_table *nt,
792170530Ssam	struct ieee80211_node *ni, const uint8_t *macaddr)
793116742Ssam{
794138568Ssam	struct ieee80211com *ic = nt->nt_ic;
795116742Ssam	int hash;
796116742Ssam
797138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
798140766Ssam		"%s %p<%s> in %s table\n", __func__, ni,
799138568Ssam		ether_sprintf(macaddr), nt->nt_name);
800138568Ssam
801116742Ssam	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
802116742Ssam	hash = IEEE80211_NODE_HASH(macaddr);
803138568Ssam	ieee80211_node_initref(ni);		/* mark referenced */
804138568Ssam	ni->ni_chan = IEEE80211_CHAN_ANYC;
805138568Ssam	ni->ni_authmode = IEEE80211_AUTH_OPEN;
806138568Ssam	ni->ni_txpower = ic->ic_txpowlimit;	/* max power */
807138568Ssam	ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE);
808139528Ssam	ni->ni_inact_reload = nt->nt_inact_init;
809139528Ssam	ni->ni_inact = ni->ni_inact_reload;
810170530Ssam	ni->ni_ath_defkeyix = 0x7fff;
811138568Ssam	IEEE80211_NODE_SAVEQ_INIT(ni, "unknown");
812138568Ssam
813138568Ssam	IEEE80211_NODE_LOCK(nt);
814138568Ssam	TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
815138568Ssam	LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
816138568Ssam	ni->ni_table = nt;
817138568Ssam	ni->ni_ic = ic;
818138568Ssam	IEEE80211_NODE_UNLOCK(nt);
819116742Ssam}
820116742Ssam
821116742Ssamstruct ieee80211_node *
822170530Ssamieee80211_alloc_node(struct ieee80211_node_table *nt, const uint8_t *macaddr)
823116742Ssam{
824138568Ssam	struct ieee80211com *ic = nt->nt_ic;
825138568Ssam	struct ieee80211_node *ni;
826138568Ssam
827138568Ssam	ni = ic->ic_node_alloc(nt);
828116742Ssam	if (ni != NULL)
829138568Ssam		ieee80211_setup_node(nt, ni, macaddr);
830127769Ssam	else
831127769Ssam		ic->ic_stats.is_rx_nodealloc++;
832116742Ssam	return ni;
833116742Ssam}
834116742Ssam
835148777Ssam/*
836148777Ssam * Craft a temporary node suitable for sending a management frame
837148777Ssam * to the specified station.  We craft only as much state as we
838148777Ssam * need to do the work since the node will be immediately reclaimed
839148777Ssam * once the send completes.
840148777Ssam */
841116742Ssamstruct ieee80211_node *
842170530Ssamieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr)
843148777Ssam{
844148777Ssam	struct ieee80211_node *ni;
845148777Ssam
846148777Ssam	ni = ic->ic_node_alloc(&ic->ic_sta);
847148777Ssam	if (ni != NULL) {
848148777Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
849148777Ssam			"%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr));
850148777Ssam
851148777Ssam		IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
852148777Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
853148777Ssam		ieee80211_node_initref(ni);		/* mark referenced */
854148777Ssam		ni->ni_txpower = ic->ic_bss->ni_txpower;
855148777Ssam		/* NB: required by ieee80211_fix_rate */
856170530Ssam		ieee80211_node_set_chan(ic, ni);
857148777Ssam		ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey,
858148777Ssam			IEEE80211_KEYIX_NONE);
859148777Ssam		/* XXX optimize away */
860148777Ssam		IEEE80211_NODE_SAVEQ_INIT(ni, "unknown");
861148777Ssam
862148777Ssam		ni->ni_table = NULL;		/* NB: pedantic */
863148777Ssam		ni->ni_ic = ic;
864148777Ssam	} else {
865148777Ssam		/* XXX msg */
866148777Ssam		ic->ic_stats.is_rx_nodealloc++;
867148777Ssam	}
868148777Ssam	return ni;
869148777Ssam}
870148777Ssam
871148777Ssamstruct ieee80211_node *
872170530Ssamieee80211_dup_bss(struct ieee80211_node_table *nt, const uint8_t *macaddr)
873116742Ssam{
874138568Ssam	struct ieee80211com *ic = nt->nt_ic;
875138568Ssam	struct ieee80211_node *ni;
876138568Ssam
877138568Ssam	ni = ic->ic_node_alloc(nt);
878116742Ssam	if (ni != NULL) {
879138568Ssam		ieee80211_setup_node(nt, ni, macaddr);
880127770Ssam		/*
881127770Ssam		 * Inherit from ic_bss.
882127770Ssam		 */
883138568Ssam		ni->ni_authmode = ic->ic_bss->ni_authmode;
884138568Ssam		ni->ni_txpower = ic->ic_bss->ni_txpower;
885138568Ssam		ni->ni_vlan = ic->ic_bss->ni_vlan;	/* XXX?? */
886127770Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
887170530Ssam		ieee80211_node_set_chan(ic, ni);
888138568Ssam		ni->ni_rsn = ic->ic_bss->ni_rsn;
889127770Ssam	} else
890127770Ssam		ic->ic_stats.is_rx_nodealloc++;
891116742Ssam	return ni;
892116742Ssam}
893116742Ssam
894127772Ssamstatic struct ieee80211_node *
895138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
896138568Ssam_ieee80211_find_node_debug(struct ieee80211_node_table *nt,
897170530Ssam	const uint8_t *macaddr, const char *func, int line)
898138568Ssam#else
899138568Ssam_ieee80211_find_node(struct ieee80211_node_table *nt,
900170530Ssam	const uint8_t *macaddr)
901138568Ssam#endif
902116742Ssam{
903116742Ssam	struct ieee80211_node *ni;
904116742Ssam	int hash;
905116742Ssam
906138568Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
907127772Ssam
908116742Ssam	hash = IEEE80211_NODE_HASH(macaddr);
909138568Ssam	LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
910116742Ssam		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
911138568Ssam			ieee80211_ref_node(ni);	/* mark referenced */
912138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
913138568Ssam			IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
914140766Ssam			    "%s (%s:%u) %p<%s> refcnt %d\n", __func__,
915140766Ssam			    func, line,
916140766Ssam			    ni, ether_sprintf(ni->ni_macaddr),
917140766Ssam			    ieee80211_node_refcnt(ni));
918138568Ssam#endif
919127772Ssam			return ni;
920116742Ssam		}
921116742Ssam	}
922127772Ssam	return NULL;
923127772Ssam}
924138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
925138568Ssam#define	_ieee80211_find_node(nt, mac) \
926138568Ssam	_ieee80211_find_node_debug(nt, mac, func, line)
927138568Ssam#endif
928127772Ssam
929127772Ssamstruct ieee80211_node *
930138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
931138568Ssamieee80211_find_node_debug(struct ieee80211_node_table *nt,
932170530Ssam	const uint8_t *macaddr, const char *func, int line)
933138568Ssam#else
934170530Ssamieee80211_find_node(struct ieee80211_node_table *nt, const uint8_t *macaddr)
935138568Ssam#endif
936127772Ssam{
937127772Ssam	struct ieee80211_node *ni;
938127772Ssam
939138568Ssam	IEEE80211_NODE_LOCK(nt);
940138568Ssam	ni = _ieee80211_find_node(nt, macaddr);
941138568Ssam	IEEE80211_NODE_UNLOCK(nt);
942116742Ssam	return ni;
943116742Ssam}
944116742Ssam
945116742Ssam/*
946138568Ssam * Fake up a node; this handles node discovery in adhoc mode.
947138568Ssam * Note that for the driver's benefit we we treat this like
948138568Ssam * an association so the driver has an opportunity to setup
949138568Ssam * it's private state.
950138568Ssam */
951138568Ssamstruct ieee80211_node *
952138568Ssamieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt,
953170530Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
954138568Ssam{
955138568Ssam	struct ieee80211com *ic = nt->nt_ic;
956138568Ssam	struct ieee80211_node *ni;
957138568Ssam
958153073Ssam	IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
959153073Ssam	    "%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
960138568Ssam	ni = ieee80211_dup_bss(nt, macaddr);
961138568Ssam	if (ni != NULL) {
962138568Ssam		/* XXX no rate negotiation; just dup */
963138568Ssam		ni->ni_rates = ic->ic_bss->ni_rates;
964139524Ssam		if (ic->ic_newassoc != NULL)
965148307Ssam			ic->ic_newassoc(ni, 1);
966153404Ssam		if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
967153404Ssam			/*
968170530Ssam			 * In adhoc demo mode there are no management
969170530Ssam			 * frames to use to discover neighbor capabilities,
970170530Ssam			 * so blindly propagate the local configuration
971170530Ssam			 * so we can do interesting things (e.g. use
972170530Ssam			 * WME to disable ACK's).
973153404Ssam			 */
974153404Ssam			if (ic->ic_flags & IEEE80211_F_WME)
975153404Ssam				ni->ni_flags |= IEEE80211_NODE_QOS;
976170530Ssam			if (ic->ic_flags & IEEE80211_F_FF)
977170530Ssam				ni->ni_flags |= IEEE80211_NODE_FF;
978153404Ssam		}
979170530Ssam		/* XXX not right for 802.1x/WPA */
980170530Ssam		ieee80211_node_authorize(ni);
981138568Ssam	}
982138568Ssam	return ni;
983138568Ssam}
984138568Ssam
985148936Ssamvoid
986153073Ssamieee80211_init_neighbor(struct ieee80211_node *ni,
987153073Ssam	const struct ieee80211_frame *wh,
988153073Ssam	const struct ieee80211_scanparams *sp)
989153073Ssam{
990153073Ssam	ni->ni_esslen = sp->ssid[1];
991153073Ssam	memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
992153073Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
993153073Ssam	memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp));
994153073Ssam	ni->ni_intval = sp->bintval;
995153073Ssam	ni->ni_capinfo = sp->capinfo;
996153073Ssam	ni->ni_chan = ni->ni_ic->ic_curchan;
997153073Ssam	ni->ni_fhdwell = sp->fhdwell;
998153073Ssam	ni->ni_fhindex = sp->fhindex;
999153073Ssam	ni->ni_erp = sp->erp;
1000153073Ssam	ni->ni_timoff = sp->timoff;
1001153073Ssam	if (sp->wme != NULL)
1002153073Ssam		ieee80211_saveie(&ni->ni_wme_ie, sp->wme);
1003153073Ssam	if (sp->wpa != NULL)
1004153073Ssam		ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa);
1005170530Ssam	if (sp->rsn != NULL)
1006170530Ssam		ieee80211_saveie(&ni->ni_rsn_ie, sp->rsn);
1007170530Ssam	if (sp->ath != NULL)
1008170530Ssam		ieee80211_saveath(ni, sp->ath);
1009153073Ssam
1010153073Ssam	/* NB: must be after ni_chan is setup */
1011165887Ssam	ieee80211_setup_rates(ni, sp->rates, sp->xrates,
1012165887Ssam		IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1013165887Ssam		IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1014153073Ssam}
1015153073Ssam
1016148936Ssam/*
1017148936Ssam * Do node discovery in adhoc mode on receipt of a beacon
1018148936Ssam * or probe response frame.  Note that for the driver's
1019148936Ssam * benefit we we treat this like an association so the
1020148936Ssam * driver has an opportunity to setup it's private state.
1021148936Ssam */
1022148936Ssamstruct ieee80211_node *
1023148936Ssamieee80211_add_neighbor(struct ieee80211com *ic,
1024148936Ssam	const struct ieee80211_frame *wh,
1025148936Ssam	const struct ieee80211_scanparams *sp)
1026148936Ssam{
1027148936Ssam	struct ieee80211_node *ni;
1028148936Ssam
1029153073Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1030153073Ssam	    "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
1031148936Ssam	ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */
1032148936Ssam	if (ni != NULL) {
1033153073Ssam		ieee80211_init_neighbor(ni, wh, sp);
1034148936Ssam		if (ic->ic_newassoc != NULL)
1035148936Ssam			ic->ic_newassoc(ni, 1);
1036148936Ssam		/* XXX not right for 802.1x/WPA */
1037148936Ssam		ieee80211_node_authorize(ni);
1038148936Ssam	}
1039148936Ssam	return ni;
1040148936Ssam}
1041148936Ssam
1042148863Ssam#define	IS_CTL(wh) \
1043148863Ssam	((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
1044148863Ssam#define	IS_PSPOLL(wh) \
1045148863Ssam	((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
1046170530Ssam#define	IS_BAR(wh) \
1047170530Ssam	((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_BAR)
1048170530Ssam
1049138568Ssam/*
1050138568Ssam * Locate the node for sender, track state, and then pass the
1051138568Ssam * (referenced) node up to the 802.11 layer for its use.  We
1052138568Ssam * are required to pass some node so we fall back to ic_bss
1053138568Ssam * when this frame is from an unknown sender.  The 802.11 layer
1054138568Ssam * knows this means the sender wasn't in the node table and
1055138568Ssam * acts accordingly.
1056138568Ssam */
1057138568Ssamstruct ieee80211_node *
1058138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1059138568Ssamieee80211_find_rxnode_debug(struct ieee80211com *ic,
1060138568Ssam	const struct ieee80211_frame_min *wh, const char *func, int line)
1061138568Ssam#else
1062138568Ssamieee80211_find_rxnode(struct ieee80211com *ic,
1063138568Ssam	const struct ieee80211_frame_min *wh)
1064138568Ssam#endif
1065138568Ssam{
1066138568Ssam	struct ieee80211_node_table *nt;
1067138568Ssam	struct ieee80211_node *ni;
1068138568Ssam
1069138568Ssam	/* XXX check ic_bss first in station mode */
1070138568Ssam	/* XXX 4-address frames? */
1071170530Ssam	nt = &ic->ic_sta;
1072138568Ssam	IEEE80211_NODE_LOCK(nt);
1073170530Ssam	if (IS_CTL(wh) && !IS_PSPOLL(wh) && !IS_BAR(wh) /*&& !IS_RTS(ah)*/)
1074138568Ssam		ni = _ieee80211_find_node(nt, wh->i_addr1);
1075138568Ssam	else
1076138568Ssam		ni = _ieee80211_find_node(nt, wh->i_addr2);
1077148863Ssam	if (ni == NULL)
1078148863Ssam		ni = ieee80211_ref_node(ic->ic_bss);
1079138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1080138568Ssam
1081148863Ssam	return ni;
1082148863Ssam}
1083148863Ssam
1084148863Ssam/*
1085148863Ssam * Like ieee80211_find_rxnode but use the supplied h/w
1086148863Ssam * key index as a hint to locate the node in the key
1087148863Ssam * mapping table.  If an entry is present at the key
1088148863Ssam * index we return it; otherwise do a normal lookup and
1089148863Ssam * update the mapping table if the station has a unicast
1090148863Ssam * key assigned to it.
1091148863Ssam */
1092148863Ssamstruct ieee80211_node *
1093148863Ssam#ifdef IEEE80211_DEBUG_REFCNT
1094148863Ssamieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic,
1095148863Ssam	const struct ieee80211_frame_min *wh, ieee80211_keyix keyix,
1096148863Ssam	const char *func, int line)
1097148863Ssam#else
1098148863Ssamieee80211_find_rxnode_withkey(struct ieee80211com *ic,
1099148863Ssam	const struct ieee80211_frame_min *wh, ieee80211_keyix keyix)
1100148863Ssam#endif
1101148863Ssam{
1102148863Ssam	struct ieee80211_node_table *nt;
1103148863Ssam	struct ieee80211_node *ni;
1104148863Ssam
1105170530Ssam	nt = &ic->ic_sta;
1106148863Ssam	IEEE80211_NODE_LOCK(nt);
1107148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax)
1108148863Ssam		ni = nt->nt_keyixmap[keyix];
1109148863Ssam	else
1110148863Ssam		ni = NULL;
1111148863Ssam	if (ni == NULL) {
1112170530Ssam		if (IS_CTL(wh) && !IS_PSPOLL(wh) && !IS_BAR(wh) /*&& !IS_RTS(ah)*/)
1113148863Ssam			ni = _ieee80211_find_node(nt, wh->i_addr1);
1114148863Ssam		else
1115148863Ssam			ni = _ieee80211_find_node(nt, wh->i_addr2);
1116148863Ssam		if (ni == NULL)
1117148863Ssam			ni = ieee80211_ref_node(ic->ic_bss);
1118148863Ssam		if (nt->nt_keyixmap != NULL) {
1119148863Ssam			/*
1120148863Ssam			 * If the station has a unicast key cache slot
1121148863Ssam			 * assigned update the key->node mapping table.
1122148863Ssam			 */
1123148863Ssam			keyix = ni->ni_ucastkey.wk_rxkeyix;
1124148863Ssam			/* XXX can keyixmap[keyix] != NULL? */
1125148863Ssam			if (keyix < nt->nt_keyixmax &&
1126148863Ssam			    nt->nt_keyixmap[keyix] == NULL) {
1127148863Ssam				IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1128148863Ssam				    "%s: add key map entry %p<%s> refcnt %d\n",
1129148863Ssam				    __func__, ni, ether_sprintf(ni->ni_macaddr),
1130148863Ssam				    ieee80211_node_refcnt(ni)+1);
1131148863Ssam				nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni);
1132148863Ssam			}
1133148863Ssam		}
1134170530Ssam	} else
1135148863Ssam		ieee80211_ref_node(ni);
1136148863Ssam	IEEE80211_NODE_UNLOCK(nt);
1137148863Ssam
1138148863Ssam	return ni;
1139148863Ssam}
1140170530Ssam#undef IS_BAR
1141138568Ssam#undef IS_PSPOLL
1142138568Ssam#undef IS_CTL
1143138568Ssam
1144138568Ssam/*
1145127772Ssam * Return a reference to the appropriate node for sending
1146127772Ssam * a data frame.  This handles node discovery in adhoc networks.
1147127772Ssam */
1148127772Ssamstruct ieee80211_node *
1149138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1150170530Ssamieee80211_find_txnode_debug(struct ieee80211com *ic, const uint8_t *macaddr,
1151138568Ssam	const char *func, int line)
1152138568Ssam#else
1153170530Ssamieee80211_find_txnode(struct ieee80211com *ic, const uint8_t *macaddr)
1154138568Ssam#endif
1155127772Ssam{
1156140753Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1157127772Ssam	struct ieee80211_node *ni;
1158127772Ssam
1159127772Ssam	/*
1160127772Ssam	 * The destination address should be in the node table
1161148863Ssam	 * unless this is a multicast/broadcast frame.  We can
1162148863Ssam	 * also optimize station mode operation, all frames go
1163148863Ssam	 * to the bss node.
1164127772Ssam	 */
1165127772Ssam	/* XXX can't hold lock across dup_bss 'cuz of recursive locking */
1166138568Ssam	IEEE80211_NODE_LOCK(nt);
1167148863Ssam	if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
1168148863Ssam		ni = ieee80211_ref_node(ic->ic_bss);
1169158121Ssam	else {
1170148863Ssam		ni = _ieee80211_find_node(nt, macaddr);
1171158121Ssam		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1172158121Ssam		    (ni != NULL && ni->ni_associd == 0)) {
1173158121Ssam			/*
1174158121Ssam			 * Station is not associated; don't permit the
1175158121Ssam			 * data frame to be sent by returning NULL.  This
1176158121Ssam			 * is kinda a kludge but the least intrusive way
1177158121Ssam			 * to add this check into all drivers.
1178158121Ssam			 */
1179158121Ssam			ieee80211_unref_node(&ni);	/* NB: null's ni */
1180158121Ssam		}
1181158121Ssam	}
1182138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1183138568Ssam
1184138568Ssam	if (ni == NULL) {
1185138568Ssam		if (ic->ic_opmode == IEEE80211_M_IBSS ||
1186140497Ssam		    ic->ic_opmode == IEEE80211_M_AHDEMO) {
1187140497Ssam			/*
1188140497Ssam			 * In adhoc mode cons up a node for the destination.
1189140497Ssam			 * Note that we need an additional reference for the
1190140497Ssam			 * caller to be consistent with _ieee80211_find_node.
1191140497Ssam			 */
1192138568Ssam			ni = ieee80211_fakeup_adhoc_node(nt, macaddr);
1193140497Ssam			if (ni != NULL)
1194140497Ssam				(void) ieee80211_ref_node(ni);
1195140497Ssam		} else {
1196138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
1197138568Ssam				"[%s] no node, discard frame (%s)\n",
1198138568Ssam				ether_sprintf(macaddr), __func__);
1199138568Ssam			ic->ic_stats.is_tx_nonode++;
1200127772Ssam		}
1201127772Ssam	}
1202127772Ssam	return ni;
1203127772Ssam}
1204127772Ssam
1205127772Ssam/*
1206138568Ssam * Like find but search based on the ssid too.
1207138568Ssam */
1208138568Ssamstruct ieee80211_node *
1209138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1210138568Ssamieee80211_find_node_with_ssid_debug(struct ieee80211_node_table *nt,
1211170530Ssam	const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid,
1212138568Ssam	const char *func, int line)
1213138568Ssam#else
1214138568Ssamieee80211_find_node_with_ssid(struct ieee80211_node_table *nt,
1215170530Ssam	const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid)
1216138568Ssam#endif
1217138568Ssam{
1218147118Ssam#define	MATCH_SSID(ni, ssid, ssidlen) \
1219147118Ssam	(ni->ni_esslen == ssidlen && memcmp(ni->ni_essid, ssid, ssidlen) == 0)
1220170530Ssam	static const uint8_t zeromac[IEEE80211_ADDR_LEN];
1221138568Ssam	struct ieee80211_node *ni;
1222138568Ssam	int hash;
1223138568Ssam
1224138568Ssam	IEEE80211_NODE_LOCK(nt);
1225147118Ssam	/*
1226147118Ssam	 * A mac address that is all zero means match only the ssid;
1227147118Ssam	 * otherwise we must match both.
1228147118Ssam	 */
1229147118Ssam	if (IEEE80211_ADDR_EQ(macaddr, zeromac)) {
1230147118Ssam		TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1231147118Ssam			if (MATCH_SSID(ni, ssid, ssidlen))
1232147118Ssam				break;
1233147118Ssam		}
1234147118Ssam	} else {
1235147118Ssam		hash = IEEE80211_NODE_HASH(macaddr);
1236147118Ssam		LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
1237147118Ssam			if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) &&
1238147118Ssam			    MATCH_SSID(ni, ssid, ssidlen))
1239147118Ssam				break;
1240147118Ssam		}
1241147118Ssam	}
1242147118Ssam	if (ni != NULL) {
1243147118Ssam		ieee80211_ref_node(ni);	/* mark referenced */
1244170530Ssam		IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
1245159139Sdds		     REFCNT_LOC, ni, ether_sprintf(ni->ni_macaddr),
1246147118Ssam		     ieee80211_node_refcnt(ni));
1247138568Ssam	}
1248138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1249138568Ssam	return ni;
1250147118Ssam#undef MATCH_SSID
1251138568Ssam}
1252138568Ssam
1253116742Ssamstatic void
1254138568Ssam_ieee80211_free_node(struct ieee80211_node *ni)
1255116742Ssam{
1256138568Ssam	struct ieee80211com *ic = ni->ni_ic;
1257138568Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1258119150Ssam
1259138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1260140766Ssam		"%s %p<%s> in %s table\n", __func__, ni,
1261140766Ssam		ether_sprintf(ni->ni_macaddr),
1262138568Ssam		nt != NULL ? nt->nt_name : "<gone>");
1263138568Ssam
1264138568Ssam	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
1265138568Ssam	if (nt != NULL) {
1266138568Ssam		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
1267138568Ssam		LIST_REMOVE(ni, ni_hash);
1268138568Ssam	}
1269138568Ssam	ic->ic_node_free(ni);
1270116742Ssam}
1271116742Ssam
1272116742Ssamvoid
1273138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1274138568Ssamieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line)
1275138568Ssam#else
1276138568Ssamieee80211_free_node(struct ieee80211_node *ni)
1277138568Ssam#endif
1278116742Ssam{
1279138568Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1280119150Ssam
1281138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1282140454Ssam	IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1283140766Ssam		"%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
1284138568Ssam		 ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1);
1285138568Ssam#endif
1286148863Ssam	if (nt != NULL) {
1287148863Ssam		IEEE80211_NODE_LOCK(nt);
1288148863Ssam		if (ieee80211_node_dectestref(ni)) {
1289148863Ssam			/*
1290148863Ssam			 * Last reference, reclaim state.
1291148863Ssam			 */
1292138568Ssam			_ieee80211_free_node(ni);
1293148863Ssam		} else if (ieee80211_node_refcnt(ni) == 1 &&
1294148863Ssam		    nt->nt_keyixmap != NULL) {
1295148863Ssam			ieee80211_keyix keyix;
1296148863Ssam			/*
1297148863Ssam			 * Check for a last reference in the key mapping table.
1298148863Ssam			 */
1299148863Ssam			keyix = ni->ni_ucastkey.wk_rxkeyix;
1300148863Ssam			if (keyix < nt->nt_keyixmax &&
1301148863Ssam			    nt->nt_keyixmap[keyix] == ni) {
1302148863Ssam				IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1303148863Ssam				    "%s: %p<%s> clear key map entry", __func__,
1304148863Ssam				    ni, ether_sprintf(ni->ni_macaddr));
1305148863Ssam				nt->nt_keyixmap[keyix] = NULL;
1306148863Ssam				ieee80211_node_decref(ni); /* XXX needed? */
1307148863Ssam				_ieee80211_free_node(ni);
1308148863Ssam			}
1309148863Ssam		}
1310148863Ssam		IEEE80211_NODE_UNLOCK(nt);
1311148863Ssam	} else {
1312148863Ssam		if (ieee80211_node_dectestref(ni))
1313138568Ssam			_ieee80211_free_node(ni);
1314116742Ssam	}
1315116742Ssam}
1316116742Ssam
1317138568Ssam/*
1318148863Ssam * Reclaim a unicast key and clear any key cache state.
1319148863Ssam */
1320148863Ssamint
1321148863Ssamieee80211_node_delucastkey(struct ieee80211_node *ni)
1322148863Ssam{
1323148863Ssam	struct ieee80211com *ic = ni->ni_ic;
1324148863Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1325148863Ssam	struct ieee80211_node *nikey;
1326148863Ssam	ieee80211_keyix keyix;
1327148863Ssam	int isowned, status;
1328148863Ssam
1329148863Ssam	/*
1330148863Ssam	 * NB: We must beware of LOR here; deleting the key
1331148863Ssam	 * can cause the crypto layer to block traffic updates
1332148863Ssam	 * which can generate a LOR against the node table lock;
1333148863Ssam	 * grab it here and stash the key index for our use below.
1334148863Ssam	 *
1335148863Ssam	 * Must also beware of recursion on the node table lock.
1336148863Ssam	 * When called from node_cleanup we may already have
1337148863Ssam	 * the node table lock held.  Unfortunately there's no
1338148863Ssam	 * way to separate out this path so we must do this
1339148863Ssam	 * conditionally.
1340148863Ssam	 */
1341148863Ssam	isowned = IEEE80211_NODE_IS_LOCKED(nt);
1342148863Ssam	if (!isowned)
1343148863Ssam		IEEE80211_NODE_LOCK(nt);
1344148863Ssam	keyix = ni->ni_ucastkey.wk_rxkeyix;
1345148863Ssam	status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
1346148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) {
1347148863Ssam		nikey = nt->nt_keyixmap[keyix];
1348148863Ssam		nt->nt_keyixmap[keyix] = NULL;;
1349148863Ssam	} else
1350148863Ssam		nikey = NULL;
1351148863Ssam	if (!isowned)
1352148863Ssam		IEEE80211_NODE_UNLOCK(&ic->ic_sta);
1353148863Ssam
1354148863Ssam	if (nikey != NULL) {
1355148863Ssam		KASSERT(nikey == ni,
1356148863Ssam			("key map out of sync, ni %p nikey %p", ni, nikey));
1357148863Ssam		IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1358148863Ssam			"%s: delete key map entry %p<%s> refcnt %d\n",
1359148863Ssam			__func__, ni, ether_sprintf(ni->ni_macaddr),
1360148863Ssam			ieee80211_node_refcnt(ni)-1);
1361148863Ssam		ieee80211_free_node(ni);
1362148863Ssam	}
1363148863Ssam	return status;
1364148863Ssam}
1365148863Ssam
1366148863Ssam/*
1367138568Ssam * Reclaim a node.  If this is the last reference count then
1368138568Ssam * do the normal free work.  Otherwise remove it from the node
1369138568Ssam * table and mark it gone by clearing the back-reference.
1370138568Ssam */
1371138568Ssamstatic void
1372138568Ssamnode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
1373116742Ssam{
1374148863Ssam	ieee80211_keyix keyix;
1375138568Ssam
1376148863Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
1377148863Ssam
1378140766Ssam	IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1379140766Ssam		"%s: remove %p<%s> from %s table, refcnt %d\n",
1380140766Ssam		__func__, ni, ether_sprintf(ni->ni_macaddr),
1381140766Ssam		nt->nt_name, ieee80211_node_refcnt(ni)-1);
1382148863Ssam	/*
1383148863Ssam	 * Clear any entry in the unicast key mapping table.
1384148863Ssam	 * We need to do it here so rx lookups don't find it
1385148863Ssam	 * in the mapping table even if it's not in the hash
1386148863Ssam	 * table.  We cannot depend on the mapping table entry
1387148863Ssam	 * being cleared because the node may not be free'd.
1388148863Ssam	 */
1389148863Ssam	keyix = ni->ni_ucastkey.wk_rxkeyix;
1390148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
1391148863Ssam	    nt->nt_keyixmap[keyix] == ni) {
1392148863Ssam		IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
1393148863Ssam			"%s: %p<%s> clear key map entry\n",
1394148863Ssam			__func__, ni, ether_sprintf(ni->ni_macaddr));
1395148863Ssam		nt->nt_keyixmap[keyix] = NULL;
1396148863Ssam		ieee80211_node_decref(ni);	/* NB: don't need free */
1397148863Ssam	}
1398138568Ssam	if (!ieee80211_node_dectestref(ni)) {
1399138568Ssam		/*
1400138568Ssam		 * Other references are present, just remove the
1401138568Ssam		 * node from the table so it cannot be found.  When
1402138568Ssam		 * the references are dropped storage will be
1403140753Ssam		 * reclaimed.
1404138568Ssam		 */
1405138568Ssam		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
1406138568Ssam		LIST_REMOVE(ni, ni_hash);
1407138568Ssam		ni->ni_table = NULL;		/* clear reference */
1408138568Ssam	} else
1409138568Ssam		_ieee80211_free_node(ni);
1410138568Ssam}
1411138568Ssam
1412138568Ssamstatic void
1413138568Ssamieee80211_free_allnodes_locked(struct ieee80211_node_table *nt)
1414138568Ssam{
1415138568Ssam	struct ieee80211com *ic = nt->nt_ic;
1416116742Ssam	struct ieee80211_node *ni;
1417116742Ssam
1418138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1419138568Ssam		"%s: free all nodes in %s table\n", __func__, nt->nt_name);
1420138568Ssam
1421138568Ssam	while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) {
1422138568Ssam		if (ni->ni_associd != 0) {
1423138568Ssam			if (ic->ic_auth->ia_node_leave != NULL)
1424138568Ssam				ic->ic_auth->ia_node_leave(ic, ni);
1425138568Ssam			IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
1426138568Ssam		}
1427138568Ssam		node_reclaim(nt, ni);
1428138568Ssam	}
1429116742Ssam}
1430116742Ssam
1431120483Ssam/*
1432138568Ssam * Timeout inactive stations and do related housekeeping.
1433138568Ssam * Note that we cannot hold the node lock while sending a
1434138568Ssam * frame as this would lead to a LOR.  Instead we use a
1435138568Ssam * generation number to mark nodes that we've scanned and
1436138568Ssam * drop the lock and restart a scan if we have to time out
1437138568Ssam * a node.  Since we are single-threaded by virtue of
1438120483Ssam * controlling the inactivity timer we can be sure this will
1439120483Ssam * process each node only once.
1440120483Ssam */
1441138568Ssamstatic void
1442138568Ssamieee80211_timeout_stations(struct ieee80211_node_table *nt)
1443116742Ssam{
1444138568Ssam	struct ieee80211com *ic = nt->nt_ic;
1445120483Ssam	struct ieee80211_node *ni;
1446138568Ssam	u_int gen;
1447148320Ssam	int isadhoc;
1448116742Ssam
1449148320Ssam	isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS ||
1450148320Ssam		   ic->ic_opmode == IEEE80211_M_AHDEMO);
1451138568Ssam	IEEE80211_SCAN_LOCK(nt);
1452154532Ssam	gen = ++nt->nt_scangen;
1453120483Ssamrestart:
1454138568Ssam	IEEE80211_NODE_LOCK(nt);
1455138568Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1456120483Ssam		if (ni->ni_scangen == gen)	/* previously handled */
1457120483Ssam			continue;
1458120483Ssam		ni->ni_scangen = gen;
1459138568Ssam		/*
1460147788Ssam		 * Ignore entries for which have yet to receive an
1461147788Ssam		 * authentication frame.  These are transient and
1462147788Ssam		 * will be reclaimed when the last reference to them
1463147788Ssam		 * goes away (when frame xmits complete).
1464147788Ssam		 */
1465170530Ssam		if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
1466170530Ssam		     ic->ic_opmode == IEEE80211_M_STA) &&
1467148323Ssam		    (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
1468147788Ssam			continue;
1469147788Ssam		/*
1470138568Ssam		 * Free fragment if not needed anymore
1471138568Ssam		 * (last fragment older than 1s).
1472138568Ssam		 * XXX doesn't belong here
1473138568Ssam		 */
1474138568Ssam		if (ni->ni_rxfrag[0] != NULL &&
1475138568Ssam		    ticks > ni->ni_rxfragstamp + hz) {
1476138568Ssam			m_freem(ni->ni_rxfrag[0]);
1477138568Ssam			ni->ni_rxfrag[0] = NULL;
1478138568Ssam		}
1479172062Ssam		if (ni->ni_inact > 0)
1480172062Ssam			ni->ni_inact--;
1481140498Ssam		/*
1482140498Ssam		 * Special case ourself; we may be idle for extended periods
1483140498Ssam		 * of time and regardless reclaiming our state is wrong.
1484140498Ssam		 */
1485140498Ssam		if (ni == ic->ic_bss)
1486140498Ssam			continue;
1487148320Ssam		if (ni->ni_associd != 0 || isadhoc) {
1488119150Ssam			/*
1489170530Ssam			 * Age frames on the power save queue.
1490138568Ssam			 */
1491170530Ssam			if (ieee80211_node_saveq_age(ni) != 0 &&
1492170530Ssam			    IEEE80211_NODE_SAVEQ_QLEN(ni) == 0 &&
1493170530Ssam			    ic->ic_set_tim != NULL)
1494170530Ssam				ic->ic_set_tim(ni, 0);
1495138568Ssam			/*
1496138568Ssam			 * Probe the station before time it out.  We
1497138568Ssam			 * send a null data frame which may not be
1498138568Ssam			 * universally supported by drivers (need it
1499138568Ssam			 * for ps-poll support so it should be...).
1500170530Ssam			 *
1501170530Ssam			 * XXX don't probe the station unless we've
1502170530Ssam			 *     received a frame from them (and have
1503170530Ssam			 *     some idea of the rates they are capable
1504170530Ssam			 *     of); this will get fixed more properly
1505170530Ssam			 *     soon with better handling of the rate set.
1506138568Ssam			 */
1507172062Ssam			if ((ic->ic_flags_ext & IEEE80211_FEXT_INACT) &&
1508172062Ssam			    (0 < ni->ni_inact &&
1509172062Ssam			     ni->ni_inact <= ic->ic_inact_probe) &&
1510170530Ssam			    ni->ni_rates.rs_nrates != 0) {
1511148320Ssam				IEEE80211_NOTE(ic,
1512148320Ssam				    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
1513148320Ssam				    ni, "%s",
1514148320Ssam				    "probe station due to inactivity");
1515148582Ssam				/*
1516148582Ssam				 * Grab a reference before unlocking the table
1517148582Ssam				 * so the node cannot be reclaimed before we
1518148582Ssam				 * send the frame. ieee80211_send_nulldata
1519148582Ssam				 * understands we've done this and reclaims the
1520148582Ssam				 * ref for us as needed.
1521148582Ssam				 */
1522148582Ssam				ieee80211_ref_node(ni);
1523138568Ssam				IEEE80211_NODE_UNLOCK(nt);
1524148301Ssam				ieee80211_send_nulldata(ni);
1525138568Ssam				/* XXX stat? */
1526138568Ssam				goto restart;
1527138568Ssam			}
1528138568Ssam		}
1529172062Ssam		if ((ic->ic_flags_ext & IEEE80211_FEXT_INACT) &&
1530172062Ssam		    ni->ni_inact <= 0) {
1531148320Ssam			IEEE80211_NOTE(ic,
1532148320Ssam			    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
1533148320Ssam			    "station timed out due to inactivity "
1534148320Ssam			    "(refcnt %u)", ieee80211_node_refcnt(ni));
1535138568Ssam			/*
1536138568Ssam			 * Send a deauthenticate frame and drop the station.
1537138568Ssam			 * This is somewhat complicated due to reference counts
1538138568Ssam			 * and locking.  At this point a station will typically
1539138568Ssam			 * have a reference count of 1.  ieee80211_node_leave
1540138568Ssam			 * will do a "free" of the node which will drop the
1541138568Ssam			 * reference count.  But in the meantime a reference
1542138568Ssam			 * wil be held by the deauth frame.  The actual reclaim
1543138568Ssam			 * of the node will happen either after the tx is
1544138568Ssam			 * completed or by ieee80211_node_leave.
1545120483Ssam			 *
1546138568Ssam			 * Separately we must drop the node lock before sending
1547170530Ssam			 * in case the driver takes a lock, as this can result
1548170530Ssam			 * in a LOR between the node lock and the driver lock.
1549119150Ssam			 */
1550138568Ssam			IEEE80211_NODE_UNLOCK(nt);
1551138568Ssam			if (ni->ni_associd != 0) {
1552138568Ssam				IEEE80211_SEND_MGMT(ic, ni,
1553138568Ssam				    IEEE80211_FC0_SUBTYPE_DEAUTH,
1554138568Ssam				    IEEE80211_REASON_AUTH_EXPIRE);
1555138568Ssam			}
1556138568Ssam			ieee80211_node_leave(ic, ni);
1557121180Ssam			ic->ic_stats.is_node_timeout++;
1558120483Ssam			goto restart;
1559120483Ssam		}
1560116742Ssam	}
1561138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1562138568Ssam
1563138568Ssam	IEEE80211_SCAN_UNLOCK(nt);
1564170530Ssam}
1565138568Ssam
1566170530Ssamvoid
1567170530Ssamieee80211_node_timeout(void *arg)
1568170530Ssam{
1569170530Ssam	struct ieee80211com *ic = arg;
1570170530Ssam
1571170530Ssam	ieee80211_scan_timeout(ic);
1572170530Ssam	ieee80211_timeout_stations(&ic->ic_sta);
1573170530Ssam
1574170530Ssam	callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
1575170530Ssam		ieee80211_node_timeout, ic);
1576116742Ssam}
1577116742Ssam
1578116742Ssamvoid
1579138568Ssamieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg)
1580116742Ssam{
1581116742Ssam	struct ieee80211_node *ni;
1582138568Ssam	u_int gen;
1583116742Ssam
1584138568Ssam	IEEE80211_SCAN_LOCK(nt);
1585154532Ssam	gen = ++nt->nt_scangen;
1586138568Ssamrestart:
1587138568Ssam	IEEE80211_NODE_LOCK(nt);
1588138568Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1589138568Ssam		if (ni->ni_scangen != gen) {
1590138568Ssam			ni->ni_scangen = gen;
1591138568Ssam			(void) ieee80211_ref_node(ni);
1592138568Ssam			IEEE80211_NODE_UNLOCK(nt);
1593138568Ssam			(*f)(arg, ni);
1594138568Ssam			ieee80211_free_node(ni);
1595138568Ssam			goto restart;
1596138568Ssam		}
1597138568Ssam	}
1598138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1599138568Ssam
1600138568Ssam	IEEE80211_SCAN_UNLOCK(nt);
1601116742Ssam}
1602138568Ssam
1603138568Ssamvoid
1604138568Ssamieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
1605138568Ssam{
1606138568Ssam	printf("0x%p: mac %s refcnt %d\n", ni,
1607138568Ssam		ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
1608138568Ssam	printf("\tscangen %u authmode %u flags 0x%x\n",
1609138568Ssam		ni->ni_scangen, ni->ni_authmode, ni->ni_flags);
1610138568Ssam	printf("\tassocid 0x%x txpower %u vlan %u\n",
1611138568Ssam		ni->ni_associd, ni->ni_txpower, ni->ni_vlan);
1612138568Ssam	printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n",
1613167439Ssam		ni->ni_txseqs[IEEE80211_NONQOS_TID],
1614167439Ssam		ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT,
1615167439Ssam		ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK,
1616138568Ssam		ni->ni_rxfragstamp);
1617170530Ssam	printf("\trstamp %u rssi %d noise %d intval %u capinfo 0x%x\n",
1618170530Ssam		ni->ni_rstamp, ni->ni_rssi, ni->ni_noise,
1619170530Ssam		ni->ni_intval, ni->ni_capinfo);
1620138568Ssam	printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n",
1621138568Ssam		ether_sprintf(ni->ni_bssid),
1622138568Ssam		ni->ni_esslen, ni->ni_essid,
1623138568Ssam		ni->ni_chan->ic_freq, ni->ni_chan->ic_flags);
1624138568Ssam	printf("\tfails %u inact %u txrate %u\n",
1625138568Ssam		ni->ni_fails, ni->ni_inact, ni->ni_txrate);
1626170530Ssam	printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n",
1627170530Ssam		ni->ni_htcap, ni->ni_htparam,
1628170530Ssam		ni->ni_htctlchan, ni->ni_ht2ndchan);
1629170530Ssam	printf("\thtopmode %x htstbc %x chw %u\n",
1630170530Ssam		ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw);
1631138568Ssam}
1632138568Ssam
1633138568Ssamvoid
1634138568Ssamieee80211_dump_nodes(struct ieee80211_node_table *nt)
1635138568Ssam{
1636138568Ssam	ieee80211_iterate_nodes(nt,
1637138568Ssam		(ieee80211_iter_func *) ieee80211_dump_node, nt);
1638138568Ssam}
1639138568Ssam
1640138568Ssam/*
1641138568Ssam * Handle a station joining an 11g network.
1642138568Ssam */
1643138568Ssamstatic void
1644138568Ssamieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
1645138568Ssam{
1646138568Ssam
1647138568Ssam	/*
1648138568Ssam	 * Station isn't capable of short slot time.  Bump
1649138568Ssam	 * the count of long slot time stations and disable
1650138568Ssam	 * use of short slot time.  Note that the actual switch
1651138568Ssam	 * over to long slot time use may not occur until the
1652138568Ssam	 * next beacon transmission (per sec. 7.3.1.4 of 11g).
1653138568Ssam	 */
1654138568Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
1655138568Ssam		ic->ic_longslotsta++;
1656138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1657138568Ssam		    "[%s] station needs long slot time, count %d\n",
1658138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_longslotsta);
1659138568Ssam		/* XXX vap's w/ conflicting needs won't work */
1660170530Ssam		if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) {
1661170530Ssam			/*
1662170530Ssam			 * Don't force slot time when switched to turbo
1663170530Ssam			 * mode as non-ERP stations won't be present; this
1664170530Ssam			 * need only be done when on the normal G channel.
1665170530Ssam			 */
1666170530Ssam			ieee80211_set_shortslottime(ic, 0);
1667170530Ssam		}
1668138568Ssam	}
1669138568Ssam	/*
1670138568Ssam	 * If the new station is not an ERP station
1671138568Ssam	 * then bump the counter and enable protection
1672138568Ssam	 * if configured.
1673138568Ssam	 */
1674138568Ssam	if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) {
1675138568Ssam		ic->ic_nonerpsta++;
1676138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1677138568Ssam		    "[%s] station is !ERP, %d non-ERP stations associated\n",
1678138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_nonerpsta);
1679138568Ssam		/*
1680138568Ssam		 * If protection is configured, enable it.
1681138568Ssam		 */
1682138568Ssam		if (ic->ic_protmode != IEEE80211_PROT_NONE) {
1683138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1684138568Ssam			    "%s: enable use of protection\n", __func__);
1685138568Ssam			ic->ic_flags |= IEEE80211_F_USEPROT;
1686138568Ssam		}
1687138568Ssam		/*
1688138568Ssam		 * If station does not support short preamble
1689138568Ssam		 * then we must enable use of Barker preamble.
1690138568Ssam		 */
1691138568Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
1692138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1693138568Ssam			    "[%s] station needs long preamble\n",
1694138568Ssam			    ether_sprintf(ni->ni_macaddr));
1695138568Ssam			ic->ic_flags |= IEEE80211_F_USEBARKER;
1696138568Ssam			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
1697138568Ssam		}
1698153973Ssam		if (ic->ic_nonerpsta == 1)
1699153973Ssam			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
1700138568Ssam	} else
1701138568Ssam		ni->ni_flags |= IEEE80211_NODE_ERP;
1702138568Ssam}
1703138568Ssam
1704138568Ssamvoid
1705138568Ssamieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp)
1706138568Ssam{
1707138568Ssam	int newassoc;
1708138568Ssam
1709138568Ssam	if (ni->ni_associd == 0) {
1710170530Ssam		uint16_t aid;
1711138568Ssam
1712138568Ssam		/*
1713138568Ssam		 * It would be good to search the bitmap
1714138568Ssam		 * more efficiently, but this will do for now.
1715138568Ssam		 */
1716138568Ssam		for (aid = 1; aid < ic->ic_max_aid; aid++) {
1717138568Ssam			if (!IEEE80211_AID_ISSET(aid,
1718138568Ssam			    ic->ic_aid_bitmap))
1719138568Ssam				break;
1720138568Ssam		}
1721138568Ssam		if (aid >= ic->ic_max_aid) {
1722138568Ssam			IEEE80211_SEND_MGMT(ic, ni, resp,
1723138568Ssam			    IEEE80211_REASON_ASSOC_TOOMANY);
1724138568Ssam			ieee80211_node_leave(ic, ni);
1725138568Ssam			return;
1726138568Ssam		}
1727138568Ssam		ni->ni_associd = aid | 0xc000;
1728138568Ssam		IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
1729138568Ssam		ic->ic_sta_assoc++;
1730138568Ssam		newassoc = 1;
1731170530Ssam		if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
1732170530Ssam		    IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
1733138568Ssam			ieee80211_node_join_11g(ic, ni);
1734138568Ssam	} else
1735138568Ssam		newassoc = 0;
1736138568Ssam
1737138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG,
1738170530Ssam	    "[%s] station %sassociated at aid %d: %s preamble, %s slot time%s%s%s%s%s\n",
1739139523Ssam	    ether_sprintf(ni->ni_macaddr), newassoc ? "" : "re",
1740139523Ssam	    IEEE80211_NODE_AID(ni),
1741139523Ssam	    ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
1742139523Ssam	    ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long",
1743139523Ssam	    ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "",
1744170530Ssam	    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
1745170530Ssam	    ni->ni_flags & IEEE80211_NODE_HT ?
1746170530Ssam		(ni->ni_chw == 20 ? ", HT20" : ", HT40") : "",
1747170530Ssam	    IEEE80211_ATH_CAP(ic, ni, IEEE80211_NODE_FF) ?
1748170530Ssam		", fast-frames" : "",
1749170530Ssam	    IEEE80211_ATH_CAP(ic, ni, IEEE80211_NODE_TURBOP) ?
1750170530Ssam		", turbo" : ""
1751139523Ssam	);
1752138568Ssam
1753138568Ssam	/* give driver a chance to setup state like ni_txrate */
1754139524Ssam	if (ic->ic_newassoc != NULL)
1755148307Ssam		ic->ic_newassoc(ni, newassoc);
1756138568Ssam	IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
1757138568Ssam	/* tell the authenticator about new station */
1758138568Ssam	if (ic->ic_auth->ia_node_join != NULL)
1759138568Ssam		ic->ic_auth->ia_node_join(ic, ni);
1760138568Ssam	ieee80211_notify_node_join(ic, ni, newassoc);
1761138568Ssam}
1762138568Ssam
1763138568Ssam/*
1764138568Ssam * Handle a station leaving an 11g network.
1765138568Ssam */
1766138568Ssamstatic void
1767138568Ssamieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
1768138568Ssam{
1769138568Ssam
1770170530Ssam	KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan),
1771170530Ssam	     ("not in 11g, bss %u:0x%x, curmode %u", ic->ic_bsschan->ic_freq,
1772170530Ssam	      ic->ic_bsschan->ic_flags, ic->ic_curmode));
1773138568Ssam
1774138568Ssam	/*
1775138568Ssam	 * If a long slot station do the slot time bookkeeping.
1776138568Ssam	 */
1777138568Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
1778138568Ssam		KASSERT(ic->ic_longslotsta > 0,
1779138568Ssam		    ("bogus long slot station count %d", ic->ic_longslotsta));
1780138568Ssam		ic->ic_longslotsta--;
1781138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1782138568Ssam		    "[%s] long slot time station leaves, count now %d\n",
1783138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_longslotsta);
1784138568Ssam		if (ic->ic_longslotsta == 0) {
1785138568Ssam			/*
1786138568Ssam			 * Re-enable use of short slot time if supported
1787138568Ssam			 * and not operating in IBSS mode (per spec).
1788138568Ssam			 */
1789138568Ssam			if ((ic->ic_caps & IEEE80211_C_SHSLOT) &&
1790138568Ssam			    ic->ic_opmode != IEEE80211_M_IBSS) {
1791138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1792138568Ssam				    "%s: re-enable use of short slot time\n",
1793138568Ssam				    __func__);
1794138568Ssam				ieee80211_set_shortslottime(ic, 1);
1795138568Ssam			}
1796138568Ssam		}
1797138568Ssam	}
1798138568Ssam	/*
1799138568Ssam	 * If a non-ERP station do the protection-related bookkeeping.
1800138568Ssam	 */
1801138568Ssam	if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
1802138568Ssam		KASSERT(ic->ic_nonerpsta > 0,
1803138568Ssam		    ("bogus non-ERP station count %d", ic->ic_nonerpsta));
1804138568Ssam		ic->ic_nonerpsta--;
1805138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1806138568Ssam		    "[%s] non-ERP station leaves, count now %d\n",
1807138568Ssam		    ether_sprintf(ni->ni_macaddr), ic->ic_nonerpsta);
1808138568Ssam		if (ic->ic_nonerpsta == 0) {
1809138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1810138568Ssam				"%s: disable use of protection\n", __func__);
1811138568Ssam			ic->ic_flags &= ~IEEE80211_F_USEPROT;
1812138568Ssam			/* XXX verify mode? */
1813138568Ssam			if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
1814138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1815138568Ssam				    "%s: re-enable use of short preamble\n",
1816138568Ssam				    __func__);
1817138568Ssam				ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
1818138568Ssam				ic->ic_flags &= ~IEEE80211_F_USEBARKER;
1819138568Ssam			}
1820153973Ssam			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
1821138568Ssam		}
1822138568Ssam	}
1823138568Ssam}
1824138568Ssam
1825138568Ssam/*
1826138568Ssam * Handle bookkeeping for station deauthentication/disassociation
1827138568Ssam * when operating as an ap.
1828138568Ssam */
1829138568Ssamvoid
1830138568Ssamieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
1831138568Ssam{
1832140499Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1833138568Ssam
1834138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG,
1835138568Ssam	    "[%s] station with aid %d leaves\n",
1836138568Ssam	    ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_AID(ni));
1837138568Ssam
1838170530Ssam	KASSERT(ic->ic_opmode != IEEE80211_M_STA,
1839138568Ssam		("unexpected operating mode %u", ic->ic_opmode));
1840138568Ssam	/*
1841138568Ssam	 * If node wasn't previously associated all
1842138568Ssam	 * we need to do is reclaim the reference.
1843138568Ssam	 */
1844138568Ssam	/* XXX ibss mode bypasses 11g and notification */
1845138568Ssam	if (ni->ni_associd == 0)
1846138568Ssam		goto done;
1847138568Ssam	/*
1848138568Ssam	 * Tell the authenticator the station is leaving.
1849138568Ssam	 * Note that we must do this before yanking the
1850138568Ssam	 * association id as the authenticator uses the
1851138568Ssam	 * associd to locate it's state block.
1852138568Ssam	 */
1853138568Ssam	if (ic->ic_auth->ia_node_leave != NULL)
1854138568Ssam		ic->ic_auth->ia_node_leave(ic, ni);
1855138568Ssam	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
1856138568Ssam	ni->ni_associd = 0;
1857138568Ssam	ic->ic_sta_assoc--;
1858138568Ssam
1859170530Ssam	if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
1860170530Ssam	    IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
1861138568Ssam		ieee80211_node_leave_11g(ic, ni);
1862138568Ssam	/*
1863138568Ssam	 * Cleanup station state.  In particular clear various
1864138568Ssam	 * state that might otherwise be reused if the node
1865138568Ssam	 * is reused before the reference count goes to zero
1866138568Ssam	 * (and memory is reclaimed).
1867138568Ssam	 */
1868138568Ssam	ieee80211_sta_leave(ic, ni);
1869138568Ssamdone:
1870140499Ssam	/*
1871140499Ssam	 * Remove the node from any table it's recorded in and
1872140499Ssam	 * drop the caller's reference.  Removal from the table
1873140499Ssam	 * is important to insure the node is not reprocessed
1874140499Ssam	 * for inactivity.
1875140499Ssam	 */
1876140499Ssam	if (nt != NULL) {
1877140499Ssam		IEEE80211_NODE_LOCK(nt);
1878140499Ssam		node_reclaim(nt, ni);
1879140499Ssam		IEEE80211_NODE_UNLOCK(nt);
1880140499Ssam	} else
1881140499Ssam		ieee80211_free_node(ni);
1882138568Ssam}
1883138568Ssam
1884170530Ssamint8_t
1885138568Ssamieee80211_getrssi(struct ieee80211com *ic)
1886138568Ssam{
1887138568Ssam#define	NZ(x)	((x) == 0 ? 1 : (x))
1888140753Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1889170530Ssam	int rssi_samples;
1890170530Ssam	int32_t rssi_total;
1891138568Ssam	struct ieee80211_node *ni;
1892138568Ssam
1893138568Ssam	rssi_total = 0;
1894138568Ssam	rssi_samples = 0;
1895138568Ssam	switch (ic->ic_opmode) {
1896138568Ssam	case IEEE80211_M_IBSS:		/* average of all ibss neighbors */
1897138568Ssam	case IEEE80211_M_AHDEMO:	/* average of all neighbors */
1898138568Ssam	case IEEE80211_M_HOSTAP:	/* average of all associated stations */
1899138568Ssam		/* XXX locking */
1900140753Ssam		TAILQ_FOREACH(ni, &nt->nt_node, ni_list)
1901170530Ssam			if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
1902170530Ssam			    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS)) {
1903170530Ssam				int8_t rssi = ic->ic_node_getrssi(ni);
1904170530Ssam				if (rssi != 0) {
1905170530Ssam					rssi_samples++;
1906170530Ssam					rssi_total += rssi;
1907170530Ssam				}
1908138568Ssam			}
1909138568Ssam		break;
1910138568Ssam	case IEEE80211_M_MONITOR:	/* XXX */
1911138568Ssam	case IEEE80211_M_STA:		/* use stats from associated ap */
1912138568Ssam	default:
1913138568Ssam		if (ic->ic_bss != NULL)
1914138568Ssam			rssi_total = ic->ic_node_getrssi(ic->ic_bss);
1915138568Ssam		rssi_samples = 1;
1916138568Ssam		break;
1917138568Ssam	}
1918138568Ssam	return rssi_total / NZ(rssi_samples);
1919138568Ssam#undef NZ
1920138568Ssam}
1921138568Ssam
1922170530Ssamvoid
1923170530Ssamieee80211_getsignal(struct ieee80211com *ic, int8_t *rssi, int8_t *noise)
1924138568Ssam{
1925138568Ssam
1926170530Ssam	if (ic->ic_bss == NULL)		/* NB: shouldn't happen */
1927170530Ssam		return;
1928170530Ssam	ic->ic_node_getsignal(ic->ic_bss, rssi, noise);
1929170530Ssam	/* for non-station mode return avg'd rssi accounting */
1930170530Ssam	if (ic->ic_opmode != IEEE80211_M_STA)
1931170530Ssam		*rssi = ieee80211_getrssi(ic);
1932138568Ssam}
1933138568Ssam
1934138568Ssam/*
1935138568Ssam * Node table support.
1936138568Ssam */
1937138568Ssam
1938138568Ssamstatic void
1939138568Ssamieee80211_node_table_init(struct ieee80211com *ic,
1940138568Ssam	struct ieee80211_node_table *nt,
1941170530Ssam	const char *name, int inact, int keyixmax)
1942138568Ssam{
1943138568Ssam
1944138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1945138568Ssam		"%s %s table, inact %u\n", __func__, name, inact);
1946138568Ssam
1947138568Ssam	nt->nt_ic = ic;
1948138568Ssam	/* XXX need unit */
1949138568Ssam	IEEE80211_NODE_LOCK_INIT(nt, ic->ic_ifp->if_xname);
1950138568Ssam	IEEE80211_SCAN_LOCK_INIT(nt, ic->ic_ifp->if_xname);
1951138568Ssam	TAILQ_INIT(&nt->nt_node);
1952138568Ssam	nt->nt_name = name;
1953138568Ssam	nt->nt_scangen = 1;
1954138568Ssam	nt->nt_inact_init = inact;
1955148863Ssam	nt->nt_keyixmax = keyixmax;
1956148863Ssam	if (nt->nt_keyixmax > 0) {
1957148863Ssam		MALLOC(nt->nt_keyixmap, struct ieee80211_node **,
1958148863Ssam			keyixmax * sizeof(struct ieee80211_node *),
1959148863Ssam			M_80211_NODE, M_NOWAIT | M_ZERO);
1960148863Ssam		if (nt->nt_keyixmap == NULL)
1961148863Ssam			if_printf(ic->ic_ifp,
1962148863Ssam			    "Cannot allocate key index map with %u entries\n",
1963148863Ssam			    keyixmax);
1964148863Ssam	} else
1965148863Ssam		nt->nt_keyixmap = NULL;
1966138568Ssam}
1967138568Ssam
1968170530Ssamstatic void
1969138568Ssamieee80211_node_table_reset(struct ieee80211_node_table *nt)
1970138568Ssam{
1971138568Ssam
1972138568Ssam	IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
1973138568Ssam		"%s %s table\n", __func__, nt->nt_name);
1974138568Ssam
1975138568Ssam	IEEE80211_NODE_LOCK(nt);
1976138568Ssam	ieee80211_free_allnodes_locked(nt);
1977138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1978138568Ssam}
1979138568Ssam
1980138568Ssamstatic void
1981138568Ssamieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
1982138568Ssam{
1983138568Ssam
1984138568Ssam	IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
1985138568Ssam		"%s %s table\n", __func__, nt->nt_name);
1986138568Ssam
1987148863Ssam	IEEE80211_NODE_LOCK(nt);
1988138568Ssam	ieee80211_free_allnodes_locked(nt);
1989148863Ssam	if (nt->nt_keyixmap != NULL) {
1990148863Ssam		/* XXX verify all entries are NULL */
1991148863Ssam		int i;
1992148863Ssam		for (i = 0; i < nt->nt_keyixmax; i++)
1993148863Ssam			if (nt->nt_keyixmap[i] != NULL)
1994148863Ssam				printf("%s: %s[%u] still active\n", __func__,
1995148863Ssam					nt->nt_name, i);
1996148863Ssam		FREE(nt->nt_keyixmap, M_80211_NODE);
1997148863Ssam		nt->nt_keyixmap = NULL;
1998148863Ssam	}
1999138568Ssam	IEEE80211_SCAN_LOCK_DESTROY(nt);
2000138568Ssam	IEEE80211_NODE_LOCK_DESTROY(nt);
2001138568Ssam}
2002