ieee80211_node.c revision 297733
1116742Ssam/*-
2116904Ssam * Copyright (c) 2001 Atsushi Onoe
3186904Ssam * Copyright (c) 2002-2009 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 297733 2016-04-09 09:31:28Z bz $");
29116742Ssam
30178354Ssam#include "opt_wlan.h"
31178354Ssam
32116742Ssam#include <sys/param.h>
33116742Ssam#include <sys/systm.h>
34116742Ssam#include <sys/mbuf.h>
35116742Ssam#include <sys/malloc.h>
36116742Ssam#include <sys/kernel.h>
37138568Ssam
38116742Ssam#include <sys/socket.h>
39116742Ssam
40116742Ssam#include <net/if.h>
41257176Sglebius#include <net/if_var.h>
42116742Ssam#include <net/if_media.h>
43116742Ssam#include <net/ethernet.h>
44116742Ssam
45116742Ssam#include <net80211/ieee80211_var.h>
46178354Ssam#include <net80211/ieee80211_input.h>
47190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG
48190391Ssam#include <net80211/ieee80211_superg.h>
49190391Ssam#endif
50186904Ssam#ifdef IEEE80211_SUPPORT_TDMA
51186904Ssam#include <net80211/ieee80211_tdma.h>
52186904Ssam#endif
53178354Ssam#include <net80211/ieee80211_wds.h>
54195618Srpaulo#include <net80211/ieee80211_mesh.h>
55206358Srpaulo#include <net80211/ieee80211_ratectl.h>
56116742Ssam
57116742Ssam#include <net/bpf.h>
58116742Ssam
59147221Ssam/*
60195618Srpaulo * IEEE80211_NODE_HASHSIZE must be a power of 2.
61195618Srpaulo */
62195618SrpauloCTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0);
63195618Srpaulo
64195618Srpaulo/*
65147221Ssam * Association id's are managed with a bit vector.
66147221Ssam */
67178354Ssam#define	IEEE80211_AID_SET(_vap, b) \
68178354Ssam	((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] |= \
69178354Ssam		(1 << (IEEE80211_AID(b) % 32)))
70178354Ssam#define	IEEE80211_AID_CLR(_vap, b) \
71178354Ssam	((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] &= \
72178354Ssam		~(1 << (IEEE80211_AID(b) % 32)))
73178354Ssam#define	IEEE80211_AID_ISSET(_vap, b) \
74178354Ssam	((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32)))
75147221Ssam
76159139Sdds#ifdef IEEE80211_DEBUG_REFCNT
77159139Sdds#define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line
78159139Sdds#else
79159139Sdds#define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__
80159139Sdds#endif
81159139Sdds
82170530Ssamstatic int ieee80211_sta_join1(struct ieee80211_node *);
83170530Ssam
84179643Ssamstatic struct ieee80211_node *node_alloc(struct ieee80211vap *,
85179643Ssam	const uint8_t [IEEE80211_ADDR_LEN]);
86138568Ssamstatic void node_cleanup(struct ieee80211_node *);
87138568Ssamstatic void node_free(struct ieee80211_node *);
88178354Ssamstatic void node_age(struct ieee80211_node *);
89170530Ssamstatic int8_t node_getrssi(const struct ieee80211_node *);
90170530Ssamstatic void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *);
91178354Ssamstatic void node_getmimoinfo(const struct ieee80211_node *,
92178354Ssam	struct ieee80211_mimo_info *);
93116742Ssam
94138568Ssamstatic void _ieee80211_free_node(struct ieee80211_node *);
95120104Ssam
96282372Sadrianstatic void node_reclaim(struct ieee80211_node_table *nt,
97282372Sadrian	struct ieee80211_node *ni);
98138568Ssamstatic void ieee80211_node_table_init(struct ieee80211com *ic,
99148863Ssam	struct ieee80211_node_table *nt, const char *name,
100170530Ssam	int inact, int keymaxix);
101178354Ssamstatic void ieee80211_node_table_reset(struct ieee80211_node_table *,
102178354Ssam	struct ieee80211vap *);
103138568Ssamstatic void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
104172211Ssamstatic void ieee80211_erp_timeout(struct ieee80211com *);
105138568Ssam
106127876SsamMALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
107178354SsamMALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie");
108120481Ssam
109116742Ssamvoid
110138568Ssamieee80211_node_attach(struct ieee80211com *ic)
111116742Ssam{
112195379Ssam	/* XXX really want maxlen enforced per-sta */
113195379Ssam	ieee80211_ageq_init(&ic->ic_stageq, ic->ic_max_keyix * 8,
114195379Ssam	    "802.11 staging q");
115178354Ssam	ieee80211_node_table_init(ic, &ic->ic_sta, "station",
116178354Ssam		IEEE80211_INACT_INIT, ic->ic_max_keyix);
117283291Sjkim	callout_init(&ic->ic_inact, 1);
118178354Ssam	callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
119178354Ssam		ieee80211_node_timeout, ic);
120116742Ssam
121138568Ssam	ic->ic_node_alloc = node_alloc;
122138568Ssam	ic->ic_node_free = node_free;
123138568Ssam	ic->ic_node_cleanup = node_cleanup;
124178354Ssam	ic->ic_node_age = node_age;
125178354Ssam	ic->ic_node_drain = node_age;		/* NB: same as age */
126138568Ssam	ic->ic_node_getrssi = node_getrssi;
127170530Ssam	ic->ic_node_getsignal = node_getsignal;
128178354Ssam	ic->ic_node_getmimoinfo = node_getmimoinfo;
129138568Ssam
130178354Ssam	/*
131178354Ssam	 * Set flags to be propagated to all vap's;
132178354Ssam	 * these define default behaviour/configuration.
133178354Ssam	 */
134178354Ssam	ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */
135178354Ssam}
136138568Ssam
137178354Ssamvoid
138178354Ssamieee80211_node_detach(struct ieee80211com *ic)
139178354Ssam{
140170530Ssam
141178354Ssam	callout_drain(&ic->ic_inact);
142178354Ssam	ieee80211_node_table_cleanup(&ic->ic_sta);
143195379Ssam	ieee80211_ageq_cleanup(&ic->ic_stageq);
144178354Ssam}
145172062Ssam
146178354Ssamvoid
147178354Ssamieee80211_node_vattach(struct ieee80211vap *vap)
148178354Ssam{
149178354Ssam	/* NB: driver can override */
150178354Ssam	vap->iv_max_aid = IEEE80211_AID_DEF;
151178354Ssam
152178354Ssam	/* default station inactivity timer setings */
153178354Ssam	vap->iv_inact_init = IEEE80211_INACT_INIT;
154178354Ssam	vap->iv_inact_auth = IEEE80211_INACT_AUTH;
155178354Ssam	vap->iv_inact_run = IEEE80211_INACT_RUN;
156178354Ssam	vap->iv_inact_probe = IEEE80211_INACT_PROBE;
157184277Ssam
158184277Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_INACT,
159184277Ssam	    "%s: init %u auth %u run %u probe %u\n", __func__,
160184277Ssam	    vap->iv_inact_init, vap->iv_inact_auth,
161184277Ssam	    vap->iv_inact_run, vap->iv_inact_probe);
162148863Ssam}
163148863Ssam
164148863Ssamvoid
165178354Ssamieee80211_node_latevattach(struct ieee80211vap *vap)
166148863Ssam{
167178354Ssam	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
168178354Ssam		/* XXX should we allow max aid to be zero? */
169178354Ssam		if (vap->iv_max_aid < IEEE80211_AID_MIN) {
170178354Ssam			vap->iv_max_aid = IEEE80211_AID_MIN;
171178354Ssam			if_printf(vap->iv_ifp,
172178354Ssam			    "WARNING: max aid too small, changed to %d\n",
173178354Ssam			    vap->iv_max_aid);
174178354Ssam		}
175283538Sadrian		vap->iv_aid_bitmap = (uint32_t *) IEEE80211_MALLOC(
176184210Sdes			howmany(vap->iv_max_aid, 32) * sizeof(uint32_t),
177283538Sadrian			M_80211_NODE,
178283538Sadrian			IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
179178354Ssam		if (vap->iv_aid_bitmap == NULL) {
180178354Ssam			/* XXX no way to recover */
181178354Ssam			printf("%s: no memory for AID bitmap, max aid %d!\n",
182178354Ssam			    __func__, vap->iv_max_aid);
183178354Ssam			vap->iv_max_aid = 0;
184178354Ssam		}
185138568Ssam	}
186138568Ssam
187178354Ssam	ieee80211_reset_bss(vap);
188118887Ssam
189178354Ssam	vap->iv_auth = ieee80211_authenticator_get(vap->iv_bss->ni_authmode);
190116742Ssam}
191116742Ssam
192116742Ssamvoid
193178354Ssamieee80211_node_vdetach(struct ieee80211vap *vap)
194116742Ssam{
195178354Ssam	struct ieee80211com *ic = vap->iv_ic;
196116742Ssam
197178354Ssam	ieee80211_node_table_reset(&ic->ic_sta, vap);
198178354Ssam	if (vap->iv_bss != NULL) {
199178354Ssam		ieee80211_free_node(vap->iv_bss);
200178354Ssam		vap->iv_bss = NULL;
201138568Ssam	}
202178354Ssam	if (vap->iv_aid_bitmap != NULL) {
203283538Sadrian		IEEE80211_FREE(vap->iv_aid_bitmap, M_80211_NODE);
204178354Ssam		vap->iv_aid_bitmap = NULL;
205138568Ssam	}
206116742Ssam}
207116742Ssam
208138568Ssam/*
209138568Ssam * Port authorize/unauthorize interfaces for use by an authenticator.
210138568Ssam */
211138568Ssam
212138568Ssamvoid
213148302Ssamieee80211_node_authorize(struct ieee80211_node *ni)
214138568Ssam{
215184277Ssam	struct ieee80211vap *vap = ni->ni_vap;
216184277Ssam
217138568Ssam	ni->ni_flags |= IEEE80211_NODE_AUTH;
218184277Ssam	ni->ni_inact_reload = vap->iv_inact_run;
219172062Ssam	ni->ni_inact = ni->ni_inact_reload;
220184277Ssam
221184277Ssam	IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
222184277Ssam	    "%s: inact_reload %u", __func__, ni->ni_inact_reload);
223138568Ssam}
224138568Ssam
225138568Ssamvoid
226148302Ssamieee80211_node_unauthorize(struct ieee80211_node *ni)
227138568Ssam{
228184277Ssam	struct ieee80211vap *vap = ni->ni_vap;
229184277Ssam
230138568Ssam	ni->ni_flags &= ~IEEE80211_NODE_AUTH;
231184277Ssam	ni->ni_inact_reload = vap->iv_inact_auth;
232172062Ssam	if (ni->ni_inact > ni->ni_inact_reload)
233172062Ssam		ni->ni_inact = ni->ni_inact_reload;
234184277Ssam
235184277Ssam	IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
236184277Ssam	    "%s: inact_reload %u inact %u", __func__,
237184277Ssam	    ni->ni_inact_reload, ni->ni_inact);
238138568Ssam}
239138568Ssam
240116742Ssam/*
241183251Ssam * Fix tx parameters for a node according to ``association state''.
242183251Ssam */
243193966Ssamvoid
244193966Ssamieee80211_node_setuptxparms(struct ieee80211_node *ni)
245183251Ssam{
246183251Ssam	struct ieee80211vap *vap = ni->ni_vap;
247187898Ssam	enum ieee80211_phymode mode;
248183251Ssam
249183251Ssam	if (ni->ni_flags & IEEE80211_NODE_HT) {
250183251Ssam		if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
251187898Ssam			mode = IEEE80211_MODE_11NA;
252183251Ssam		else
253187898Ssam			mode = IEEE80211_MODE_11NG;
254183251Ssam	} else {				/* legacy rate handling */
255187898Ssam		if (IEEE80211_IS_CHAN_ST(ni->ni_chan))
256187898Ssam			mode = IEEE80211_MODE_STURBO_A;
257188782Ssam		else if (IEEE80211_IS_CHAN_HALF(ni->ni_chan))
258188782Ssam			mode = IEEE80211_MODE_HALF;
259188782Ssam		else if (IEEE80211_IS_CHAN_QUARTER(ni->ni_chan))
260188782Ssam			mode = IEEE80211_MODE_QUARTER;
261191015Ssam		/* NB: 108A should be handled as 11a */
262187898Ssam		else if (IEEE80211_IS_CHAN_A(ni->ni_chan))
263187898Ssam			mode = IEEE80211_MODE_11A;
264191015Ssam		else if (IEEE80211_IS_CHAN_108G(ni->ni_chan) ||
265191015Ssam		    (ni->ni_flags & IEEE80211_NODE_ERP))
266187898Ssam			mode = IEEE80211_MODE_11G;
267183251Ssam		else
268187898Ssam			mode = IEEE80211_MODE_11B;
269183251Ssam	}
270187898Ssam	ni->ni_txparms = &vap->iv_txparms[mode];
271183251Ssam}
272183251Ssam
273183251Ssam/*
274138568Ssam * Set/change the channel.  The rate set is also updated as
275138568Ssam * to insure a consistent view by drivers.
276178354Ssam * XXX should be private but hostap needs it to deal with CSA
277138568Ssam */
278178354Ssamvoid
279178354Ssamieee80211_node_set_chan(struct ieee80211_node *ni,
280178354Ssam	struct ieee80211_channel *chan)
281138568Ssam{
282178354Ssam	struct ieee80211com *ic = ni->ni_ic;
283183251Ssam	struct ieee80211vap *vap = ni->ni_vap;
284183251Ssam	enum ieee80211_phymode mode;
285170530Ssam
286178354Ssam	KASSERT(chan != IEEE80211_CHAN_ANYC, ("no channel"));
287178354Ssam
288138568Ssam	ni->ni_chan = chan;
289183251Ssam	mode = ieee80211_chan2mode(chan);
290170530Ssam	if (IEEE80211_IS_CHAN_HT(chan)) {
291170530Ssam		/*
292219602Sbschmidt		 * We must install the legacy rate est in ni_rates and the
293170530Ssam		 * HT rate set in ni_htrates.
294170530Ssam		 */
295170530Ssam		ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan);
296183251Ssam		/*
297183251Ssam		 * Setup bss tx parameters based on operating mode.  We
298183251Ssam		 * use legacy rates when operating in a mixed HT+non-HT bss
299183251Ssam		 * and non-ERP rates in 11g for mixed ERP+non-ERP bss.
300183251Ssam		 */
301183251Ssam		if (mode == IEEE80211_MODE_11NA &&
302193655Ssam		    (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0)
303183251Ssam			mode = IEEE80211_MODE_11A;
304183251Ssam		else if (mode == IEEE80211_MODE_11NG &&
305193655Ssam		    (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0)
306183251Ssam			mode = IEEE80211_MODE_11G;
307183251Ssam		if (mode == IEEE80211_MODE_11G &&
308183251Ssam		    (vap->iv_flags & IEEE80211_F_PUREG) == 0)
309183251Ssam			mode = IEEE80211_MODE_11B;
310170530Ssam	}
311183251Ssam	ni->ni_txparms = &vap->iv_txparms[mode];
312165569Ssam	ni->ni_rates = *ieee80211_get_suprates(ic, chan);
313138568Ssam}
314138568Ssam
315141658Ssamstatic __inline void
316141658Ssamcopy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss)
317141658Ssam{
318141658Ssam	/* propagate useful state */
319141658Ssam	nbss->ni_authmode = obss->ni_authmode;
320141658Ssam	nbss->ni_txpower = obss->ni_txpower;
321141658Ssam	nbss->ni_vlan = obss->ni_vlan;
322141658Ssam	/* XXX statistics? */
323178354Ssam	/* XXX legacy WDS bssid? */
324141658Ssam}
325141658Ssam
326116742Ssamvoid
327178354Ssamieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
328116742Ssam{
329178354Ssam	struct ieee80211com *ic = vap->iv_ic;
330116742Ssam	struct ieee80211_node *ni;
331116742Ssam
332178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
333297731Sadrian		"%s: creating %s on channel %u%c\n", __func__,
334195618Srpaulo		ieee80211_opmode_name[vap->iv_opmode],
335297731Sadrian		ieee80211_chan2ieee(ic, chan),
336297731Sadrian		ieee80211_channel_type_char(chan));
337138568Ssam
338178354Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
339140753Ssam	if (ni == NULL) {
340140753Ssam		/* XXX recovery? */
341138568Ssam		return;
342138568Ssam	}
343178354Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
344178354Ssam	ni->ni_esslen = vap->iv_des_ssid[0].len;
345178354Ssam	memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen);
346178354Ssam	if (vap->iv_bss != NULL)
347178354Ssam		copy_bss(ni, vap->iv_bss);
348148843Ssam	ni->ni_intval = ic->ic_bintval;
349178354Ssam	if (vap->iv_flags & IEEE80211_F_PRIVACY)
350116742Ssam		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
351116742Ssam	if (ic->ic_phytype == IEEE80211_T_FH) {
352116742Ssam		ni->ni_fhdwell = 200;	/* XXX */
353116742Ssam		ni->ni_fhindex = 1;
354116742Ssam	}
355178354Ssam	if (vap->iv_opmode == IEEE80211_M_IBSS) {
356178354Ssam		vap->iv_flags |= IEEE80211_F_SIBSS;
357138568Ssam		ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS;	/* XXX */
358178354Ssam		if (vap->iv_flags & IEEE80211_F_DESBSSID)
359178354Ssam			IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid);
360167282Ssam		else {
361167282Ssam			get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN);
362167282Ssam			/* clear group bit, add local bit */
363167282Ssam			ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02;
364167282Ssam		}
365178354Ssam	} else if (vap->iv_opmode == IEEE80211_M_AHDEMO) {
366178354Ssam		if (vap->iv_flags & IEEE80211_F_DESBSSID)
367178354Ssam			IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid);
368153403Ssam		else
369186904Ssam#ifdef IEEE80211_SUPPORT_TDMA
370186904Ssam		if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
371186904Ssam#endif
372153403Ssam			memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
373195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
374195618Srpaulo	} else if (vap->iv_opmode == IEEE80211_M_MBSS) {
375195618Srpaulo		ni->ni_meshidlen = vap->iv_mesh->ms_idlen;
376195618Srpaulo		memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen);
377195618Srpaulo#endif
378138568Ssam	}
379138568Ssam	/*
380138568Ssam	 * Fix the channel and related attributes.
381138568Ssam	 */
382178354Ssam	/* clear DFS CAC state on previous channel */
383178354Ssam	if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
384178354Ssam	    ic->ic_bsschan->ic_freq != chan->ic_freq &&
385178354Ssam	    IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan))
386178354Ssam		ieee80211_dfs_cac_clear(ic, ic->ic_bsschan);
387170530Ssam	ic->ic_bsschan = chan;
388178354Ssam	ieee80211_node_set_chan(ni, chan);
389170530Ssam	ic->ic_curmode = ieee80211_chan2mode(chan);
390138568Ssam	/*
391178354Ssam	 * Do mode-specific setup.
392138568Ssam	 */
393170530Ssam	if (IEEE80211_IS_CHAN_FULL(chan)) {
394170530Ssam		if (IEEE80211_IS_CHAN_ANYG(chan)) {
395170530Ssam			/*
396178354Ssam			 * Use a mixed 11b/11g basic rate set.
397170530Ssam			 */
398178354Ssam			ieee80211_setbasicrates(&ni->ni_rates,
399178354Ssam			    IEEE80211_MODE_11G);
400178354Ssam			if (vap->iv_flags & IEEE80211_F_PUREG) {
401178354Ssam				/*
402178354Ssam				 * Also mark OFDM rates basic so 11b
403178354Ssam				 * stations do not join (WiFi compliance).
404178354Ssam				 */
405178354Ssam				ieee80211_addbasicrates(&ni->ni_rates,
406178354Ssam				    IEEE80211_MODE_11A);
407178354Ssam			}
408170530Ssam		} else if (IEEE80211_IS_CHAN_B(chan)) {
409170530Ssam			/*
410170530Ssam			 * Force pure 11b rate set.
411170530Ssam			 */
412178354Ssam			ieee80211_setbasicrates(&ni->ni_rates,
413170530Ssam				IEEE80211_MODE_11B);
414170530Ssam		}
415170530Ssam	}
416138568Ssam
417170530Ssam	(void) ieee80211_sta_join1(ieee80211_ref_node(ni));
418116742Ssam}
419116742Ssam
420170530Ssam/*
421170530Ssam * Reset bss state on transition to the INIT state.
422170530Ssam * Clear any stations from the table (they have been
423170530Ssam * deauth'd) and reset the bss node (clears key, rate
424170530Ssam * etc. state).
425170530Ssam */
426138568Ssamvoid
427178354Ssamieee80211_reset_bss(struct ieee80211vap *vap)
428138568Ssam{
429178354Ssam	struct ieee80211com *ic = vap->iv_ic;
430138568Ssam	struct ieee80211_node *ni, *obss;
431138568Ssam
432178354Ssam	ieee80211_node_table_reset(&ic->ic_sta, vap);
433178354Ssam	/* XXX multi-bss: wrong */
434170530Ssam	ieee80211_reset_erp(ic);
435140753Ssam
436178354Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
437207322Srpaulo	KASSERT(ni != NULL, ("unable to setup initial BSS node"));
438178354Ssam	obss = vap->iv_bss;
439178354Ssam	vap->iv_bss = ieee80211_ref_node(ni);
440141658Ssam	if (obss != NULL) {
441141658Ssam		copy_bss(ni, obss);
442148843Ssam		ni->ni_intval = ic->ic_bintval;
443138568Ssam		ieee80211_free_node(obss);
444178354Ssam	} else
445178354Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
446138568Ssam}
447138568Ssam
448170530Ssamstatic int
449170530Ssammatch_ssid(const struct ieee80211_node *ni,
450170530Ssam	int nssid, const struct ieee80211_scan_ssid ssids[])
451170530Ssam{
452170530Ssam	int i;
453148432Ssam
454170530Ssam	for (i = 0; i < nssid; i++) {
455170530Ssam		if (ni->ni_esslen == ssids[i].len &&
456170530Ssam		     memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0)
457170530Ssam			return 1;
458170530Ssam	}
459170530Ssam	return 0;
460170530Ssam}
461170530Ssam
462170530Ssam/*
463170530Ssam * Test a node for suitability/compatibility.
464170530Ssam */
465127767Ssamstatic int
466178354Ssamcheck_bss(struct ieee80211vap *vap, struct ieee80211_node *ni)
467127767Ssam{
468178354Ssam	struct ieee80211com *ic = ni->ni_ic;
469170530Ssam        uint8_t rate;
470170530Ssam
471170530Ssam	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
472170530Ssam		return 0;
473178354Ssam	if (vap->iv_opmode == IEEE80211_M_IBSS) {
474170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
475170530Ssam			return 0;
476170530Ssam	} else {
477170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
478170530Ssam			return 0;
479170530Ssam	}
480178354Ssam	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
481170530Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
482170530Ssam			return 0;
483170530Ssam	} else {
484170530Ssam		/* XXX does this mean privacy is supported or required? */
485170530Ssam		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
486170530Ssam			return 0;
487170530Ssam	}
488170530Ssam	rate = ieee80211_fix_rate(ni, &ni->ni_rates,
489170530Ssam	    IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
490170530Ssam	if (rate & IEEE80211_RATE_BASIC)
491170530Ssam		return 0;
492178354Ssam	if (vap->iv_des_nssid != 0 &&
493178354Ssam	    !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid))
494170530Ssam		return 0;
495178354Ssam	if ((vap->iv_flags & IEEE80211_F_DESBSSID) &&
496178354Ssam	    !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid))
497170530Ssam		return 0;
498170530Ssam	return 1;
499170530Ssam}
500170530Ssam
501170530Ssam#ifdef IEEE80211_DEBUG
502170530Ssam/*
503170530Ssam * Display node suitability/compatibility.
504170530Ssam */
505170530Ssamstatic void
506178354Ssamcheck_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni)
507170530Ssam{
508178354Ssam	struct ieee80211com *ic = ni->ni_ic;
509170530Ssam        uint8_t rate;
510127767Ssam        int fail;
511127767Ssam
512127767Ssam	fail = 0;
513127767Ssam	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
514127767Ssam		fail |= 0x01;
515178354Ssam	if (vap->iv_opmode == IEEE80211_M_IBSS) {
516127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
517127767Ssam			fail |= 0x02;
518127767Ssam	} else {
519127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
520127767Ssam			fail |= 0x02;
521127767Ssam	}
522178354Ssam	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
523127767Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
524127767Ssam			fail |= 0x04;
525127767Ssam	} else {
526127767Ssam		/* XXX does this mean privacy is supported or required? */
527127767Ssam		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
528127767Ssam			fail |= 0x04;
529127767Ssam	}
530167442Ssam	rate = ieee80211_fix_rate(ni, &ni->ni_rates,
531165887Ssam	     IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
532127767Ssam	if (rate & IEEE80211_RATE_BASIC)
533127767Ssam		fail |= 0x08;
534178354Ssam	if (vap->iv_des_nssid != 0 &&
535178354Ssam	    !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid))
536127767Ssam		fail |= 0x10;
537178354Ssam	if ((vap->iv_flags & IEEE80211_F_DESBSSID) &&
538178354Ssam	    !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid))
539127767Ssam		fail |= 0x20;
540127767Ssam
541170530Ssam	printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr));
542170530Ssam	printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' ');
543170530Ssam	printf(" %3d%c",
544170530Ssam	    ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' ');
545170530Ssam	printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
546170530Ssam	    fail & 0x08 ? '!' : ' ');
547170530Ssam	printf(" %4s%c",
548170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
549170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
550170530Ssam	    "????",
551170530Ssam	    fail & 0x02 ? '!' : ' ');
552170530Ssam	printf(" %3s%c ",
553170530Ssam	    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?  "wep" : "no",
554170530Ssam	    fail & 0x04 ? '!' : ' ');
555170530Ssam	ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
556170530Ssam	printf("%s\n", fail & 0x10 ? "!" : "");
557138568Ssam}
558170530Ssam#endif /* IEEE80211_DEBUG */
559138568Ssam
560297728Sadrian
561297728Sadrianint
562297728Sadrianieee80211_ibss_merge_check(struct ieee80211_node *ni)
563297728Sadrian{
564297728Sadrian	struct ieee80211vap *vap = ni->ni_vap;
565297728Sadrian
566297728Sadrian	if (ni == vap->iv_bss ||
567297728Sadrian	    IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) {
568297728Sadrian		/* unchanged, nothing to do */
569297728Sadrian		return 0;
570297728Sadrian	}
571297728Sadrian
572297728Sadrian	if (!check_bss(vap, ni)) {
573297728Sadrian		/* capabilities mismatch */
574297728Sadrian		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
575297728Sadrian		    "%s: merge failed, capabilities mismatch\n", __func__);
576297728Sadrian#ifdef IEEE80211_DEBUG
577297728Sadrian		if (ieee80211_msg_assoc(vap))
578297728Sadrian			check_bss_debug(vap, ni);
579297728Sadrian#endif
580297728Sadrian		vap->iv_stats.is_ibss_capmismatch++;
581297728Sadrian		return 0;
582297728Sadrian	}
583297728Sadrian
584297728Sadrian	return 1;
585297728Sadrian}
586297728Sadrian
587138568Ssam/*
588138568Ssam * Handle 802.11 ad hoc network merge.  The
589138568Ssam * convention, set by the Wireless Ethernet Compatibility Alliance
590138568Ssam * (WECA), is that an 802.11 station will change its BSSID to match
591138568Ssam * the "oldest" 802.11 ad hoc network, on the same channel, that
592138568Ssam * has the station's desired SSID.  The "oldest" 802.11 network
593138568Ssam * sends beacons with the greatest TSF timestamp.
594138568Ssam *
595138568Ssam * The caller is assumed to validate TSF's before attempting a merge.
596138568Ssam *
597138568Ssam * Return !0 if the BSSID changed, 0 otherwise.
598138568Ssam */
599138568Ssamint
600148306Ssamieee80211_ibss_merge(struct ieee80211_node *ni)
601138568Ssam{
602297733Sbz#ifdef IEEE80211_DEBUG
603178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
604148306Ssam	struct ieee80211com *ic = ni->ni_ic;
605178354Ssam#endif
606138568Ssam
607297728Sadrian	if (! ieee80211_ibss_merge_check(ni))
608138568Ssam		return 0;
609297728Sadrian
610178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
611138568Ssam		"%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
612138568Ssam		ether_sprintf(ni->ni_bssid),
613138568Ssam		ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
614138568Ssam		ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
615138568Ssam		ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
616138568Ssam	);
617170530Ssam	return ieee80211_sta_join1(ieee80211_ref_node(ni));
618138568Ssam}
619138568Ssam
620138568Ssam/*
621178354Ssam * Calculate HT channel promotion flags for all vaps.
622178354Ssam * This assumes ni_chan have been setup for each vap.
623173273Ssam */
624178354Ssamstatic int
625178354Ssamgethtadjustflags(struct ieee80211com *ic)
626178354Ssam{
627178354Ssam	struct ieee80211vap *vap;
628178354Ssam	int flags;
629178354Ssam
630178354Ssam	flags = 0;
631178354Ssam	/* XXX locking */
632178354Ssam	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
633178354Ssam		if (vap->iv_state < IEEE80211_S_RUN)
634178354Ssam			continue;
635178354Ssam		switch (vap->iv_opmode) {
636178354Ssam		case IEEE80211_M_WDS:
637178354Ssam		case IEEE80211_M_STA:
638178354Ssam		case IEEE80211_M_AHDEMO:
639178354Ssam		case IEEE80211_M_HOSTAP:
640178354Ssam		case IEEE80211_M_IBSS:
641195618Srpaulo		case IEEE80211_M_MBSS:
642178354Ssam			flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan);
643178354Ssam			break;
644178354Ssam		default:
645178354Ssam			break;
646178354Ssam		}
647178354Ssam	}
648178354Ssam	return flags;
649178354Ssam}
650178354Ssam
651178354Ssam/*
652178354Ssam * Check if the current channel needs to change based on whether
653184303Ssam * any vap's are using HT20/HT40.  This is used to sync the state
654184303Ssam * of ic_curchan after a channel width change on a running vap.
655178354Ssam */
656173273Ssamvoid
657178354Ssamieee80211_sync_curchan(struct ieee80211com *ic)
658173273Ssam{
659178354Ssam	struct ieee80211_channel *c;
660178354Ssam
661178354Ssam	c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic));
662178354Ssam	if (c != ic->ic_curchan) {
663178354Ssam		ic->ic_curchan = c;
664178354Ssam		ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
665190532Ssam		ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
666191746Sthompsa		IEEE80211_UNLOCK(ic);
667178354Ssam		ic->ic_set_channel(ic);
668192468Ssam		ieee80211_radiotap_chan_change(ic);
669191746Sthompsa		IEEE80211_LOCK(ic);
670178354Ssam	}
671178354Ssam}
672178354Ssam
673178354Ssam/*
674191746Sthompsa * Setup the current channel.  The request channel may be
675178354Ssam * promoted if other vap's are operating with HT20/HT40.
676178354Ssam */
677178354Ssamvoid
678191746Sthompsaieee80211_setupcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
679178354Ssam{
680178354Ssam	if (ic->ic_htcaps & IEEE80211_HTC_HT) {
681178354Ssam		int flags = gethtadjustflags(ic);
682178354Ssam		/*
683178354Ssam		 * Check for channel promotion required to support the
684178354Ssam		 * set of running vap's.  This assumes we are called
685178354Ssam		 * after ni_chan is setup for each vap.
686178354Ssam		 */
687193655Ssam		/* NB: this assumes IEEE80211_FHT_USEHT40 > IEEE80211_FHT_HT */
688178354Ssam		if (flags > ieee80211_htchanflags(c))
689178354Ssam			c = ieee80211_ht_adjust_channel(ic, c, flags);
690178354Ssam	}
691178354Ssam	ic->ic_bsschan = ic->ic_curchan = c;
692173273Ssam	ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
693190532Ssam	ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
694173273Ssam}
695173273Ssam
696173273Ssam/*
697191746Sthompsa * Change the current channel.  The channel change is guaranteed to have
698191746Sthompsa * happened before the next state change.
699191746Sthompsa */
700191746Sthompsavoid
701191746Sthompsaieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
702191746Sthompsa{
703191746Sthompsa	ieee80211_setupcurchan(ic, c);
704191746Sthompsa	ieee80211_runtask(ic, &ic->ic_chan_task);
705191746Sthompsa}
706191746Sthompsa
707233452Sadrianvoid
708233452Sadrianieee80211_update_chw(struct ieee80211com *ic)
709233452Sadrian{
710233452Sadrian
711233452Sadrian	ieee80211_setupcurchan(ic, ic->ic_curchan);
712233452Sadrian	ieee80211_runtask(ic, &ic->ic_chw_task);
713233452Sadrian}
714233452Sadrian
715191746Sthompsa/*
716138568Ssam * Join the specified IBSS/BSS network.  The node is assumed to
717138568Ssam * be passed in with a held reference.
718138568Ssam */
719170530Ssamstatic int
720170530Ssamieee80211_sta_join1(struct ieee80211_node *selbs)
721138568Ssam{
722178354Ssam	struct ieee80211vap *vap = selbs->ni_vap;
723170530Ssam	struct ieee80211com *ic = selbs->ni_ic;
724138568Ssam	struct ieee80211_node *obss;
725170530Ssam	int canreassoc;
726138568Ssam
727138568Ssam	/*
728138568Ssam	 * Committed to selbs, setup state.
729138568Ssam	 */
730178354Ssam	obss = vap->iv_bss;
731170530Ssam	/*
732170530Ssam	 * Check if old+new node have the same address in which
733170530Ssam	 * case we can reassociate when operating in sta mode.
734170530Ssam	 */
735170530Ssam	canreassoc = (obss != NULL &&
736178354Ssam		vap->iv_state == IEEE80211_S_RUN &&
737170530Ssam		IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr));
738178354Ssam	vap->iv_bss = selbs;		/* NB: caller assumed to bump refcnt */
739153352Ssam	if (obss != NULL) {
740282372Sadrian		struct ieee80211_node_table *nt = obss->ni_table;
741282372Sadrian
742153352Ssam		copy_bss(selbs, obss);
743188541Ssam		ieee80211_node_decref(obss);	/* iv_bss reference */
744282372Sadrian
745282372Sadrian		IEEE80211_NODE_LOCK(nt);
746282372Sadrian		node_reclaim(nt, obss);		/* station table reference */
747282372Sadrian		IEEE80211_NODE_UNLOCK(nt);
748282372Sadrian
749178354Ssam		obss = NULL;		/* NB: guard against later use */
750153352Ssam	}
751165887Ssam
752138568Ssam	/*
753165887Ssam	 * Delete unusable rates; we've already checked
754165887Ssam	 * that the negotiated rate set is acceptable.
755165887Ssam	 */
756178354Ssam	ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates,
757167442Ssam		IEEE80211_F_DODEL | IEEE80211_F_JOIN);
758165887Ssam
759178354Ssam	ieee80211_setcurchan(ic, selbs->ni_chan);
760165887Ssam	/*
761138568Ssam	 * Set the erp state (mostly the slot time) to deal with
762138568Ssam	 * the auto-select case; this should be redundant if the
763138568Ssam	 * mode is locked.
764138568Ssam	 */
765138568Ssam	ieee80211_reset_erp(ic);
766178354Ssam	ieee80211_wme_initparams(vap);
767140753Ssam
768178354Ssam	if (vap->iv_opmode == IEEE80211_M_STA) {
769170530Ssam		if (canreassoc) {
770170530Ssam			/* Reassociate */
771178354Ssam			ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
772170530Ssam		} else {
773170530Ssam			/*
774170530Ssam			 * Act as if we received a DEAUTH frame in case we
775170530Ssam			 * are invoked from the RUN state.  This will cause
776170530Ssam			 * us to try to re-authenticate if we are operating
777170530Ssam			 * as a station.
778170530Ssam			 */
779178354Ssam			ieee80211_new_state(vap, IEEE80211_S_AUTH,
780170530Ssam				IEEE80211_FC0_SUBTYPE_DEAUTH);
781170530Ssam		}
782170530Ssam	} else
783178354Ssam		ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
784138568Ssam	return 1;
785116742Ssam}
786116742Ssam
787170530Ssamint
788184274Ssamieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
789170530Ssam	const struct ieee80211_scan_entry *se)
790170530Ssam{
791178354Ssam	struct ieee80211com *ic = vap->iv_ic;
792170530Ssam	struct ieee80211_node *ni;
793170530Ssam
794178354Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr);
795170530Ssam	if (ni == NULL) {
796170530Ssam		/* XXX msg */
797170530Ssam		return 0;
798170530Ssam	}
799245928Sadrian
800170530Ssam	/*
801170530Ssam	 * Expand scan state into node's format.
802170530Ssam	 * XXX may not need all this stuff
803170530Ssam	 */
804170530Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid);
805170530Ssam	ni->ni_esslen = se->se_ssid[1];
806170530Ssam	memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen);
807170530Ssam	ni->ni_tstamp.tsf = se->se_tstamp.tsf;
808170530Ssam	ni->ni_intval = se->se_intval;
809170530Ssam	ni->ni_capinfo = se->se_capinfo;
810184274Ssam	ni->ni_chan = chan;
811170530Ssam	ni->ni_timoff = se->se_timoff;
812170530Ssam	ni->ni_fhdwell = se->se_fhdwell;
813170530Ssam	ni->ni_fhindex = se->se_fhindex;
814170530Ssam	ni->ni_erp = se->se_erp;
815178354Ssam	IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi);
816170530Ssam	ni->ni_noise = se->se_noise;
817186870Ssam	if (vap->iv_opmode == IEEE80211_M_STA) {
818186870Ssam		/* NB: only infrastructure mode requires an associd */
819186870Ssam		ni->ni_flags |= IEEE80211_NODE_ASSOCID;
820186870Ssam	}
821178354Ssam
822178354Ssam	if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) {
823178354Ssam		ieee80211_ies_expand(&ni->ni_ies);
824190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG
825178354Ssam		if (ni->ni_ies.ath_ie != NULL)
826178354Ssam			ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
827190391Ssam#endif
828178354Ssam		if (ni->ni_ies.htcap_ie != NULL)
829178354Ssam			ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
830178354Ssam		if (ni->ni_ies.htinfo_ie != NULL)
831178354Ssam			ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
832195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
833195618Srpaulo		if (ni->ni_ies.meshid_ie != NULL)
834195618Srpaulo			ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie);
835195618Srpaulo#endif
836186904Ssam#ifdef IEEE80211_SUPPORT_TDMA
837186904Ssam		if (ni->ni_ies.tdma_ie != NULL)
838186904Ssam			ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie);
839186904Ssam#endif
840173864Ssam	}
841170530Ssam
842178354Ssam	vap->iv_dtim_period = se->se_dtimperiod;
843178354Ssam	vap->iv_dtim_count = 0;
844170530Ssam
845170530Ssam	/* NB: must be after ni_chan is setup */
846170530Ssam	ieee80211_setup_rates(ni, se->se_rates, se->se_xrates,
847170530Ssam		IEEE80211_F_DOSORT);
848184279Ssam	if (ieee80211_iserp_rateset(&ni->ni_rates))
849184279Ssam		ni->ni_flags |= IEEE80211_NODE_ERP;
850245928Sadrian
851245928Sadrian	/*
852245928Sadrian	 * Setup HT state for this node if it's available, otherwise
853245928Sadrian	 * non-STA modes won't pick this state up.
854245928Sadrian	 *
855245928Sadrian	 * For IBSS and related modes that don't go through an
856245928Sadrian	 * association request/response, the only appropriate place
857245928Sadrian	 * to setup the HT state is here.
858245928Sadrian	 */
859245928Sadrian	if (ni->ni_ies.htinfo_ie != NULL &&
860245928Sadrian	    ni->ni_ies.htcap_ie != NULL &&
861245928Sadrian	    vap->iv_flags_ht & IEEE80211_FHT_HT) {
862245928Sadrian		ieee80211_ht_node_init(ni);
863245928Sadrian		ieee80211_ht_updateparams(ni,
864245928Sadrian		    ni->ni_ies.htcap_ie,
865245928Sadrian		    ni->ni_ies.htinfo_ie);
866245928Sadrian		ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie,
867245928Sadrian		    IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
868245928Sadrian		ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie);
869245928Sadrian	}
870245928Sadrian	/* XXX else check for ath FF? */
871245928Sadrian	/* XXX QoS? Difficult given that WME config is specific to a master */
872245928Sadrian
873193966Ssam	ieee80211_node_setuptxparms(ni);
874214894Sbschmidt	ieee80211_ratectl_node_init(ni);
875170530Ssam
876170530Ssam	return ieee80211_sta_join1(ieee80211_ref_node(ni));
877170530Ssam}
878170530Ssam
879138568Ssam/*
880138568Ssam * Leave the specified IBSS/BSS network.  The node is assumed to
881138568Ssam * be passed in with a held reference.
882138568Ssam */
883138568Ssamvoid
884178354Ssamieee80211_sta_leave(struct ieee80211_node *ni)
885138568Ssam{
886178354Ssam	struct ieee80211com *ic = ni->ni_ic;
887178354Ssam
888138568Ssam	ic->ic_node_cleanup(ni);
889178354Ssam	ieee80211_notify_node_leave(ni);
890138568Ssam}
891138568Ssam
892178354Ssam/*
893178354Ssam * Send a deauthenticate frame and drop the station.
894178354Ssam */
895178354Ssamvoid
896178354Ssamieee80211_node_deauth(struct ieee80211_node *ni, int reason)
897178354Ssam{
898282404Sadrian	/* NB: bump the refcnt to be sure temporary nodes are not reclaimed */
899178354Ssam	ieee80211_ref_node(ni);
900178354Ssam	if (ni->ni_associd != 0)
901178354Ssam		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
902178354Ssam	ieee80211_node_leave(ni);
903178354Ssam	ieee80211_free_node(ni);
904178354Ssam}
905178354Ssam
906116742Ssamstatic struct ieee80211_node *
907179643Ssamnode_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
908116742Ssam{
909127768Ssam	struct ieee80211_node *ni;
910138568Ssam
911283538Sadrian	ni = (struct ieee80211_node *) IEEE80211_MALLOC(sizeof(struct ieee80211_node),
912283538Sadrian		M_80211_NODE, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
913127768Ssam	return ni;
914116742Ssam}
915116742Ssam
916138568Ssam/*
917178354Ssam * Initialize an ie blob with the specified data.  If previous
918178354Ssam * data exists re-use the data block.  As a side effect we clear
919178354Ssam * all references to specific ie's; the caller is required to
920178354Ssam * recalculate them.
921178354Ssam */
922178354Ssamint
923178354Ssamieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len)
924178354Ssam{
925178354Ssam	/* NB: assumes data+len are the last fields */
926178354Ssam	memset(ies, 0, offsetof(struct ieee80211_ies, data));
927178354Ssam	if (ies->data != NULL && ies->len != len) {
928178354Ssam		/* data size changed */
929283538Sadrian		IEEE80211_FREE(ies->data, M_80211_NODE_IE);
930178354Ssam		ies->data = NULL;
931178354Ssam	}
932178354Ssam	if (ies->data == NULL) {
933283538Sadrian		ies->data = (uint8_t *) IEEE80211_MALLOC(len, M_80211_NODE_IE,
934283538Sadrian		    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
935178354Ssam		if (ies->data == NULL) {
936178354Ssam			ies->len = 0;
937178354Ssam			/* NB: pointers have already been zero'd above */
938178354Ssam			return 0;
939178354Ssam		}
940178354Ssam	}
941178354Ssam	memcpy(ies->data, data, len);
942178354Ssam	ies->len = len;
943178354Ssam	return 1;
944178354Ssam}
945178354Ssam
946178354Ssam/*
947178354Ssam * Reclaim storage for an ie blob.
948178354Ssam */
949178354Ssamvoid
950178354Ssamieee80211_ies_cleanup(struct ieee80211_ies *ies)
951178354Ssam{
952178354Ssam	if (ies->data != NULL)
953283538Sadrian		IEEE80211_FREE(ies->data, M_80211_NODE_IE);
954178354Ssam}
955178354Ssam
956178354Ssam/*
957178354Ssam * Expand an ie blob data contents and to fillin individual
958178354Ssam * ie pointers.  The data blob is assumed to be well-formed;
959178354Ssam * we don't do any validity checking of ie lengths.
960178354Ssam */
961178354Ssamvoid
962178354Ssamieee80211_ies_expand(struct ieee80211_ies *ies)
963178354Ssam{
964178354Ssam	uint8_t *ie;
965178354Ssam	int ielen;
966178354Ssam
967178354Ssam	ie = ies->data;
968178354Ssam	ielen = ies->len;
969178354Ssam	while (ielen > 0) {
970178354Ssam		switch (ie[0]) {
971178354Ssam		case IEEE80211_ELEMID_VENDOR:
972178354Ssam			if (iswpaoui(ie))
973178354Ssam				ies->wpa_ie = ie;
974178354Ssam			else if (iswmeoui(ie))
975178354Ssam				ies->wme_ie = ie;
976190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG
977178354Ssam			else if (isatherosoui(ie))
978178354Ssam				ies->ath_ie = ie;
979190391Ssam#endif
980186904Ssam#ifdef IEEE80211_SUPPORT_TDMA
981186904Ssam			else if (istdmaoui(ie))
982186904Ssam				ies->tdma_ie = ie;
983186904Ssam#endif
984178354Ssam			break;
985178354Ssam		case IEEE80211_ELEMID_RSN:
986178354Ssam			ies->rsn_ie = ie;
987178354Ssam			break;
988178354Ssam		case IEEE80211_ELEMID_HTCAP:
989178354Ssam			ies->htcap_ie = ie;
990178354Ssam			break;
991245928Sadrian		case IEEE80211_ELEMID_HTINFO:
992245928Sadrian			ies->htinfo_ie = ie;
993245928Sadrian			break;
994195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
995195618Srpaulo		case IEEE80211_ELEMID_MESHID:
996195618Srpaulo			ies->meshid_ie = ie;
997195618Srpaulo			break;
998195618Srpaulo#endif
999178354Ssam		}
1000178354Ssam		ielen -= 2 + ie[1];
1001178354Ssam		ie += 2 + ie[1];
1002178354Ssam	}
1003178354Ssam}
1004178354Ssam
1005178354Ssam/*
1006138568Ssam * Reclaim any resources in a node and reset any critical
1007138568Ssam * state.  Typically nodes are free'd immediately after,
1008138568Ssam * but in some cases the storage may be reused so we need
1009138568Ssam * to insure consistent state (should probably fix that).
1010138568Ssam */
1011116742Ssamstatic void
1012138568Ssamnode_cleanup(struct ieee80211_node *ni)
1013116742Ssam{
1014178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
1015195379Ssam	struct ieee80211com *ic = ni->ni_ic;
1016170530Ssam	int i;
1017138568Ssam
1018138568Ssam	/* NB: preserve ni_table */
1019138568Ssam	if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) {
1020178354Ssam		if (vap->iv_opmode != IEEE80211_M_STA)
1021178354Ssam			vap->iv_ps_sta--;
1022138568Ssam		ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
1023178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
1024178354Ssam		    "power save mode off, %u sta's in ps mode", vap->iv_ps_sta);
1025138568Ssam	}
1026147788Ssam	/*
1027173273Ssam	 * Cleanup any HT-related state.
1028173273Ssam	 */
1029173273Ssam	if (ni->ni_flags & IEEE80211_NODE_HT)
1030173273Ssam		ieee80211_ht_node_cleanup(ni);
1031190579Ssam#ifdef IEEE80211_SUPPORT_SUPERG
1032297603Sadrian	/* Always do FF node cleanup; for A-MSDU */
1033297603Sadrian	ieee80211_ff_node_cleanup(ni);
1034190579Ssam#endif
1035195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
1036173273Ssam	/*
1037195618Srpaulo	 * Cleanup any mesh-related state.
1038195618Srpaulo	 */
1039195618Srpaulo	if (vap->iv_opmode == IEEE80211_M_MBSS)
1040195618Srpaulo		ieee80211_mesh_node_cleanup(ni);
1041195618Srpaulo#endif
1042195618Srpaulo	/*
1043195379Ssam	 * Clear any staging queue entries.
1044195379Ssam	 */
1045195379Ssam	ieee80211_ageq_drain_node(&ic->ic_stageq, ni);
1046195379Ssam
1047195379Ssam	/*
1048147788Ssam	 * Clear AREF flag that marks the authorization refcnt bump
1049147788Ssam	 * has happened.  This is probably not needed as the node
1050147788Ssam	 * should always be removed from the table so not found but
1051147788Ssam	 * do it just in case.
1052186099Ssam	 * Likewise clear the ASSOCID flag as these flags are intended
1053186099Ssam	 * to be managed in tandem.
1054147788Ssam	 */
1055186099Ssam	ni->ni_flags &= ~(IEEE80211_NODE_AREF | IEEE80211_NODE_ASSOCID);
1056138568Ssam
1057138568Ssam	/*
1058138568Ssam	 * Drain power save queue and, if needed, clear TIM.
1059138568Ssam	 */
1060184288Ssam	if (ieee80211_node_psq_drain(ni) != 0 && vap->iv_set_tim != NULL)
1061178354Ssam		vap->iv_set_tim(ni, 0);
1062138568Ssam
1063138568Ssam	ni->ni_associd = 0;
1064138568Ssam	if (ni->ni_challenge != NULL) {
1065283538Sadrian		IEEE80211_FREE(ni->ni_challenge, M_80211_NODE);
1066138568Ssam		ni->ni_challenge = NULL;
1067138568Ssam	}
1068138568Ssam	/*
1069138568Ssam	 * Preserve SSID, WPA, and WME ie's so the bss node is
1070138568Ssam	 * reusable during a re-auth/re-assoc state transition.
1071138568Ssam	 * If we remove these data they will not be recreated
1072138568Ssam	 * because they come from a probe-response or beacon frame
1073138568Ssam	 * which cannot be expected prior to the association-response.
1074138568Ssam	 * This should not be an issue when operating in other modes
1075138568Ssam	 * as stations leaving always go through a full state transition
1076138568Ssam	 * which will rebuild this state.
1077138568Ssam	 *
1078138568Ssam	 * XXX does this leave us open to inheriting old state?
1079138568Ssam	 */
1080254315Srpaulo	for (i = 0; i < nitems(ni->ni_rxfrag); i++)
1081138568Ssam		if (ni->ni_rxfrag[i] != NULL) {
1082138568Ssam			m_freem(ni->ni_rxfrag[i]);
1083138568Ssam			ni->ni_rxfrag[i] = NULL;
1084138568Ssam		}
1085148863Ssam	/*
1086148863Ssam	 * Must be careful here to remove any key map entry w/o a LOR.
1087148863Ssam	 */
1088148863Ssam	ieee80211_node_delucastkey(ni);
1089116742Ssam}
1090116742Ssam
1091116742Ssamstatic void
1092138568Ssamnode_free(struct ieee80211_node *ni)
1093116742Ssam{
1094138568Ssam	struct ieee80211com *ic = ni->ni_ic;
1095138568Ssam
1096214894Sbschmidt	ieee80211_ratectl_node_deinit(ni);
1097138568Ssam	ic->ic_node_cleanup(ni);
1098178354Ssam	ieee80211_ies_cleanup(&ni->ni_ies);
1099184288Ssam	ieee80211_psq_cleanup(&ni->ni_psq);
1100283538Sadrian	IEEE80211_FREE(ni, M_80211_NODE);
1101116742Ssam}
1102116742Ssam
1103178354Ssamstatic void
1104178354Ssamnode_age(struct ieee80211_node *ni)
1105178354Ssam{
1106178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
1107184303Ssam
1108184303Ssam	IEEE80211_NODE_LOCK_ASSERT(&vap->iv_ic->ic_sta);
1109184303Ssam
1110178354Ssam	/*
1111178354Ssam	 * Age frames on the power save queue.
1112178354Ssam	 */
1113184288Ssam	if (ieee80211_node_psq_age(ni) != 0 &&
1114184288Ssam	    ni->ni_psq.psq_len == 0 && vap->iv_set_tim != NULL)
1115178354Ssam		vap->iv_set_tim(ni, 0);
1116178354Ssam	/*
1117178354Ssam	 * Age out HT resources (e.g. frames on the
1118178354Ssam	 * A-MPDU reorder queues).
1119178354Ssam	 */
1120178354Ssam	if (ni->ni_associd != 0 && (ni->ni_flags & IEEE80211_NODE_HT))
1121178354Ssam		ieee80211_ht_node_age(ni);
1122178354Ssam}
1123178354Ssam
1124170530Ssamstatic int8_t
1125138568Ssamnode_getrssi(const struct ieee80211_node *ni)
1126120104Ssam{
1127178354Ssam	uint32_t avgrssi = ni->ni_avgrssi;
1128178354Ssam	int32_t rssi;
1129178354Ssam
1130178354Ssam	if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER)
1131178354Ssam		return 0;
1132178354Ssam	rssi = IEEE80211_RSSI_GET(avgrssi);
1133178354Ssam	return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
1134120104Ssam}
1135120104Ssam
1136116742Ssamstatic void
1137170530Ssamnode_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
1138170530Ssam{
1139178354Ssam	*rssi = node_getrssi(ni);
1140170530Ssam	*noise = ni->ni_noise;
1141170530Ssam}
1142170530Ssam
1143170530Ssamstatic void
1144178354Ssamnode_getmimoinfo(const struct ieee80211_node *ni,
1145178354Ssam	struct ieee80211_mimo_info *info)
1146116742Ssam{
1147220445Sadrian	int i;
1148220445Sadrian	uint32_t avgrssi;
1149220445Sadrian	int32_t rssi;
1150220445Sadrian
1151220445Sadrian	bzero(info, sizeof(*info));
1152220445Sadrian
1153220445Sadrian	for (i = 0; i < ni->ni_mimo_chains; i++) {
1154220445Sadrian		avgrssi = ni->ni_mimo_rssi_ctl[i];
1155220445Sadrian		if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) {
1156220935Sadrian			info->rssi[i] = 0;
1157220445Sadrian		} else {
1158220445Sadrian			rssi = IEEE80211_RSSI_GET(avgrssi);
1159220935Sadrian			info->rssi[i] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
1160220445Sadrian		}
1161220935Sadrian		info->noise[i] = ni->ni_mimo_noise_ctl[i];
1162220445Sadrian	}
1163220445Sadrian
1164220935Sadrian	/* XXX ext radios? */
1165220935Sadrian
1166220445Sadrian	/* XXX EVM? */
1167178354Ssam}
1168178354Ssam
1169178354Ssamstruct ieee80211_node *
1170178354Ssamieee80211_alloc_node(struct ieee80211_node_table *nt,
1171178354Ssam	struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
1172178354Ssam{
1173138568Ssam	struct ieee80211com *ic = nt->nt_ic;
1174178354Ssam	struct ieee80211_node *ni;
1175116742Ssam	int hash;
1176116742Ssam
1177179643Ssam	ni = ic->ic_node_alloc(vap, macaddr);
1178178354Ssam	if (ni == NULL) {
1179178354Ssam		vap->iv_stats.is_rx_nodealloc++;
1180178354Ssam		return NULL;
1181178354Ssam	}
1182178354Ssam
1183178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1184140766Ssam		"%s %p<%s> in %s table\n", __func__, ni,
1185138568Ssam		ether_sprintf(macaddr), nt->nt_name);
1186138568Ssam
1187116742Ssam	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
1188195618Srpaulo	hash = IEEE80211_NODE_HASH(ic, macaddr);
1189138568Ssam	ieee80211_node_initref(ni);		/* mark referenced */
1190138568Ssam	ni->ni_chan = IEEE80211_CHAN_ANYC;
1191138568Ssam	ni->ni_authmode = IEEE80211_AUTH_OPEN;
1192138568Ssam	ni->ni_txpower = ic->ic_txpowlimit;	/* max power */
1193183251Ssam	ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1194178354Ssam	ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE);
1195178354Ssam	ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER;
1196139528Ssam	ni->ni_inact_reload = nt->nt_inact_init;
1197139528Ssam	ni->ni_inact = ni->ni_inact_reload;
1198170530Ssam	ni->ni_ath_defkeyix = 0x7fff;
1199184288Ssam	ieee80211_psq_init(&ni->ni_psq, "unknown");
1200195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
1201195618Srpaulo	if (vap->iv_opmode == IEEE80211_M_MBSS)
1202195618Srpaulo		ieee80211_mesh_node_init(vap, ni);
1203195618Srpaulo#endif
1204138568Ssam	IEEE80211_NODE_LOCK(nt);
1205138568Ssam	TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
1206138568Ssam	LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
1207138568Ssam	ni->ni_table = nt;
1208178354Ssam	ni->ni_vap = vap;
1209138568Ssam	ni->ni_ic = ic;
1210138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1211116742Ssam
1212184277Ssam	IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
1213184277Ssam	    "%s: inact_reload %u", __func__, ni->ni_inact_reload);
1214184277Ssam
1215217511Sbschmidt	ieee80211_ratectl_node_init(ni);
1216217511Sbschmidt
1217116742Ssam	return ni;
1218116742Ssam}
1219116742Ssam
1220148777Ssam/*
1221148777Ssam * Craft a temporary node suitable for sending a management frame
1222148777Ssam * to the specified station.  We craft only as much state as we
1223148777Ssam * need to do the work since the node will be immediately reclaimed
1224148777Ssam * once the send completes.
1225148777Ssam */
1226116742Ssamstruct ieee80211_node *
1227178354Ssamieee80211_tmp_node(struct ieee80211vap *vap,
1228178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1229148777Ssam{
1230178354Ssam	struct ieee80211com *ic = vap->iv_ic;
1231148777Ssam	struct ieee80211_node *ni;
1232148777Ssam
1233179643Ssam	ni = ic->ic_node_alloc(vap, macaddr);
1234148777Ssam	if (ni != NULL) {
1235183259Ssam		struct ieee80211_node *bss = vap->iv_bss;
1236183259Ssam
1237178354Ssam		IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1238148777Ssam			"%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr));
1239148777Ssam
1240178354Ssam		ni->ni_table = NULL;		/* NB: pedantic */
1241178354Ssam		ni->ni_ic = ic;			/* NB: needed to set channel */
1242178354Ssam		ni->ni_vap = vap;
1243178354Ssam
1244148777Ssam		IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
1245183259Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid);
1246148777Ssam		ieee80211_node_initref(ni);		/* mark referenced */
1247148777Ssam		/* NB: required by ieee80211_fix_rate */
1248183259Ssam		ieee80211_node_set_chan(ni, bss->ni_chan);
1249178354Ssam		ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey,
1250148777Ssam			IEEE80211_KEYIX_NONE);
1251183259Ssam		ni->ni_txpower = bss->ni_txpower;
1252148777Ssam		/* XXX optimize away */
1253184288Ssam		ieee80211_psq_init(&ni->ni_psq, "unknown");
1254217511Sbschmidt
1255217511Sbschmidt		ieee80211_ratectl_node_init(ni);
1256148777Ssam	} else {
1257148777Ssam		/* XXX msg */
1258178354Ssam		vap->iv_stats.is_rx_nodealloc++;
1259148777Ssam	}
1260148777Ssam	return ni;
1261148777Ssam}
1262148777Ssam
1263148777Ssamstruct ieee80211_node *
1264178354Ssamieee80211_dup_bss(struct ieee80211vap *vap,
1265178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1266116742Ssam{
1267178354Ssam	struct ieee80211com *ic = vap->iv_ic;
1268138568Ssam	struct ieee80211_node *ni;
1269138568Ssam
1270178354Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr);
1271116742Ssam	if (ni != NULL) {
1272183259Ssam		struct ieee80211_node *bss = vap->iv_bss;
1273127770Ssam		/*
1274178354Ssam		 * Inherit from iv_bss.
1275127770Ssam		 */
1276183259Ssam		copy_bss(ni, bss);
1277183259Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid);
1278183259Ssam		ieee80211_node_set_chan(ni, bss->ni_chan);
1279178354Ssam	}
1280116742Ssam	return ni;
1281116742Ssam}
1282116742Ssam
1283178354Ssam/*
1284178354Ssam * Create a bss node for a legacy WDS vap.  The far end does
1285178354Ssam * not associate so we just create create a new node and
1286178354Ssam * simulate an association.  The caller is responsible for
1287178354Ssam * installing the node as the bss node and handling any further
1288178354Ssam * setup work like authorizing the port.
1289178354Ssam */
1290178354Ssamstruct ieee80211_node *
1291178354Ssamieee80211_node_create_wds(struct ieee80211vap *vap,
1292178354Ssam	const uint8_t bssid[IEEE80211_ADDR_LEN], struct ieee80211_channel *chan)
1293178354Ssam{
1294178354Ssam	struct ieee80211com *ic = vap->iv_ic;
1295178354Ssam	struct ieee80211_node *ni;
1296178354Ssam
1297178354Ssam	/* XXX check if node already in sta table? */
1298178354Ssam	ni = ieee80211_alloc_node(&ic->ic_sta, vap, bssid);
1299178354Ssam	if (ni != NULL) {
1300178354Ssam		ni->ni_wdsvap = vap;
1301178354Ssam		IEEE80211_ADDR_COPY(ni->ni_bssid, bssid);
1302178354Ssam		/*
1303178354Ssam		 * Inherit any manually configured settings.
1304178354Ssam		 */
1305183259Ssam		copy_bss(ni, vap->iv_bss);
1306178354Ssam		ieee80211_node_set_chan(ni, chan);
1307178354Ssam		/* NB: propagate ssid so available to WPA supplicant */
1308178354Ssam		ni->ni_esslen = vap->iv_des_ssid[0].len;
1309178354Ssam		memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen);
1310178354Ssam		/* NB: no associd for peer */
1311178354Ssam		/*
1312178354Ssam		 * There are no management frames to use to
1313178354Ssam		 * discover neighbor capabilities, so blindly
1314178354Ssam		 * propagate the local configuration.
1315178354Ssam		 */
1316178354Ssam		if (vap->iv_flags & IEEE80211_F_WME)
1317178354Ssam			ni->ni_flags |= IEEE80211_NODE_QOS;
1318190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG
1319178354Ssam		if (vap->iv_flags & IEEE80211_F_FF)
1320178354Ssam			ni->ni_flags |= IEEE80211_NODE_FF;
1321190391Ssam#endif
1322178354Ssam		if ((ic->ic_htcaps & IEEE80211_HTC_HT) &&
1323193655Ssam		    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1324178354Ssam			/*
1325178354Ssam			 * Device is HT-capable and HT is enabled for
1326178354Ssam			 * the vap; setup HT operation.  On return
1327178354Ssam			 * ni_chan will be adjusted to an HT channel.
1328178354Ssam			 */
1329178354Ssam			ieee80211_ht_wds_init(ni);
1330178354Ssam		} else {
1331178354Ssam			struct ieee80211_channel *c = ni->ni_chan;
1332178354Ssam			/*
1333178354Ssam			 * Force a legacy channel to be used.
1334178354Ssam			 */
1335178354Ssam			c = ieee80211_find_channel(ic,
1336178354Ssam			    c->ic_freq, c->ic_flags &~ IEEE80211_CHAN_HT);
1337178354Ssam			KASSERT(c != NULL, ("no legacy channel, %u/%x",
1338178354Ssam			    ni->ni_chan->ic_freq, ni->ni_chan->ic_flags));
1339178354Ssam			ni->ni_chan = c;
1340178354Ssam		}
1341178354Ssam	}
1342178354Ssam	return ni;
1343178354Ssam}
1344178354Ssam
1345178354Ssamstruct ieee80211_node *
1346138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1347178354Ssamieee80211_find_node_locked_debug(struct ieee80211_node_table *nt,
1348178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line)
1349138568Ssam#else
1350178354Ssamieee80211_find_node_locked(struct ieee80211_node_table *nt,
1351178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1352138568Ssam#endif
1353116742Ssam{
1354116742Ssam	struct ieee80211_node *ni;
1355116742Ssam	int hash;
1356116742Ssam
1357138568Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
1358127772Ssam
1359195618Srpaulo	hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
1360138568Ssam	LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
1361116742Ssam		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
1362138568Ssam			ieee80211_ref_node(ni);	/* mark referenced */
1363138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1364178354Ssam			IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1365140766Ssam			    "%s (%s:%u) %p<%s> refcnt %d\n", __func__,
1366140766Ssam			    func, line,
1367140766Ssam			    ni, ether_sprintf(ni->ni_macaddr),
1368140766Ssam			    ieee80211_node_refcnt(ni));
1369138568Ssam#endif
1370127772Ssam			return ni;
1371116742Ssam		}
1372116742Ssam	}
1373127772Ssam	return NULL;
1374127772Ssam}
1375178354Ssam
1376178354Ssamstruct ieee80211_node *
1377138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1378178354Ssamieee80211_find_node_debug(struct ieee80211_node_table *nt,
1379178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line)
1380178354Ssam#else
1381178354Ssamieee80211_find_node(struct ieee80211_node_table *nt,
1382178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1383138568Ssam#endif
1384178354Ssam{
1385178354Ssam	struct ieee80211_node *ni;
1386127772Ssam
1387178354Ssam	IEEE80211_NODE_LOCK(nt);
1388178354Ssam	ni = ieee80211_find_node_locked(nt, macaddr);
1389178354Ssam	IEEE80211_NODE_UNLOCK(nt);
1390178354Ssam	return ni;
1391178354Ssam}
1392178354Ssam
1393127772Ssamstruct ieee80211_node *
1394138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1395178354Ssamieee80211_find_vap_node_locked_debug(struct ieee80211_node_table *nt,
1396178354Ssam	const struct ieee80211vap *vap,
1397178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line)
1398138568Ssam#else
1399178354Ssamieee80211_find_vap_node_locked(struct ieee80211_node_table *nt,
1400178354Ssam	const struct ieee80211vap *vap,
1401178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1402138568Ssam#endif
1403127772Ssam{
1404127772Ssam	struct ieee80211_node *ni;
1405178354Ssam	int hash;
1406127772Ssam
1407178354Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
1408178354Ssam
1409195618Srpaulo	hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
1410178354Ssam	LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
1411178354Ssam		if (ni->ni_vap == vap &&
1412178354Ssam		    IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
1413178354Ssam			ieee80211_ref_node(ni);	/* mark referenced */
1414178354Ssam#ifdef IEEE80211_DEBUG_REFCNT
1415178354Ssam			IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1416178354Ssam			    "%s (%s:%u) %p<%s> refcnt %d\n", __func__,
1417178354Ssam			    func, line,
1418178354Ssam			    ni, ether_sprintf(ni->ni_macaddr),
1419178354Ssam			    ieee80211_node_refcnt(ni));
1420178354Ssam#endif
1421178354Ssam			return ni;
1422178354Ssam		}
1423178354Ssam	}
1424178354Ssam	return NULL;
1425178354Ssam}
1426178354Ssam
1427178354Ssamstruct ieee80211_node *
1428178354Ssam#ifdef IEEE80211_DEBUG_REFCNT
1429178354Ssamieee80211_find_vap_node_debug(struct ieee80211_node_table *nt,
1430178354Ssam	const struct ieee80211vap *vap,
1431178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *func, int line)
1432178354Ssam#else
1433178354Ssamieee80211_find_vap_node(struct ieee80211_node_table *nt,
1434178354Ssam	const struct ieee80211vap *vap,
1435178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1436178354Ssam#endif
1437178354Ssam{
1438178354Ssam	struct ieee80211_node *ni;
1439178354Ssam
1440138568Ssam	IEEE80211_NODE_LOCK(nt);
1441178354Ssam	ni = ieee80211_find_vap_node_locked(nt, vap, macaddr);
1442138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1443116742Ssam	return ni;
1444116742Ssam}
1445116742Ssam
1446116742Ssam/*
1447138568Ssam * Fake up a node; this handles node discovery in adhoc mode.
1448138568Ssam * Note that for the driver's benefit we we treat this like
1449138568Ssam * an association so the driver has an opportunity to setup
1450138568Ssam * it's private state.
1451138568Ssam */
1452138568Ssamstruct ieee80211_node *
1453178354Ssamieee80211_fakeup_adhoc_node(struct ieee80211vap *vap,
1454170530Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1455138568Ssam{
1456138568Ssam	struct ieee80211_node *ni;
1457138568Ssam
1458245928Sadrian	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC,
1459153073Ssam	    "%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
1460178354Ssam	ni = ieee80211_dup_bss(vap, macaddr);
1461138568Ssam	if (ni != NULL) {
1462178354Ssam		struct ieee80211com *ic = vap->iv_ic;
1463178354Ssam
1464138568Ssam		/* XXX no rate negotiation; just dup */
1465178354Ssam		ni->ni_rates = vap->iv_bss->ni_rates;
1466188869Ssam		if (ieee80211_iserp_rateset(&ni->ni_rates))
1467188869Ssam			ni->ni_flags |= IEEE80211_NODE_ERP;
1468178354Ssam		if (vap->iv_opmode == IEEE80211_M_AHDEMO) {
1469153404Ssam			/*
1470170530Ssam			 * In adhoc demo mode there are no management
1471170530Ssam			 * frames to use to discover neighbor capabilities,
1472170530Ssam			 * so blindly propagate the local configuration
1473170530Ssam			 * so we can do interesting things (e.g. use
1474170530Ssam			 * WME to disable ACK's).
1475153404Ssam			 */
1476178354Ssam			if (vap->iv_flags & IEEE80211_F_WME)
1477153404Ssam				ni->ni_flags |= IEEE80211_NODE_QOS;
1478190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG
1479178354Ssam			if (vap->iv_flags & IEEE80211_F_FF)
1480170530Ssam				ni->ni_flags |= IEEE80211_NODE_FF;
1481190391Ssam#endif
1482153404Ssam		}
1483193966Ssam		ieee80211_node_setuptxparms(ni);
1484214894Sbschmidt		ieee80211_ratectl_node_init(ni);
1485178354Ssam		if (ic->ic_newassoc != NULL)
1486178354Ssam			ic->ic_newassoc(ni, 1);
1487170530Ssam		/* XXX not right for 802.1x/WPA */
1488170530Ssam		ieee80211_node_authorize(ni);
1489138568Ssam	}
1490138568Ssam	return ni;
1491138568Ssam}
1492138568Ssam
1493148936Ssamvoid
1494153073Ssamieee80211_init_neighbor(struct ieee80211_node *ni,
1495153073Ssam	const struct ieee80211_frame *wh,
1496153073Ssam	const struct ieee80211_scanparams *sp)
1497153073Ssam{
1498245928Sadrian	int do_ht_setup = 0;
1499245928Sadrian
1500153073Ssam	ni->ni_esslen = sp->ssid[1];
1501153073Ssam	memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
1502153073Ssam	IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
1503153073Ssam	memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp));
1504153073Ssam	ni->ni_intval = sp->bintval;
1505153073Ssam	ni->ni_capinfo = sp->capinfo;
1506153073Ssam	ni->ni_chan = ni->ni_ic->ic_curchan;
1507153073Ssam	ni->ni_fhdwell = sp->fhdwell;
1508153073Ssam	ni->ni_fhindex = sp->fhindex;
1509153073Ssam	ni->ni_erp = sp->erp;
1510153073Ssam	ni->ni_timoff = sp->timoff;
1511195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
1512195618Srpaulo	if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS)
1513195618Srpaulo		ieee80211_mesh_init_neighbor(ni, wh, sp);
1514195618Srpaulo#endif
1515178354Ssam	if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) {
1516178354Ssam		ieee80211_ies_expand(&ni->ni_ies);
1517186659Ssam		if (ni->ni_ies.wme_ie != NULL)
1518186659Ssam			ni->ni_flags |= IEEE80211_NODE_QOS;
1519186659Ssam		else
1520186659Ssam			ni->ni_flags &= ~IEEE80211_NODE_QOS;
1521190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG
1522178354Ssam		if (ni->ni_ies.ath_ie != NULL)
1523178354Ssam			ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
1524190391Ssam#endif
1525245928Sadrian		if (ni->ni_ies.htcap_ie != NULL)
1526245928Sadrian			ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
1527245928Sadrian		if (ni->ni_ies.htinfo_ie != NULL)
1528245928Sadrian			ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
1529245928Sadrian
1530245928Sadrian		if ((ni->ni_ies.htcap_ie != NULL) &&
1531245928Sadrian		    (ni->ni_ies.htinfo_ie != NULL) &&
1532245928Sadrian		    (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1533245928Sadrian			do_ht_setup = 1;
1534245928Sadrian		}
1535178354Ssam	}
1536178354Ssam
1537153073Ssam	/* NB: must be after ni_chan is setup */
1538165887Ssam	ieee80211_setup_rates(ni, sp->rates, sp->xrates,
1539165887Ssam		IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1540165887Ssam		IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1541245928Sadrian
1542245928Sadrian	/*
1543245928Sadrian	 * If the neighbor is HT compatible, flip that on.
1544245928Sadrian	 */
1545245928Sadrian	if (do_ht_setup) {
1546245928Sadrian		IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
1547245928Sadrian		    "%s: doing HT setup\n", __func__);
1548245928Sadrian		ieee80211_ht_node_init(ni);
1549245928Sadrian		ieee80211_ht_updateparams(ni,
1550245928Sadrian		    ni->ni_ies.htcap_ie,
1551245928Sadrian		    ni->ni_ies.htinfo_ie);
1552245928Sadrian		ieee80211_setup_htrates(ni,
1553245928Sadrian		    ni->ni_ies.htcap_ie,
1554245928Sadrian		    IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
1555245928Sadrian		ieee80211_setup_basic_htrates(ni,
1556245928Sadrian		    ni->ni_ies.htinfo_ie);
1557245928Sadrian		ieee80211_node_setuptxparms(ni);
1558245928Sadrian		ieee80211_ratectl_node_init(ni);
1559245928Sadrian	}
1560153073Ssam}
1561153073Ssam
1562148936Ssam/*
1563148936Ssam * Do node discovery in adhoc mode on receipt of a beacon
1564148936Ssam * or probe response frame.  Note that for the driver's
1565148936Ssam * benefit we we treat this like an association so the
1566148936Ssam * driver has an opportunity to setup it's private state.
1567148936Ssam */
1568148936Ssamstruct ieee80211_node *
1569178354Ssamieee80211_add_neighbor(struct ieee80211vap *vap,
1570148936Ssam	const struct ieee80211_frame *wh,
1571148936Ssam	const struct ieee80211_scanparams *sp)
1572148936Ssam{
1573148936Ssam	struct ieee80211_node *ni;
1574148936Ssam
1575245928Sadrian	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
1576153073Ssam	    "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
1577178354Ssam	ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */
1578148936Ssam	if (ni != NULL) {
1579178354Ssam		struct ieee80211com *ic = vap->iv_ic;
1580178354Ssam
1581153073Ssam		ieee80211_init_neighbor(ni, wh, sp);
1582188869Ssam		if (ieee80211_iserp_rateset(&ni->ni_rates))
1583188869Ssam			ni->ni_flags |= IEEE80211_NODE_ERP;
1584193966Ssam		ieee80211_node_setuptxparms(ni);
1585214894Sbschmidt		ieee80211_ratectl_node_init(ni);
1586148936Ssam		if (ic->ic_newassoc != NULL)
1587148936Ssam			ic->ic_newassoc(ni, 1);
1588148936Ssam		/* XXX not right for 802.1x/WPA */
1589148936Ssam		ieee80211_node_authorize(ni);
1590148936Ssam	}
1591148936Ssam	return ni;
1592148936Ssam}
1593148936Ssam
1594179220Ssam#define	IS_PROBEREQ(wh) \
1595179220Ssam	((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) \
1596179220Ssam	    == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ))
1597179220Ssam#define	IS_BCAST_PROBEREQ(wh) \
1598179220Ssam	(IS_PROBEREQ(wh) && IEEE80211_IS_MULTICAST( \
1599179220Ssam	    ((const struct ieee80211_frame *)(wh))->i_addr3))
1600170530Ssam
1601179220Ssamstatic __inline struct ieee80211_node *
1602179220Ssam_find_rxnode(struct ieee80211_node_table *nt,
1603179220Ssam    const struct ieee80211_frame_min *wh)
1604179220Ssam{
1605179220Ssam	if (IS_BCAST_PROBEREQ(wh))
1606179220Ssam		return NULL;		/* spam bcast probe req to all vap's */
1607179220Ssam	return ieee80211_find_node_locked(nt, wh->i_addr2);
1608179220Ssam}
1609179220Ssam
1610138568Ssam/*
1611138568Ssam * Locate the node for sender, track state, and then pass the
1612179220Ssam * (referenced) node up to the 802.11 layer for its use.  Note
1613179220Ssam * we can return NULL if the sender is not in the table.
1614138568Ssam */
1615138568Ssamstruct ieee80211_node *
1616138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1617138568Ssamieee80211_find_rxnode_debug(struct ieee80211com *ic,
1618138568Ssam	const struct ieee80211_frame_min *wh, const char *func, int line)
1619138568Ssam#else
1620138568Ssamieee80211_find_rxnode(struct ieee80211com *ic,
1621138568Ssam	const struct ieee80211_frame_min *wh)
1622138568Ssam#endif
1623138568Ssam{
1624138568Ssam	struct ieee80211_node_table *nt;
1625138568Ssam	struct ieee80211_node *ni;
1626138568Ssam
1627170530Ssam	nt = &ic->ic_sta;
1628138568Ssam	IEEE80211_NODE_LOCK(nt);
1629179220Ssam	ni = _find_rxnode(nt, wh);
1630138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1631138568Ssam
1632148863Ssam	return ni;
1633148863Ssam}
1634148863Ssam
1635148863Ssam/*
1636148863Ssam * Like ieee80211_find_rxnode but use the supplied h/w
1637148863Ssam * key index as a hint to locate the node in the key
1638148863Ssam * mapping table.  If an entry is present at the key
1639148863Ssam * index we return it; otherwise do a normal lookup and
1640148863Ssam * update the mapping table if the station has a unicast
1641148863Ssam * key assigned to it.
1642148863Ssam */
1643148863Ssamstruct ieee80211_node *
1644148863Ssam#ifdef IEEE80211_DEBUG_REFCNT
1645148863Ssamieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic,
1646148863Ssam	const struct ieee80211_frame_min *wh, ieee80211_keyix keyix,
1647148863Ssam	const char *func, int line)
1648148863Ssam#else
1649148863Ssamieee80211_find_rxnode_withkey(struct ieee80211com *ic,
1650148863Ssam	const struct ieee80211_frame_min *wh, ieee80211_keyix keyix)
1651148863Ssam#endif
1652148863Ssam{
1653148863Ssam	struct ieee80211_node_table *nt;
1654148863Ssam	struct ieee80211_node *ni;
1655148863Ssam
1656170530Ssam	nt = &ic->ic_sta;
1657148863Ssam	IEEE80211_NODE_LOCK(nt);
1658148863Ssam	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax)
1659148863Ssam		ni = nt->nt_keyixmap[keyix];
1660148863Ssam	else
1661148863Ssam		ni = NULL;
1662148863Ssam	if (ni == NULL) {
1663179220Ssam		ni = _find_rxnode(nt, wh);
1664178354Ssam		if (ni != NULL && nt->nt_keyixmap != NULL) {
1665148863Ssam			/*
1666148863Ssam			 * If the station has a unicast key cache slot
1667148863Ssam			 * assigned update the key->node mapping table.
1668148863Ssam			 */
1669148863Ssam			keyix = ni->ni_ucastkey.wk_rxkeyix;
1670148863Ssam			/* XXX can keyixmap[keyix] != NULL? */
1671148863Ssam			if (keyix < nt->nt_keyixmax &&
1672148863Ssam			    nt->nt_keyixmap[keyix] == NULL) {
1673178354Ssam				IEEE80211_DPRINTF(ni->ni_vap,
1674178354Ssam				    IEEE80211_MSG_NODE,
1675148863Ssam				    "%s: add key map entry %p<%s> refcnt %d\n",
1676148863Ssam				    __func__, ni, ether_sprintf(ni->ni_macaddr),
1677148863Ssam				    ieee80211_node_refcnt(ni)+1);
1678148863Ssam				nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni);
1679148863Ssam			}
1680148863Ssam		}
1681179220Ssam	} else {
1682179220Ssam		if (IS_BCAST_PROBEREQ(wh))
1683179220Ssam			ni = NULL;	/* spam bcast probe req to all vap's */
1684179220Ssam		else
1685179220Ssam			ieee80211_ref_node(ni);
1686179220Ssam	}
1687148863Ssam	IEEE80211_NODE_UNLOCK(nt);
1688148863Ssam
1689148863Ssam	return ni;
1690148863Ssam}
1691179220Ssam#undef IS_BCAST_PROBEREQ
1692179220Ssam#undef IS_PROBEREQ
1693138568Ssam
1694138568Ssam/*
1695127772Ssam * Return a reference to the appropriate node for sending
1696127772Ssam * a data frame.  This handles node discovery in adhoc networks.
1697127772Ssam */
1698127772Ssamstruct ieee80211_node *
1699138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1700178354Ssamieee80211_find_txnode_debug(struct ieee80211vap *vap,
1701178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN],
1702138568Ssam	const char *func, int line)
1703138568Ssam#else
1704178354Ssamieee80211_find_txnode(struct ieee80211vap *vap,
1705178354Ssam	const uint8_t macaddr[IEEE80211_ADDR_LEN])
1706138568Ssam#endif
1707127772Ssam{
1708178354Ssam	struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta;
1709127772Ssam	struct ieee80211_node *ni;
1710127772Ssam
1711127772Ssam	/*
1712127772Ssam	 * The destination address should be in the node table
1713148863Ssam	 * unless this is a multicast/broadcast frame.  We can
1714148863Ssam	 * also optimize station mode operation, all frames go
1715148863Ssam	 * to the bss node.
1716127772Ssam	 */
1717127772Ssam	/* XXX can't hold lock across dup_bss 'cuz of recursive locking */
1718138568Ssam	IEEE80211_NODE_LOCK(nt);
1719178354Ssam	if (vap->iv_opmode == IEEE80211_M_STA ||
1720178354Ssam	    vap->iv_opmode == IEEE80211_M_WDS ||
1721178354Ssam	    IEEE80211_IS_MULTICAST(macaddr))
1722178354Ssam		ni = ieee80211_ref_node(vap->iv_bss);
1723186099Ssam	else
1724178354Ssam		ni = ieee80211_find_node_locked(nt, macaddr);
1725138568Ssam	IEEE80211_NODE_UNLOCK(nt);
1726138568Ssam
1727138568Ssam	if (ni == NULL) {
1728178354Ssam		if (vap->iv_opmode == IEEE80211_M_IBSS ||
1729178354Ssam		    vap->iv_opmode == IEEE80211_M_AHDEMO) {
1730140497Ssam			/*
1731140497Ssam			 * In adhoc mode cons up a node for the destination.
1732140497Ssam			 * Note that we need an additional reference for the
1733178354Ssam			 * caller to be consistent with
1734178354Ssam			 * ieee80211_find_node_locked.
1735140497Ssam			 */
1736178354Ssam			ni = ieee80211_fakeup_adhoc_node(vap, macaddr);
1737140497Ssam			if (ni != NULL)
1738140497Ssam				(void) ieee80211_ref_node(ni);
1739140497Ssam		} else {
1740178354Ssam			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, macaddr,
1741178354Ssam			    "no node, discard frame (%s)", __func__);
1742178354Ssam			vap->iv_stats.is_tx_nonode++;
1743127772Ssam		}
1744127772Ssam	}
1745127772Ssam	return ni;
1746127772Ssam}
1747127772Ssam
1748116742Ssamstatic void
1749138568Ssam_ieee80211_free_node(struct ieee80211_node *ni)
1750116742Ssam{
1751138568Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1752119150Ssam
1753179641Ssam	/*
1754179641Ssam	 * NB: careful about referencing the vap as it may be
1755179641Ssam	 * gone if the last reference was held by a driver.
1756179641Ssam	 * We know the com will always be present so it's safe
1757179641Ssam	 * to use ni_ic below to reclaim resources.
1758179641Ssam	 */
1759179641Ssam#if 0
1760178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1761140766Ssam		"%s %p<%s> in %s table\n", __func__, ni,
1762140766Ssam		ether_sprintf(ni->ni_macaddr),
1763138568Ssam		nt != NULL ? nt->nt_name : "<gone>");
1764179641Ssam#endif
1765179641Ssam	if (ni->ni_associd != 0) {
1766179641Ssam		struct ieee80211vap *vap = ni->ni_vap;
1767179641Ssam		if (vap->iv_aid_bitmap != NULL)
1768179641Ssam			IEEE80211_AID_CLR(vap, ni->ni_associd);
1769179641Ssam	}
1770138568Ssam	if (nt != NULL) {
1771138568Ssam		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
1772138568Ssam		LIST_REMOVE(ni, ni_hash);
1773138568Ssam	}
1774179641Ssam	ni->ni_ic->ic_node_free(ni);
1775116742Ssam}
1776116742Ssam
1777282404Sadrian/*
1778282404Sadrian * Clear any entry in the unicast key mapping table.
1779282404Sadrian */
1780282404Sadrianstatic int
1781282404Sadriannode_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
1782282404Sadrian{
1783282404Sadrian	ieee80211_keyix keyix;
1784282404Sadrian
1785282404Sadrian	keyix = ni->ni_ucastkey.wk_rxkeyix;
1786282404Sadrian	if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
1787282404Sadrian	    nt->nt_keyixmap[keyix] == ni) {
1788282404Sadrian		IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1789282404Sadrian			"%s: %p<%s> clear key map entry %u\n",
1790282404Sadrian			__func__, ni, ether_sprintf(ni->ni_macaddr), keyix);
1791282404Sadrian		nt->nt_keyixmap[keyix] = NULL;
1792282404Sadrian		ieee80211_node_decref(ni);
1793282404Sadrian		return 1;
1794282404Sadrian	}
1795282404Sadrian
1796282404Sadrian	return 0;
1797282404Sadrian}
1798282404Sadrian
1799116742Ssamvoid
1800138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1801138568Ssamieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line)
1802138568Ssam#else
1803138568Ssamieee80211_free_node(struct ieee80211_node *ni)
1804138568Ssam#endif
1805116742Ssam{
1806138568Ssam	struct ieee80211_node_table *nt = ni->ni_table;
1807119150Ssam
1808138568Ssam#ifdef IEEE80211_DEBUG_REFCNT
1809178354Ssam	IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1810140766Ssam		"%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
1811138568Ssam		 ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1);
1812138568Ssam#endif
1813148863Ssam	if (nt != NULL) {
1814148863Ssam		IEEE80211_NODE_LOCK(nt);
1815148863Ssam		if (ieee80211_node_dectestref(ni)) {
1816148863Ssam			/*
1817148863Ssam			 * Last reference, reclaim state.
1818148863Ssam			 */
1819138568Ssam			_ieee80211_free_node(ni);
1820282404Sadrian		} else if (ieee80211_node_refcnt(ni) == 1)
1821282404Sadrian			if (node_clear_keyixmap(nt, ni))
1822148863Ssam				_ieee80211_free_node(ni);
1823148863Ssam		IEEE80211_NODE_UNLOCK(nt);
1824148863Ssam	} else {
1825148863Ssam		if (ieee80211_node_dectestref(ni))
1826138568Ssam			_ieee80211_free_node(ni);
1827116742Ssam	}
1828116742Ssam}
1829116742Ssam
1830138568Ssam/*
1831148863Ssam * Reclaim a unicast key and clear any key cache state.
1832148863Ssam */
1833148863Ssamint
1834148863Ssamieee80211_node_delucastkey(struct ieee80211_node *ni)
1835148863Ssam{
1836179641Ssam	struct ieee80211com *ic = ni->ni_ic;
1837179641Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
1838148863Ssam	struct ieee80211_node *nikey;
1839148863Ssam	ieee80211_keyix keyix;
1840148863Ssam	int isowned, status;
1841148863Ssam
1842148863Ssam	/*
1843148863Ssam	 * NB: We must beware of LOR here; deleting the key
1844148863Ssam	 * can cause the crypto layer to block traffic updates
1845148863Ssam	 * which can generate a LOR against the node table lock;
1846148863Ssam	 * grab it here and stash the key index for our use below.
1847148863Ssam	 *
1848148863Ssam	 * Must also beware of recursion on the node table lock.
1849148863Ssam	 * When called from node_cleanup we may already have
1850148863Ssam	 * the node table lock held.  Unfortunately there's no
1851148863Ssam	 * way to separate out this path so we must do this
1852148863Ssam	 * conditionally.
1853148863Ssam	 */
1854148863Ssam	isowned = IEEE80211_NODE_IS_LOCKED(nt);
1855148863Ssam	if (!isowned)
1856148863Ssam		IEEE80211_NODE_LOCK(nt);
1857179641Ssam	nikey = NULL;
1858179641Ssam	status = 1;		/* NB: success */
1859186144Ssam	if (ni->ni_ucastkey.wk_keyix != IEEE80211_KEYIX_NONE) {
1860179641Ssam		keyix = ni->ni_ucastkey.wk_rxkeyix;
1861179641Ssam		status = ieee80211_crypto_delkey(ni->ni_vap, &ni->ni_ucastkey);
1862179641Ssam		if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) {
1863179641Ssam			nikey = nt->nt_keyixmap[keyix];
1864201758Smbr			nt->nt_keyixmap[keyix] = NULL;
1865179641Ssam		}
1866179641Ssam	}
1867148863Ssam	if (!isowned)
1868178354Ssam		IEEE80211_NODE_UNLOCK(nt);
1869148863Ssam
1870148863Ssam	if (nikey != NULL) {
1871148863Ssam		KASSERT(nikey == ni,
1872148863Ssam			("key map out of sync, ni %p nikey %p", ni, nikey));
1873179641Ssam		IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1874148863Ssam			"%s: delete key map entry %p<%s> refcnt %d\n",
1875148863Ssam			__func__, ni, ether_sprintf(ni->ni_macaddr),
1876148863Ssam			ieee80211_node_refcnt(ni)-1);
1877148863Ssam		ieee80211_free_node(ni);
1878148863Ssam	}
1879148863Ssam	return status;
1880148863Ssam}
1881148863Ssam
1882148863Ssam/*
1883138568Ssam * Reclaim a node.  If this is the last reference count then
1884138568Ssam * do the normal free work.  Otherwise remove it from the node
1885138568Ssam * table and mark it gone by clearing the back-reference.
1886138568Ssam */
1887138568Ssamstatic void
1888138568Ssamnode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
1889116742Ssam{
1890138568Ssam
1891148863Ssam	IEEE80211_NODE_LOCK_ASSERT(nt);
1892148863Ssam
1893178354Ssam	IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1894140766Ssam		"%s: remove %p<%s> from %s table, refcnt %d\n",
1895140766Ssam		__func__, ni, ether_sprintf(ni->ni_macaddr),
1896140766Ssam		nt->nt_name, ieee80211_node_refcnt(ni)-1);
1897148863Ssam	/*
1898148863Ssam	 * Clear any entry in the unicast key mapping table.
1899148863Ssam	 * We need to do it here so rx lookups don't find it
1900148863Ssam	 * in the mapping table even if it's not in the hash
1901148863Ssam	 * table.  We cannot depend on the mapping table entry
1902148863Ssam	 * being cleared because the node may not be free'd.
1903148863Ssam	 */
1904282404Sadrian	(void)node_clear_keyixmap(nt, ni);
1905138568Ssam	if (!ieee80211_node_dectestref(ni)) {
1906138568Ssam		/*
1907138568Ssam		 * Other references are present, just remove the
1908138568Ssam		 * node from the table so it cannot be found.  When
1909138568Ssam		 * the references are dropped storage will be
1910140753Ssam		 * reclaimed.
1911138568Ssam		 */
1912138568Ssam		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
1913138568Ssam		LIST_REMOVE(ni, ni_hash);
1914138568Ssam		ni->ni_table = NULL;		/* clear reference */
1915138568Ssam	} else
1916138568Ssam		_ieee80211_free_node(ni);
1917138568Ssam}
1918138568Ssam
1919178354Ssam/*
1920178354Ssam * Node table support.
1921178354Ssam */
1922178354Ssam
1923178354Ssamstatic void
1924178354Ssamieee80211_node_table_init(struct ieee80211com *ic,
1925178354Ssam	struct ieee80211_node_table *nt,
1926178354Ssam	const char *name, int inact, int keyixmax)
1927178354Ssam{
1928178354Ssam
1929178354Ssam	nt->nt_ic = ic;
1930283529Sglebius	IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name);
1931283529Sglebius	IEEE80211_NODE_ITERATE_LOCK_INIT(nt, ic->ic_name);
1932178354Ssam	TAILQ_INIT(&nt->nt_node);
1933178354Ssam	nt->nt_name = name;
1934178354Ssam	nt->nt_scangen = 1;
1935178354Ssam	nt->nt_inact_init = inact;
1936178354Ssam	nt->nt_keyixmax = keyixmax;
1937178354Ssam	if (nt->nt_keyixmax > 0) {
1938283538Sadrian		nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC(
1939184210Sdes			keyixmax * sizeof(struct ieee80211_node *),
1940283538Sadrian			M_80211_NODE,
1941283538Sadrian			IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1942178354Ssam		if (nt->nt_keyixmap == NULL)
1943283529Sglebius			ic_printf(ic,
1944178354Ssam			    "Cannot allocate key index map with %u entries\n",
1945178354Ssam			    keyixmax);
1946178354Ssam	} else
1947178354Ssam		nt->nt_keyixmap = NULL;
1948178354Ssam}
1949178354Ssam
1950178354Ssamstatic void
1951178354Ssamieee80211_node_table_reset(struct ieee80211_node_table *nt,
1952178354Ssam	struct ieee80211vap *match)
1953178354Ssam{
1954178354Ssam	struct ieee80211_node *ni, *next;
1955178354Ssam
1956178354Ssam	IEEE80211_NODE_LOCK(nt);
1957178354Ssam	TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) {
1958178354Ssam		if (match != NULL && ni->ni_vap != match)
1959178354Ssam			continue;
1960178354Ssam		/* XXX can this happen?  if so need's work */
1961138568Ssam		if (ni->ni_associd != 0) {
1962178354Ssam			struct ieee80211vap *vap = ni->ni_vap;
1963178354Ssam
1964178354Ssam			if (vap->iv_auth->ia_node_leave != NULL)
1965178354Ssam				vap->iv_auth->ia_node_leave(ni);
1966178354Ssam			if (vap->iv_aid_bitmap != NULL)
1967178354Ssam				IEEE80211_AID_CLR(vap, ni->ni_associd);
1968138568Ssam		}
1969178354Ssam		ni->ni_wdsvap = NULL;		/* clear reference */
1970138568Ssam		node_reclaim(nt, ni);
1971138568Ssam	}
1972178354Ssam	if (match != NULL && match->iv_opmode == IEEE80211_M_WDS) {
1973178354Ssam		/*
1974178354Ssam		 * Make a separate pass to clear references to this vap
1975178354Ssam		 * held by DWDS entries.  They will not be matched above
1976178354Ssam		 * because ni_vap will point to the ap vap but we still
1977178354Ssam		 * need to clear ni_wdsvap when the WDS vap is destroyed
1978178354Ssam		 * and/or reset.
1979178354Ssam		 */
1980178354Ssam		TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next)
1981178354Ssam			if (ni->ni_wdsvap == match)
1982178354Ssam				ni->ni_wdsvap = NULL;
1983178354Ssam	}
1984178354Ssam	IEEE80211_NODE_UNLOCK(nt);
1985116742Ssam}
1986116742Ssam
1987178354Ssamstatic void
1988178354Ssamieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
1989178354Ssam{
1990178354Ssam	ieee80211_node_table_reset(nt, NULL);
1991178354Ssam	if (nt->nt_keyixmap != NULL) {
1992178354Ssam#ifdef DIAGNOSTIC
1993178354Ssam		/* XXX verify all entries are NULL */
1994178354Ssam		int i;
1995178354Ssam		for (i = 0; i < nt->nt_keyixmax; i++)
1996178354Ssam			if (nt->nt_keyixmap[i] != NULL)
1997178354Ssam				printf("%s: %s[%u] still active\n", __func__,
1998178354Ssam					nt->nt_name, i);
1999178354Ssam#endif
2000283538Sadrian		IEEE80211_FREE(nt->nt_keyixmap, M_80211_NODE);
2001178354Ssam		nt->nt_keyixmap = NULL;
2002178354Ssam	}
2003178354Ssam	IEEE80211_NODE_ITERATE_LOCK_DESTROY(nt);
2004178354Ssam	IEEE80211_NODE_LOCK_DESTROY(nt);
2005178354Ssam}
2006178354Ssam
2007120483Ssam/*
2008138568Ssam * Timeout inactive stations and do related housekeeping.
2009138568Ssam * Note that we cannot hold the node lock while sending a
2010138568Ssam * frame as this would lead to a LOR.  Instead we use a
2011138568Ssam * generation number to mark nodes that we've scanned and
2012138568Ssam * drop the lock and restart a scan if we have to time out
2013138568Ssam * a node.  Since we are single-threaded by virtue of
2014120483Ssam * controlling the inactivity timer we can be sure this will
2015120483Ssam * process each node only once.
2016120483Ssam */
2017138568Ssamstatic void
2018178354Ssamieee80211_timeout_stations(struct ieee80211com *ic)
2019116742Ssam{
2020178354Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
2021178354Ssam	struct ieee80211vap *vap;
2022120483Ssam	struct ieee80211_node *ni;
2023178354Ssam	int gen = 0;
2024116742Ssam
2025178354Ssam	IEEE80211_NODE_ITERATE_LOCK(nt);
2026154532Ssam	gen = ++nt->nt_scangen;
2027120483Ssamrestart:
2028138568Ssam	IEEE80211_NODE_LOCK(nt);
2029138568Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
2030120483Ssam		if (ni->ni_scangen == gen)	/* previously handled */
2031120483Ssam			continue;
2032120483Ssam		ni->ni_scangen = gen;
2033138568Ssam		/*
2034147788Ssam		 * Ignore entries for which have yet to receive an
2035147788Ssam		 * authentication frame.  These are transient and
2036147788Ssam		 * will be reclaimed when the last reference to them
2037147788Ssam		 * goes away (when frame xmits complete).
2038147788Ssam		 */
2039178354Ssam		vap = ni->ni_vap;
2040178354Ssam		/*
2041178354Ssam		 * Only process stations when in RUN state.  This
2042178354Ssam		 * insures, for example, that we don't timeout an
2043178354Ssam		 * inactive station during CAC.  Note that CSA state
2044178354Ssam		 * is actually handled in ieee80211_node_timeout as
2045178354Ssam		 * it applies to more than timeout processing.
2046178354Ssam		 */
2047178354Ssam		if (vap->iv_state != IEEE80211_S_RUN)
2048178354Ssam			continue;
2049178354Ssam		/* XXX can vap be NULL? */
2050178354Ssam		if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
2051178354Ssam		     vap->iv_opmode == IEEE80211_M_STA) &&
2052148323Ssam		    (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
2053147788Ssam			continue;
2054147788Ssam		/*
2055138568Ssam		 * Free fragment if not needed anymore
2056138568Ssam		 * (last fragment older than 1s).
2057178354Ssam		 * XXX doesn't belong here, move to node_age
2058138568Ssam		 */
2059138568Ssam		if (ni->ni_rxfrag[0] != NULL &&
2060138568Ssam		    ticks > ni->ni_rxfragstamp + hz) {
2061138568Ssam			m_freem(ni->ni_rxfrag[0]);
2062138568Ssam			ni->ni_rxfrag[0] = NULL;
2063138568Ssam		}
2064184277Ssam		if (ni->ni_inact > 0) {
2065172062Ssam			ni->ni_inact--;
2066184277Ssam			IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
2067184277Ssam			    "%s: inact %u inact_reload %u nrates %u",
2068184277Ssam			    __func__, ni->ni_inact, ni->ni_inact_reload,
2069184277Ssam			    ni->ni_rates.rs_nrates);
2070184277Ssam		}
2071140498Ssam		/*
2072140498Ssam		 * Special case ourself; we may be idle for extended periods
2073140498Ssam		 * of time and regardless reclaiming our state is wrong.
2074178354Ssam		 * XXX run ic_node_age
2075140498Ssam		 */
2076178354Ssam		if (ni == vap->iv_bss)
2077140498Ssam			continue;
2078178354Ssam		if (ni->ni_associd != 0 ||
2079178354Ssam		    (vap->iv_opmode == IEEE80211_M_IBSS ||
2080178354Ssam		     vap->iv_opmode == IEEE80211_M_AHDEMO)) {
2081119150Ssam			/*
2082178354Ssam			 * Age/drain resources held by the station.
2083138568Ssam			 */
2084178354Ssam			ic->ic_node_age(ni);
2085138568Ssam			/*
2086138568Ssam			 * Probe the station before time it out.  We
2087138568Ssam			 * send a null data frame which may not be
2088138568Ssam			 * universally supported by drivers (need it
2089138568Ssam			 * for ps-poll support so it should be...).
2090170530Ssam			 *
2091170530Ssam			 * XXX don't probe the station unless we've
2092170530Ssam			 *     received a frame from them (and have
2093170530Ssam			 *     some idea of the rates they are capable
2094170530Ssam			 *     of); this will get fixed more properly
2095170530Ssam			 *     soon with better handling of the rate set.
2096138568Ssam			 */
2097178354Ssam			if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
2098172062Ssam			    (0 < ni->ni_inact &&
2099178354Ssam			     ni->ni_inact <= vap->iv_inact_probe) &&
2100170530Ssam			    ni->ni_rates.rs_nrates != 0) {
2101178354Ssam				IEEE80211_NOTE(vap,
2102148320Ssam				    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
2103148320Ssam				    ni, "%s",
2104148320Ssam				    "probe station due to inactivity");
2105148582Ssam				/*
2106148582Ssam				 * Grab a reference before unlocking the table
2107148582Ssam				 * so the node cannot be reclaimed before we
2108148582Ssam				 * send the frame. ieee80211_send_nulldata
2109148582Ssam				 * understands we've done this and reclaims the
2110148582Ssam				 * ref for us as needed.
2111148582Ssam				 */
2112148582Ssam				ieee80211_ref_node(ni);
2113138568Ssam				IEEE80211_NODE_UNLOCK(nt);
2114148301Ssam				ieee80211_send_nulldata(ni);
2115138568Ssam				/* XXX stat? */
2116138568Ssam				goto restart;
2117138568Ssam			}
2118138568Ssam		}
2119178354Ssam		if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
2120172062Ssam		    ni->ni_inact <= 0) {
2121178354Ssam			IEEE80211_NOTE(vap,
2122148320Ssam			    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
2123148320Ssam			    "station timed out due to inactivity "
2124148320Ssam			    "(refcnt %u)", ieee80211_node_refcnt(ni));
2125138568Ssam			/*
2126138568Ssam			 * Send a deauthenticate frame and drop the station.
2127138568Ssam			 * This is somewhat complicated due to reference counts
2128138568Ssam			 * and locking.  At this point a station will typically
2129138568Ssam			 * have a reference count of 1.  ieee80211_node_leave
2130138568Ssam			 * will do a "free" of the node which will drop the
2131138568Ssam			 * reference count.  But in the meantime a reference
2132138568Ssam			 * wil be held by the deauth frame.  The actual reclaim
2133138568Ssam			 * of the node will happen either after the tx is
2134138568Ssam			 * completed or by ieee80211_node_leave.
2135120483Ssam			 *
2136138568Ssam			 * Separately we must drop the node lock before sending
2137170530Ssam			 * in case the driver takes a lock, as this can result
2138170530Ssam			 * in a LOR between the node lock and the driver lock.
2139119150Ssam			 */
2140172229Ssam			ieee80211_ref_node(ni);
2141138568Ssam			IEEE80211_NODE_UNLOCK(nt);
2142138568Ssam			if (ni->ni_associd != 0) {
2143178354Ssam				IEEE80211_SEND_MGMT(ni,
2144138568Ssam				    IEEE80211_FC0_SUBTYPE_DEAUTH,
2145138568Ssam				    IEEE80211_REASON_AUTH_EXPIRE);
2146138568Ssam			}
2147178354Ssam			ieee80211_node_leave(ni);
2148172229Ssam			ieee80211_free_node(ni);
2149178354Ssam			vap->iv_stats.is_node_timeout++;
2150120483Ssam			goto restart;
2151120483Ssam		}
2152116742Ssam	}
2153138568Ssam	IEEE80211_NODE_UNLOCK(nt);
2154138568Ssam
2155178354Ssam	IEEE80211_NODE_ITERATE_UNLOCK(nt);
2156170530Ssam}
2157138568Ssam
2158178354Ssam/*
2159178354Ssam * Aggressively reclaim resources.  This should be used
2160178354Ssam * only in a critical situation to reclaim mbuf resources.
2161178354Ssam */
2162170530Ssamvoid
2163178354Ssamieee80211_drain(struct ieee80211com *ic)
2164178354Ssam{
2165178354Ssam	struct ieee80211_node_table *nt = &ic->ic_sta;
2166178354Ssam	struct ieee80211vap *vap;
2167178354Ssam	struct ieee80211_node *ni;
2168178354Ssam
2169178354Ssam	IEEE80211_NODE_LOCK(nt);
2170178354Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
2171178354Ssam		/*
2172178354Ssam		 * Ignore entries for which have yet to receive an
2173178354Ssam		 * authentication frame.  These are transient and
2174178354Ssam		 * will be reclaimed when the last reference to them
2175178354Ssam		 * goes away (when frame xmits complete).
2176178354Ssam		 */
2177178354Ssam		vap = ni->ni_vap;
2178178354Ssam		/*
2179178354Ssam		 * Only process stations when in RUN state.  This
2180178354Ssam		 * insures, for example, that we don't timeout an
2181178354Ssam		 * inactive station during CAC.  Note that CSA state
2182178354Ssam		 * is actually handled in ieee80211_node_timeout as
2183178354Ssam		 * it applies to more than timeout processing.
2184178354Ssam		 */
2185178354Ssam		if (vap->iv_state != IEEE80211_S_RUN)
2186178354Ssam			continue;
2187178354Ssam		/* XXX can vap be NULL? */
2188178354Ssam		if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
2189178354Ssam		     vap->iv_opmode == IEEE80211_M_STA) &&
2190178354Ssam		    (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
2191178354Ssam			continue;
2192178354Ssam		/*
2193178354Ssam		 * Free fragments.
2194178354Ssam		 * XXX doesn't belong here, move to node_drain
2195178354Ssam		 */
2196178354Ssam		if (ni->ni_rxfrag[0] != NULL) {
2197178354Ssam			m_freem(ni->ni_rxfrag[0]);
2198178354Ssam			ni->ni_rxfrag[0] = NULL;
2199178354Ssam		}
2200178354Ssam		/*
2201178354Ssam		 * Drain resources held by the station.
2202178354Ssam		 */
2203178354Ssam		ic->ic_node_drain(ni);
2204178354Ssam	}
2205178354Ssam	IEEE80211_NODE_UNLOCK(nt);
2206178354Ssam}
2207178354Ssam
2208178354Ssam/*
2209178354Ssam * Per-ieee80211com inactivity timer callback.
2210178354Ssam */
2211178354Ssamvoid
2212170530Ssamieee80211_node_timeout(void *arg)
2213170530Ssam{
2214170530Ssam	struct ieee80211com *ic = arg;
2215170530Ssam
2216178354Ssam	/*
2217178354Ssam	 * Defer timeout processing if a channel switch is pending.
2218178354Ssam	 * We typically need to be mute so not doing things that
2219178354Ssam	 * might generate frames is good to handle in one place.
2220178354Ssam	 * Supressing the station timeout processing may extend the
2221178354Ssam	 * lifetime of inactive stations (by not decrementing their
2222178354Ssam	 * idle counters) but this should be ok unless the CSA is
2223178354Ssam	 * active for an unusually long time.
2224178354Ssam	 */
2225178354Ssam	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
2226178354Ssam		ieee80211_scan_timeout(ic);
2227178354Ssam		ieee80211_timeout_stations(ic);
2228195379Ssam		ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT);
2229170530Ssam
2230178354Ssam		IEEE80211_LOCK(ic);
2231178354Ssam		ieee80211_erp_timeout(ic);
2232178354Ssam		ieee80211_ht_timeout(ic);
2233178354Ssam		IEEE80211_UNLOCK(ic);
2234178354Ssam	}
2235170530Ssam	callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
2236170530Ssam		ieee80211_node_timeout, ic);
2237116742Ssam}
2238116742Ssam
2239239312Sadrian/*
2240239312Sadrian * Iterate over the node table and return an array of ref'ed nodes.
2241239312Sadrian *
2242239312Sadrian * This is separated out from calling the actual node function so that
2243239312Sadrian * no LORs will occur.
2244239312Sadrian *
2245239312Sadrian * If there are too many nodes (ie, the number of nodes doesn't fit
2246239312Sadrian * within 'max_aid' entries) then the node references will be freed
2247239312Sadrian * and an error will be returned.
2248239312Sadrian *
2249239312Sadrian * The responsibility of allocating and freeing "ni_arr" is up to
2250239312Sadrian * the caller.
2251239312Sadrian */
2252239312Sadrianint
2253239312Sadrianieee80211_iterate_nt(struct ieee80211_node_table *nt,
2254239312Sadrian    struct ieee80211_node **ni_arr, uint16_t max_aid)
2255116742Ssam{
2256239312Sadrian	u_int gen;
2257239312Sadrian	int i, j, ret;
2258116742Ssam	struct ieee80211_node *ni;
2259116742Ssam
2260178354Ssam	IEEE80211_NODE_ITERATE_LOCK(nt);
2261239312Sadrian	IEEE80211_NODE_LOCK(nt);
2262239312Sadrian
2263154532Ssam	gen = ++nt->nt_scangen;
2264239312Sadrian	i = ret = 0;
2265239312Sadrian
2266239312Sadrian	/*
2267239312Sadrian	 * We simply assume here that since the node
2268239312Sadrian	 * scan generation doesn't change (as
2269239312Sadrian	 * we are holding both the node table and
2270239312Sadrian	 * node table iteration locks), we can simply
2271239312Sadrian	 * assign it to the node here.
2272239312Sadrian	 */
2273138568Ssam	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
2274239312Sadrian		if (i >= max_aid) {
2275239312Sadrian			ret = E2BIG;
2276283529Sglebius			ic_printf(nt->nt_ic, "Node array overflow: max=%u",
2277283529Sglebius			    max_aid);
2278239312Sadrian			break;
2279138568Ssam		}
2280239312Sadrian		ni_arr[i] = ieee80211_ref_node(ni);
2281239312Sadrian		ni_arr[i]->ni_scangen = gen;
2282239312Sadrian		i++;
2283138568Ssam	}
2284239312Sadrian
2285239312Sadrian	/*
2286239312Sadrian	 * It's safe to unlock here.
2287239312Sadrian	 *
2288239312Sadrian	 * If we're successful, the list is returned.
2289239312Sadrian	 * If we're unsuccessful, the list is ignored
2290239312Sadrian	 * and we remove our references.
2291239312Sadrian	 *
2292239312Sadrian	 * This avoids any potential LOR with
2293239312Sadrian	 * ieee80211_free_node().
2294239312Sadrian	 */
2295138568Ssam	IEEE80211_NODE_UNLOCK(nt);
2296239312Sadrian	IEEE80211_NODE_ITERATE_UNLOCK(nt);
2297138568Ssam
2298239312Sadrian	/*
2299239312Sadrian	 * If ret is non-zero, we hit some kind of error.
2300239312Sadrian	 * Rather than walking some nodes, we'll walk none
2301239312Sadrian	 * of them.
2302239312Sadrian	 */
2303239312Sadrian	if (ret) {
2304239312Sadrian		for (j = 0; j < i; j++) {
2305239312Sadrian			/* ieee80211_free_node() locks by itself */
2306239312Sadrian			ieee80211_free_node(ni_arr[j]);
2307239312Sadrian		}
2308239312Sadrian	}
2309239312Sadrian
2310239312Sadrian	return (ret);
2311116742Ssam}
2312138568Ssam
2313239312Sadrian/*
2314239312Sadrian * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
2315239312Sadrian * reference in the source.
2316239312Sadrian *
2317239312Sadrian * Note that this fetches 'max_aid' from the first VAP, rather than finding
2318239312Sadrian * the largest max_aid from all VAPs.
2319239312Sadrian */
2320138568Ssamvoid
2321239312Sadrianieee80211_iterate_nodes(struct ieee80211_node_table *nt,
2322239312Sadrian	ieee80211_iter_func *f, void *arg)
2323239312Sadrian{
2324239312Sadrian	struct ieee80211_node **ni_arr;
2325239319Sadrian	size_t size;
2326239312Sadrian	int i;
2327239312Sadrian	uint16_t max_aid;
2328240574Sadrian	struct ieee80211vap *vap;
2329239312Sadrian
2330240574Sadrian	/* Overdoing it default */
2331240574Sadrian	max_aid = IEEE80211_AID_MAX;
2332240574Sadrian
2333240574Sadrian	/* Handle the case of there being no vaps just yet */
2334240574Sadrian	vap = TAILQ_FIRST(&nt->nt_ic->ic_vaps);
2335240574Sadrian	if (vap != NULL)
2336240574Sadrian		max_aid = vap->iv_max_aid;
2337240574Sadrian
2338239312Sadrian	size = max_aid * sizeof(struct ieee80211_node *);
2339283538Sadrian	ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
2340283538Sadrian	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
2341239312Sadrian	if (ni_arr == NULL)
2342239312Sadrian		return;
2343239312Sadrian
2344239312Sadrian	/*
2345239312Sadrian	 * If this fails, the node table won't have any
2346239312Sadrian	 * valid entries - ieee80211_iterate_nt() frees
2347239312Sadrian	 * the references to them.  So don't try walking
2348239312Sadrian	 * the table; just skip to the end and free the
2349239312Sadrian	 * temporary memory.
2350239312Sadrian	 */
2351239319Sadrian	if (ieee80211_iterate_nt(nt, ni_arr, max_aid) != 0)
2352239312Sadrian		goto done;
2353239312Sadrian
2354239312Sadrian	for (i = 0; i < max_aid; i++) {
2355239312Sadrian		if (ni_arr[i] == NULL)	/* end of the list */
2356239312Sadrian			break;
2357239312Sadrian		(*f)(arg, ni_arr[i]);
2358239312Sadrian		/* ieee80211_free_node() locks by itself */
2359239312Sadrian		ieee80211_free_node(ni_arr[i]);
2360239312Sadrian	}
2361239312Sadrian
2362239312Sadriandone:
2363283538Sadrian	IEEE80211_FREE(ni_arr, M_80211_NODE);
2364239312Sadrian}
2365239312Sadrian
2366239312Sadrianvoid
2367138568Ssamieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
2368138568Ssam{
2369138568Ssam	printf("0x%p: mac %s refcnt %d\n", ni,
2370138568Ssam		ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
2371138568Ssam	printf("\tscangen %u authmode %u flags 0x%x\n",
2372138568Ssam		ni->ni_scangen, ni->ni_authmode, ni->ni_flags);
2373138568Ssam	printf("\tassocid 0x%x txpower %u vlan %u\n",
2374138568Ssam		ni->ni_associd, ni->ni_txpower, ni->ni_vlan);
2375138568Ssam	printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n",
2376167439Ssam		ni->ni_txseqs[IEEE80211_NONQOS_TID],
2377167439Ssam		ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT,
2378167439Ssam		ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK,
2379138568Ssam		ni->ni_rxfragstamp);
2380192468Ssam	printf("\trssi %d noise %d intval %u capinfo 0x%x\n",
2381192468Ssam		node_getrssi(ni), ni->ni_noise,
2382170530Ssam		ni->ni_intval, ni->ni_capinfo);
2383138568Ssam	printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n",
2384138568Ssam		ether_sprintf(ni->ni_bssid),
2385138568Ssam		ni->ni_esslen, ni->ni_essid,
2386138568Ssam		ni->ni_chan->ic_freq, ni->ni_chan->ic_flags);
2387184277Ssam	printf("\tinact %u inact_reload %u txrate %u\n",
2388184277Ssam		ni->ni_inact, ni->ni_inact_reload, ni->ni_txrate);
2389170530Ssam	printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n",
2390170530Ssam		ni->ni_htcap, ni->ni_htparam,
2391170530Ssam		ni->ni_htctlchan, ni->ni_ht2ndchan);
2392170530Ssam	printf("\thtopmode %x htstbc %x chw %u\n",
2393170530Ssam		ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw);
2394138568Ssam}
2395138568Ssam
2396138568Ssamvoid
2397138568Ssamieee80211_dump_nodes(struct ieee80211_node_table *nt)
2398138568Ssam{
2399138568Ssam	ieee80211_iterate_nodes(nt,
2400138568Ssam		(ieee80211_iter_func *) ieee80211_dump_node, nt);
2401138568Ssam}
2402138568Ssam
2403179642Ssamstatic void
2404179642Ssamieee80211_notify_erp_locked(struct ieee80211com *ic)
2405172211Ssam{
2406178354Ssam	struct ieee80211vap *vap;
2407178354Ssam
2408178354Ssam	IEEE80211_LOCK_ASSERT(ic);
2409178354Ssam
2410178354Ssam	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
2411178354Ssam		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2412178354Ssam			ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP);
2413172211Ssam}
2414172211Ssam
2415179642Ssamvoid
2416179642Ssamieee80211_notify_erp(struct ieee80211com *ic)
2417179642Ssam{
2418179642Ssam	IEEE80211_LOCK(ic);
2419179642Ssam	ieee80211_notify_erp_locked(ic);
2420179642Ssam	IEEE80211_UNLOCK(ic);
2421179642Ssam}
2422179642Ssam
2423138568Ssam/*
2424138568Ssam * Handle a station joining an 11g network.
2425138568Ssam */
2426138568Ssamstatic void
2427178354Ssamieee80211_node_join_11g(struct ieee80211_node *ni)
2428138568Ssam{
2429178354Ssam	struct ieee80211com *ic = ni->ni_ic;
2430138568Ssam
2431173273Ssam	IEEE80211_LOCK_ASSERT(ic);
2432173273Ssam
2433138568Ssam	/*
2434138568Ssam	 * Station isn't capable of short slot time.  Bump
2435138568Ssam	 * the count of long slot time stations and disable
2436138568Ssam	 * use of short slot time.  Note that the actual switch
2437138568Ssam	 * over to long slot time use may not occur until the
2438138568Ssam	 * next beacon transmission (per sec. 7.3.1.4 of 11g).
2439138568Ssam	 */
2440138568Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
2441138568Ssam		ic->ic_longslotsta++;
2442178354Ssam		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2443172211Ssam		    "station needs long slot time, count %d",
2444172211Ssam		    ic->ic_longslotsta);
2445138568Ssam		/* XXX vap's w/ conflicting needs won't work */
2446170530Ssam		if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) {
2447170530Ssam			/*
2448170530Ssam			 * Don't force slot time when switched to turbo
2449170530Ssam			 * mode as non-ERP stations won't be present; this
2450170530Ssam			 * need only be done when on the normal G channel.
2451170530Ssam			 */
2452170530Ssam			ieee80211_set_shortslottime(ic, 0);
2453170530Ssam		}
2454138568Ssam	}
2455138568Ssam	/*
2456138568Ssam	 * If the new station is not an ERP station
2457138568Ssam	 * then bump the counter and enable protection
2458138568Ssam	 * if configured.
2459138568Ssam	 */
2460178354Ssam	if (!ieee80211_iserp_rateset(&ni->ni_rates)) {
2461138568Ssam		ic->ic_nonerpsta++;
2462178354Ssam		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2463172211Ssam		    "station is !ERP, %d non-ERP stations associated",
2464172211Ssam		    ic->ic_nonerpsta);
2465138568Ssam		/*
2466138568Ssam		 * If station does not support short preamble
2467138568Ssam		 * then we must enable use of Barker preamble.
2468138568Ssam		 */
2469138568Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
2470178354Ssam			IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2471172211Ssam			    "%s", "station needs long preamble");
2472138568Ssam			ic->ic_flags |= IEEE80211_F_USEBARKER;
2473138568Ssam			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
2474138568Ssam		}
2475172211Ssam		/*
2476178354Ssam		 * If protection is configured and this is the first
2477178354Ssam		 * indication we should use protection, enable it.
2478172211Ssam		 */
2479172211Ssam		if (ic->ic_protmode != IEEE80211_PROT_NONE &&
2480172211Ssam		    ic->ic_nonerpsta == 1 &&
2481172211Ssam		    (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
2482178354Ssam			IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
2483172211Ssam			    "%s: enable use of protection\n", __func__);
2484172211Ssam			ic->ic_flags |= IEEE80211_F_USEPROT;
2485179642Ssam			ieee80211_notify_erp_locked(ic);
2486172211Ssam		}
2487138568Ssam	} else
2488138568Ssam		ni->ni_flags |= IEEE80211_NODE_ERP;
2489138568Ssam}
2490138568Ssam
2491138568Ssamvoid
2492178354Ssamieee80211_node_join(struct ieee80211_node *ni, int resp)
2493138568Ssam{
2494178354Ssam	struct ieee80211com *ic = ni->ni_ic;
2495178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2496138568Ssam	int newassoc;
2497138568Ssam
2498138568Ssam	if (ni->ni_associd == 0) {
2499170530Ssam		uint16_t aid;
2500138568Ssam
2501178354Ssam		KASSERT(vap->iv_aid_bitmap != NULL, ("no aid bitmap"));
2502138568Ssam		/*
2503138568Ssam		 * It would be good to search the bitmap
2504138568Ssam		 * more efficiently, but this will do for now.
2505138568Ssam		 */
2506178354Ssam		for (aid = 1; aid < vap->iv_max_aid; aid++) {
2507178354Ssam			if (!IEEE80211_AID_ISSET(vap, aid))
2508138568Ssam				break;
2509138568Ssam		}
2510178354Ssam		if (aid >= vap->iv_max_aid) {
2511179640Ssam			IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_TOOMANY);
2512178354Ssam			ieee80211_node_leave(ni);
2513138568Ssam			return;
2514138568Ssam		}
2515138568Ssam		ni->ni_associd = aid | 0xc000;
2516173273Ssam		ni->ni_jointime = time_uptime;
2517178354Ssam		IEEE80211_LOCK(ic);
2518178354Ssam		IEEE80211_AID_SET(vap, ni->ni_associd);
2519178354Ssam		vap->iv_sta_assoc++;
2520138568Ssam		ic->ic_sta_assoc++;
2521173273Ssam
2522173273Ssam		if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2523173273Ssam			ieee80211_ht_node_join(ni);
2524170530Ssam		if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
2525170530Ssam		    IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
2526178354Ssam			ieee80211_node_join_11g(ni);
2527173273Ssam		IEEE80211_UNLOCK(ic);
2528173273Ssam
2529173273Ssam		newassoc = 1;
2530138568Ssam	} else
2531138568Ssam		newassoc = 0;
2532138568Ssam
2533178354Ssam	IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni,
2534183256Ssam	    "station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s",
2535139523Ssam	    IEEE80211_NODE_AID(ni),
2536139523Ssam	    ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
2537139523Ssam	    ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long",
2538139523Ssam	    ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "",
2539170530Ssam	    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
2540170530Ssam	    ni->ni_flags & IEEE80211_NODE_HT ?
2541182834Ssam		(ni->ni_chw == 40 ? ", HT40" : ", HT20") : "",
2542173273Ssam	    ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
2543183255Ssam	    ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
2544183255Ssam	        ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "",
2545183256Ssam	    ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "",
2546178354Ssam	    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ?
2547170530Ssam		", fast-frames" : "",
2548178354Ssam	    IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ?
2549170530Ssam		", turbo" : ""
2550139523Ssam	);
2551138568Ssam
2552193966Ssam	ieee80211_node_setuptxparms(ni);
2553214894Sbschmidt	ieee80211_ratectl_node_init(ni);
2554138568Ssam	/* give driver a chance to setup state like ni_txrate */
2555139524Ssam	if (ic->ic_newassoc != NULL)
2556148307Ssam		ic->ic_newassoc(ni, newassoc);
2557178354Ssam	IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_SUCCESS);
2558138568Ssam	/* tell the authenticator about new station */
2559178354Ssam	if (vap->iv_auth->ia_node_join != NULL)
2560178354Ssam		vap->iv_auth->ia_node_join(ni);
2561178354Ssam	ieee80211_notify_node_join(ni,
2562173866Ssam	    resp == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
2563138568Ssam}
2564138568Ssam
2565172211Ssamstatic void
2566172211Ssamdisable_protection(struct ieee80211com *ic)
2567172211Ssam{
2568172211Ssam	KASSERT(ic->ic_nonerpsta == 0 &&
2569172211Ssam	    (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0,
2570172211Ssam	   ("%d non ERP stations, flags 0x%x", ic->ic_nonerpsta,
2571172211Ssam	   ic->ic_flags_ext));
2572172211Ssam
2573172211Ssam	ic->ic_flags &= ~IEEE80211_F_USEPROT;
2574172211Ssam	/* XXX verify mode? */
2575172211Ssam	if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
2576172211Ssam		ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
2577172211Ssam		ic->ic_flags &= ~IEEE80211_F_USEBARKER;
2578172211Ssam	}
2579179642Ssam	ieee80211_notify_erp_locked(ic);
2580172211Ssam}
2581172211Ssam
2582138568Ssam/*
2583138568Ssam * Handle a station leaving an 11g network.
2584138568Ssam */
2585138568Ssamstatic void
2586178354Ssamieee80211_node_leave_11g(struct ieee80211_node *ni)
2587138568Ssam{
2588178354Ssam	struct ieee80211com *ic = ni->ni_ic;
2589138568Ssam
2590173273Ssam	IEEE80211_LOCK_ASSERT(ic);
2591173273Ssam
2592170530Ssam	KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan),
2593178354Ssam	     ("not in 11g, bss %u:0x%x", ic->ic_bsschan->ic_freq,
2594178354Ssam	      ic->ic_bsschan->ic_flags));
2595138568Ssam
2596138568Ssam	/*
2597138568Ssam	 * If a long slot station do the slot time bookkeeping.
2598138568Ssam	 */
2599138568Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
2600138568Ssam		KASSERT(ic->ic_longslotsta > 0,
2601138568Ssam		    ("bogus long slot station count %d", ic->ic_longslotsta));
2602138568Ssam		ic->ic_longslotsta--;
2603178354Ssam		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2604172211Ssam		    "long slot time station leaves, count now %d",
2605172211Ssam		    ic->ic_longslotsta);
2606138568Ssam		if (ic->ic_longslotsta == 0) {
2607138568Ssam			/*
2608138568Ssam			 * Re-enable use of short slot time if supported
2609138568Ssam			 * and not operating in IBSS mode (per spec).
2610138568Ssam			 */
2611138568Ssam			if ((ic->ic_caps & IEEE80211_C_SHSLOT) &&
2612138568Ssam			    ic->ic_opmode != IEEE80211_M_IBSS) {
2613178354Ssam				IEEE80211_DPRINTF(ni->ni_vap,
2614178354Ssam				    IEEE80211_MSG_ASSOC,
2615138568Ssam				    "%s: re-enable use of short slot time\n",
2616138568Ssam				    __func__);
2617138568Ssam				ieee80211_set_shortslottime(ic, 1);
2618138568Ssam			}
2619138568Ssam		}
2620138568Ssam	}
2621138568Ssam	/*
2622138568Ssam	 * If a non-ERP station do the protection-related bookkeeping.
2623138568Ssam	 */
2624138568Ssam	if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
2625138568Ssam		KASSERT(ic->ic_nonerpsta > 0,
2626138568Ssam		    ("bogus non-ERP station count %d", ic->ic_nonerpsta));
2627138568Ssam		ic->ic_nonerpsta--;
2628178354Ssam		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2629172211Ssam		    "non-ERP station leaves, count now %d%s", ic->ic_nonerpsta,
2630172211Ssam		    (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) ?
2631172211Ssam			" (non-ERP sta present)" : "");
2632172211Ssam		if (ic->ic_nonerpsta == 0 &&
2633172211Ssam		    (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
2634178354Ssam			IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
2635138568Ssam				"%s: disable use of protection\n", __func__);
2636172211Ssam			disable_protection(ic);
2637138568Ssam		}
2638138568Ssam	}
2639138568Ssam}
2640138568Ssam
2641138568Ssam/*
2642172211Ssam * Time out presence of an overlapping bss with non-ERP
2643172211Ssam * stations.  When operating in hostap mode we listen for
2644172211Ssam * beacons from other stations and if we identify a non-ERP
2645172211Ssam * station is present we enable protection.  To identify
2646172211Ssam * when all non-ERP stations are gone we time out this
2647172211Ssam * condition.
2648172211Ssam */
2649172211Ssamstatic void
2650172211Ssamieee80211_erp_timeout(struct ieee80211com *ic)
2651172211Ssam{
2652172211Ssam
2653172211Ssam	IEEE80211_LOCK_ASSERT(ic);
2654172211Ssam
2655172211Ssam	if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) &&
2656297405Sadrian	    ieee80211_time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
2657178354Ssam#if 0
2658178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
2659178354Ssam		    "%s", "age out non-ERP sta present on channel");
2660178354Ssam#endif
2661172211Ssam		ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
2662172211Ssam		if (ic->ic_nonerpsta == 0)
2663172211Ssam			disable_protection(ic);
2664172211Ssam	}
2665172211Ssam}
2666172211Ssam
2667172211Ssam/*
2668138568Ssam * Handle bookkeeping for station deauthentication/disassociation
2669138568Ssam * when operating as an ap.
2670138568Ssam */
2671138568Ssamvoid
2672178354Ssamieee80211_node_leave(struct ieee80211_node *ni)
2673138568Ssam{
2674178354Ssam	struct ieee80211com *ic = ni->ni_ic;
2675178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2676140499Ssam	struct ieee80211_node_table *nt = ni->ni_table;
2677138568Ssam
2678178354Ssam	IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni,
2679172211Ssam	    "station with aid %d leaves", IEEE80211_NODE_AID(ni));
2680138568Ssam
2681178354Ssam	KASSERT(vap->iv_opmode != IEEE80211_M_STA,
2682178354Ssam		("unexpected operating mode %u", vap->iv_opmode));
2683138568Ssam	/*
2684138568Ssam	 * If node wasn't previously associated all
2685138568Ssam	 * we need to do is reclaim the reference.
2686138568Ssam	 */
2687138568Ssam	/* XXX ibss mode bypasses 11g and notification */
2688138568Ssam	if (ni->ni_associd == 0)
2689138568Ssam		goto done;
2690138568Ssam	/*
2691138568Ssam	 * Tell the authenticator the station is leaving.
2692138568Ssam	 * Note that we must do this before yanking the
2693138568Ssam	 * association id as the authenticator uses the
2694138568Ssam	 * associd to locate it's state block.
2695138568Ssam	 */
2696178354Ssam	if (vap->iv_auth->ia_node_leave != NULL)
2697178354Ssam		vap->iv_auth->ia_node_leave(ni);
2698173273Ssam
2699173273Ssam	IEEE80211_LOCK(ic);
2700178354Ssam	IEEE80211_AID_CLR(vap, ni->ni_associd);
2701178354Ssam	vap->iv_sta_assoc--;
2702138568Ssam	ic->ic_sta_assoc--;
2703138568Ssam
2704173273Ssam	if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2705173273Ssam		ieee80211_ht_node_leave(ni);
2706170530Ssam	if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
2707170530Ssam	    IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
2708178354Ssam		ieee80211_node_leave_11g(ni);
2709173273Ssam	IEEE80211_UNLOCK(ic);
2710138568Ssam	/*
2711138568Ssam	 * Cleanup station state.  In particular clear various
2712138568Ssam	 * state that might otherwise be reused if the node
2713138568Ssam	 * is reused before the reference count goes to zero
2714138568Ssam	 * (and memory is reclaimed).
2715138568Ssam	 */
2716178354Ssam	ieee80211_sta_leave(ni);
2717138568Ssamdone:
2718140499Ssam	/*
2719140499Ssam	 * Remove the node from any table it's recorded in and
2720140499Ssam	 * drop the caller's reference.  Removal from the table
2721140499Ssam	 * is important to insure the node is not reprocessed
2722140499Ssam	 * for inactivity.
2723140499Ssam	 */
2724140499Ssam	if (nt != NULL) {
2725140499Ssam		IEEE80211_NODE_LOCK(nt);
2726140499Ssam		node_reclaim(nt, ni);
2727140499Ssam		IEEE80211_NODE_UNLOCK(nt);
2728140499Ssam	} else
2729140499Ssam		ieee80211_free_node(ni);
2730138568Ssam}
2731138568Ssam
2732178354Ssamstruct rssiinfo {
2733178354Ssam	struct ieee80211vap *vap;
2734178354Ssam	int	rssi_samples;
2735178354Ssam	uint32_t rssi_total;
2736178354Ssam};
2737178354Ssam
2738178354Ssamstatic void
2739178354Ssamget_hostap_rssi(void *arg, struct ieee80211_node *ni)
2740178354Ssam{
2741178354Ssam	struct rssiinfo *info = arg;
2742178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2743178354Ssam	int8_t rssi;
2744178354Ssam
2745178354Ssam	if (info->vap != vap)
2746178354Ssam		return;
2747178354Ssam	/* only associated stations */
2748178354Ssam	if (ni->ni_associd == 0)
2749178354Ssam		return;
2750178354Ssam	rssi = vap->iv_ic->ic_node_getrssi(ni);
2751178354Ssam	if (rssi != 0) {
2752178354Ssam		info->rssi_samples++;
2753178354Ssam		info->rssi_total += rssi;
2754178354Ssam	}
2755178354Ssam}
2756178354Ssam
2757178354Ssamstatic void
2758178354Ssamget_adhoc_rssi(void *arg, struct ieee80211_node *ni)
2759178354Ssam{
2760178354Ssam	struct rssiinfo *info = arg;
2761178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2762178354Ssam	int8_t rssi;
2763178354Ssam
2764178354Ssam	if (info->vap != vap)
2765178354Ssam		return;
2766178354Ssam	/* only neighbors */
2767178354Ssam	/* XXX check bssid */
2768178354Ssam	if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
2769178354Ssam		return;
2770178354Ssam	rssi = vap->iv_ic->ic_node_getrssi(ni);
2771178354Ssam	if (rssi != 0) {
2772178354Ssam		info->rssi_samples++;
2773178354Ssam		info->rssi_total += rssi;
2774178354Ssam	}
2775178354Ssam}
2776178354Ssam
2777195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
2778195618Srpaulostatic void
2779195618Srpauloget_mesh_rssi(void *arg, struct ieee80211_node *ni)
2780195618Srpaulo{
2781195618Srpaulo	struct rssiinfo *info = arg;
2782195618Srpaulo	struct ieee80211vap *vap = ni->ni_vap;
2783195618Srpaulo	int8_t rssi;
2784195618Srpaulo
2785195618Srpaulo	if (info->vap != vap)
2786195618Srpaulo		return;
2787195618Srpaulo	/* only neighbors that peered successfully */
2788195618Srpaulo	if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
2789195618Srpaulo		return;
2790195618Srpaulo	rssi = vap->iv_ic->ic_node_getrssi(ni);
2791195618Srpaulo	if (rssi != 0) {
2792195618Srpaulo		info->rssi_samples++;
2793195618Srpaulo		info->rssi_total += rssi;
2794195618Srpaulo	}
2795195618Srpaulo}
2796195618Srpaulo#endif /* IEEE80211_SUPPORT_MESH */
2797195618Srpaulo
2798170530Ssamint8_t
2799178354Ssamieee80211_getrssi(struct ieee80211vap *vap)
2800138568Ssam{
2801138568Ssam#define	NZ(x)	((x) == 0 ? 1 : (x))
2802178354Ssam	struct ieee80211com *ic = vap->iv_ic;
2803178354Ssam	struct rssiinfo info;
2804138568Ssam
2805178354Ssam	info.rssi_total = 0;
2806178354Ssam	info.rssi_samples = 0;
2807178354Ssam	info.vap = vap;
2808178354Ssam	switch (vap->iv_opmode) {
2809138568Ssam	case IEEE80211_M_IBSS:		/* average of all ibss neighbors */
2810138568Ssam	case IEEE80211_M_AHDEMO:	/* average of all neighbors */
2811178354Ssam		ieee80211_iterate_nodes(&ic->ic_sta, get_adhoc_rssi, &info);
2812178354Ssam		break;
2813138568Ssam	case IEEE80211_M_HOSTAP:	/* average of all associated stations */
2814178354Ssam		ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info);
2815138568Ssam		break;
2816195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH
2817195618Srpaulo	case IEEE80211_M_MBSS:		/* average of all mesh neighbors */
2818195618Srpaulo		ieee80211_iterate_nodes(&ic->ic_sta, get_mesh_rssi, &info);
2819195618Srpaulo		break;
2820195618Srpaulo#endif
2821138568Ssam	case IEEE80211_M_MONITOR:	/* XXX */
2822138568Ssam	case IEEE80211_M_STA:		/* use stats from associated ap */
2823138568Ssam	default:
2824178354Ssam		if (vap->iv_bss != NULL)
2825178354Ssam			info.rssi_total = ic->ic_node_getrssi(vap->iv_bss);
2826178354Ssam		info.rssi_samples = 1;
2827138568Ssam		break;
2828138568Ssam	}
2829178354Ssam	return info.rssi_total / NZ(info.rssi_samples);
2830138568Ssam#undef NZ
2831138568Ssam}
2832138568Ssam
2833170530Ssamvoid
2834178354Ssamieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise)
2835138568Ssam{
2836138568Ssam
2837178354Ssam	if (vap->iv_bss == NULL)		/* NB: shouldn't happen */
2838170530Ssam		return;
2839178354Ssam	vap->iv_ic->ic_node_getsignal(vap->iv_bss, rssi, noise);
2840170530Ssam	/* for non-station mode return avg'd rssi accounting */
2841178354Ssam	if (vap->iv_opmode != IEEE80211_M_STA)
2842178354Ssam		*rssi = ieee80211_getrssi(vap);
2843138568Ssam}
2844