xref: /openbsd-src/sys/net80211/ieee80211_node.c (revision 9593dc34da13a12012033a17061c846c208061c2)
1*9593dc34Smglocker /*	$OpenBSD: ieee80211_node.c,v 1.199 2024/09/04 07:54:52 mglocker Exp $	*/
291b2158bSmillert /*	$NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $	*/
391b2158bSmillert 
491b2158bSmillert /*-
591b2158bSmillert  * Copyright (c) 2001 Atsushi Onoe
691b2158bSmillert  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7f91ff320Sdamien  * Copyright (c) 2008 Damien Bergamini
891b2158bSmillert  * All rights reserved.
991b2158bSmillert  *
1091b2158bSmillert  * Redistribution and use in source and binary forms, with or without
1191b2158bSmillert  * modification, are permitted provided that the following conditions
1291b2158bSmillert  * are met:
1391b2158bSmillert  * 1. Redistributions of source code must retain the above copyright
1491b2158bSmillert  *    notice, this list of conditions and the following disclaimer.
1591b2158bSmillert  * 2. Redistributions in binary form must reproduce the above copyright
1691b2158bSmillert  *    notice, this list of conditions and the following disclaimer in the
1791b2158bSmillert  *    documentation and/or other materials provided with the distribution.
1891b2158bSmillert  * 3. The name of the author may not be used to endorse or promote products
1991b2158bSmillert  *    derived from this software without specific prior written permission.
2091b2158bSmillert  *
2191b2158bSmillert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2291b2158bSmillert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2391b2158bSmillert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2491b2158bSmillert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2591b2158bSmillert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2691b2158bSmillert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2791b2158bSmillert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2891b2158bSmillert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2991b2158bSmillert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3091b2158bSmillert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3191b2158bSmillert  */
3291b2158bSmillert 
33b64f3d33Sreyk #include "bridge.h"
3491b2158bSmillert 
3591b2158bSmillert #include <sys/param.h>
3691b2158bSmillert #include <sys/systm.h>
3791b2158bSmillert #include <sys/mbuf.h>
3891b2158bSmillert #include <sys/malloc.h>
3991b2158bSmillert #include <sys/kernel.h>
4091b2158bSmillert #include <sys/socket.h>
4191b2158bSmillert #include <sys/sockio.h>
4291b2158bSmillert #include <sys/endian.h>
4391b2158bSmillert #include <sys/errno.h>
4491b2158bSmillert #include <sys/sysctl.h>
453ce67372Sreyk #include <sys/tree.h>
4691b2158bSmillert 
4791b2158bSmillert #include <net/if.h>
4891b2158bSmillert #include <net/if_dl.h>
4991b2158bSmillert #include <net/if_media.h>
5091b2158bSmillert 
5191b2158bSmillert #include <netinet/in.h>
5291b2158bSmillert #include <netinet/if_ether.h>
5391b2158bSmillert 
54b64f3d33Sreyk #if NBRIDGE > 0
55b64f3d33Sreyk #include <net/if_bridge.h>
56b64f3d33Sreyk #endif
57b64f3d33Sreyk 
5891b2158bSmillert #include <net80211/ieee80211_var.h>
596aaa29faSdamien #include <net80211/ieee80211_priv.h>
6091b2158bSmillert 
61250085e6Sdamien struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *);
62250085e6Sdamien void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *);
63250085e6Sdamien void ieee80211_node_copy(struct ieee80211com *, struct ieee80211_node *,
64250085e6Sdamien     const struct ieee80211_node *);
65f91ff320Sdamien void ieee80211_choose_rsnparams(struct ieee80211com *);
66250085e6Sdamien u_int8_t ieee80211_node_getrssi(struct ieee80211com *,
67f22d9adcSdamien     const struct ieee80211_node *);
6806e069b5Sstsp int ieee80211_node_checkrssi(struct ieee80211com *,
6906e069b5Sstsp     const struct ieee80211_node *);
70020402a2Sphessler int ieee80211_ess_is_better(struct ieee80211com *ic, struct ieee80211_node *,
71020402a2Sphessler     struct ieee80211_node *);
72aefc44daSstsp void ieee80211_node_set_timeouts(struct ieee80211_node *);
73250085e6Sdamien void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *,
74f22d9adcSdamien     const u_int8_t *);
75250085e6Sdamien struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
76de9c1173Sstsp void ieee80211_node_free_unref_cb(struct ieee80211_node *);
77de9c1173Sstsp void ieee80211_node_tx_flushed(struct ieee80211com *, struct ieee80211_node *);
7806e069b5Sstsp void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *);
79aefc44daSstsp void ieee80211_node_addba_request(struct ieee80211_node *, int);
80aefc44daSstsp void ieee80211_node_addba_request_ac_be_to(void *);
81aefc44daSstsp void ieee80211_node_addba_request_ac_bk_to(void *);
82aefc44daSstsp void ieee80211_node_addba_request_ac_vi_to(void *);
83aefc44daSstsp void ieee80211_node_addba_request_ac_vo_to(void *);
84f91ff320Sdamien void ieee80211_needs_auth(struct ieee80211com *, struct ieee80211_node *);
85171ac09aSdamien #ifndef IEEE80211_STA_ONLY
8645eec175Sdamien void ieee80211_node_join_ht(struct ieee80211com *, struct ieee80211_node *);
87e03e709cSdamien void ieee80211_node_join_rsn(struct ieee80211com *, struct ieee80211_node *);
88250085e6Sdamien void ieee80211_node_join_11g(struct ieee80211com *, struct ieee80211_node *);
8945eec175Sdamien void ieee80211_node_leave_ht(struct ieee80211com *, struct ieee80211_node *);
9050e8fe1cSstsp void ieee80211_node_leave_vht(struct ieee80211com *, struct ieee80211_node *);
91e03e709cSdamien void ieee80211_node_leave_rsn(struct ieee80211com *, struct ieee80211_node *);
92250085e6Sdamien void ieee80211_node_leave_11g(struct ieee80211com *, struct ieee80211_node *);
93a6224a8bSstsp void ieee80211_node_leave_pwrsave(struct ieee80211com *,
94a6224a8bSstsp     struct ieee80211_node *);
959c2641a5Sstsp void ieee80211_inact_timeout(void *);
969c2641a5Sstsp void ieee80211_node_cache_timeout(void *);
97171ac09aSdamien #endif
986a173c79Sstsp void ieee80211_clean_inactive_nodes(struct ieee80211com *, int);
9991b2158bSmillert 
1009c2641a5Sstsp #ifndef IEEE80211_STA_ONLY
1019c2641a5Sstsp void
1029c2641a5Sstsp ieee80211_inact_timeout(void *arg)
1039c2641a5Sstsp {
1049c2641a5Sstsp 	struct ieee80211com *ic = arg;
1059c2641a5Sstsp 	struct ieee80211_node *ni, *next_ni;
1069c2641a5Sstsp 	int s;
1079c2641a5Sstsp 
1089c2641a5Sstsp 	s = splnet();
1098529d8f0Sdlg 	for (ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
1109c2641a5Sstsp 	    ni != NULL; ni = next_ni) {
1118529d8f0Sdlg 		next_ni = RBT_NEXT(ieee80211_tree, ni);
1129c2641a5Sstsp 		if (ni->ni_refcnt > 0)
1139c2641a5Sstsp 			continue;
1149c2641a5Sstsp 		if (ni->ni_inact < IEEE80211_INACT_MAX)
1159c2641a5Sstsp 			ni->ni_inact++;
1169c2641a5Sstsp 	}
1179c2641a5Sstsp 	splx(s);
1189c2641a5Sstsp 
1199c2641a5Sstsp 	timeout_add_sec(&ic->ic_inact_timeout, IEEE80211_INACT_WAIT);
1209c2641a5Sstsp }
1219c2641a5Sstsp 
1229c2641a5Sstsp void
1239c2641a5Sstsp ieee80211_node_cache_timeout(void *arg)
1249c2641a5Sstsp {
1259c2641a5Sstsp 	struct ieee80211com *ic = arg;
1269c2641a5Sstsp 
1279c2641a5Sstsp 	ieee80211_clean_nodes(ic, 1);
1289c2641a5Sstsp 	timeout_add_sec(&ic->ic_node_cache_timeout, IEEE80211_CACHE_WAIT);
1299c2641a5Sstsp }
1309c2641a5Sstsp #endif
1319c2641a5Sstsp 
132020402a2Sphessler /*
133020402a2Sphessler  * For debug purposes
134020402a2Sphessler  */
135020402a2Sphessler void
136020402a2Sphessler ieee80211_print_ess(struct ieee80211_ess *ess)
137020402a2Sphessler {
138020402a2Sphessler 	ieee80211_print_essid(ess->essid, ess->esslen);
139020402a2Sphessler 	if (ess->flags & IEEE80211_F_RSNON) {
140020402a2Sphessler 		printf(" wpa");
141020402a2Sphessler 		if (ess->rsnprotos & IEEE80211_PROTO_RSN)
142020402a2Sphessler 			printf(",wpa2");
143020402a2Sphessler 		if (ess->rsnprotos & IEEE80211_PROTO_WPA)
144020402a2Sphessler 			printf(",wpa1");
145020402a2Sphessler 
146020402a2Sphessler 		if (ess->rsnakms & IEEE80211_AKM_8021X ||
147020402a2Sphessler 		    ess->rsnakms & IEEE80211_AKM_SHA256_8021X)
148020402a2Sphessler 			printf(",802.1x");
149020402a2Sphessler 		printf(" ");
150020402a2Sphessler 
151020402a2Sphessler 		if (ess->rsnciphers & IEEE80211_CIPHER_USEGROUP)
152020402a2Sphessler 			printf(" usegroup");
153020402a2Sphessler 		if (ess->rsnciphers & IEEE80211_CIPHER_WEP40)
154020402a2Sphessler 			printf(" wep40");
155020402a2Sphessler 		if (ess->rsnciphers & IEEE80211_CIPHER_WEP104)
156020402a2Sphessler 			printf(" wep104");
157020402a2Sphessler 		if (ess->rsnciphers & IEEE80211_CIPHER_TKIP)
158020402a2Sphessler 			printf(" tkip");
159020402a2Sphessler 		if (ess->rsnciphers & IEEE80211_CIPHER_CCMP)
160020402a2Sphessler 			printf(" ccmp");
161020402a2Sphessler 	}
162020402a2Sphessler 	if (ess->flags & IEEE80211_F_WEPON) {
163020402a2Sphessler 		int i = ess->def_txkey;
164020402a2Sphessler 
165020402a2Sphessler 		printf(" wep,");
166020402a2Sphessler 		if (ess->nw_keys[i].k_cipher & IEEE80211_CIPHER_WEP40)
167020402a2Sphessler 			printf("wep40");
168020402a2Sphessler 		if (ess->nw_keys[i].k_cipher & IEEE80211_CIPHER_WEP104)
169020402a2Sphessler 			printf("wep104");
170020402a2Sphessler 	}
171020402a2Sphessler 	if (ess->flags == 0)
172020402a2Sphessler 		printf(" clear");
173020402a2Sphessler 	printf("\n");
174020402a2Sphessler }
175020402a2Sphessler 
176020402a2Sphessler void
177020402a2Sphessler ieee80211_print_ess_list(struct ieee80211com *ic)
178020402a2Sphessler {
179020402a2Sphessler 	struct ifnet		*ifp = &ic->ic_if;
180020402a2Sphessler 	struct ieee80211_ess	*ess;
181020402a2Sphessler 
182020402a2Sphessler 	printf("%s: known networks\n", ifp->if_xname);
183020402a2Sphessler 	TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
184020402a2Sphessler 		ieee80211_print_ess(ess);
185020402a2Sphessler 	}
186020402a2Sphessler }
187020402a2Sphessler 
188d6390b08Sphessler struct ieee80211_ess *
189d6390b08Sphessler ieee80211_get_ess(struct ieee80211com *ic, const char *nwid, int len)
190d6390b08Sphessler {
191d6390b08Sphessler 	struct ieee80211_ess	*ess;
192d6390b08Sphessler 
193d6390b08Sphessler 	TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
194d6390b08Sphessler 		if (len == ess->esslen &&
195d6390b08Sphessler 		    memcmp(ess->essid, nwid, ess->esslen) == 0)
196d6390b08Sphessler 			return ess;
197d6390b08Sphessler 	}
198d6390b08Sphessler 
199d6390b08Sphessler 	return NULL;
200d6390b08Sphessler }
201d6390b08Sphessler 
202020402a2Sphessler void
203157eb8fdSphessler ieee80211_del_ess(struct ieee80211com *ic, char *nwid, int len, int all)
204020402a2Sphessler {
205020402a2Sphessler 	struct ieee80211_ess *ess, *next;
206020402a2Sphessler 
207020402a2Sphessler 	TAILQ_FOREACH_SAFE(ess, &ic->ic_ess, ess_next, next) {
208157eb8fdSphessler 		if (all == 1 || (ess->esslen == len &&
209157eb8fdSphessler 		    memcmp(ess->essid, nwid, len) == 0)) {
210020402a2Sphessler 			TAILQ_REMOVE(&ic->ic_ess, ess, ess_next);
211020402a2Sphessler 			explicit_bzero(ess, sizeof(*ess));
212020402a2Sphessler 			free(ess, M_DEVBUF, sizeof(*ess));
2136aa27acdSphessler 			if (TAILQ_EMPTY(&ic->ic_ess))
2146aa27acdSphessler 				ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN;
215020402a2Sphessler 			if (all != 1)
216020402a2Sphessler 				return;
217020402a2Sphessler 		}
218020402a2Sphessler 	}
219020402a2Sphessler }
220020402a2Sphessler 
221d6390b08Sphessler /* Keep in sync with ieee80211_ioctl.c:ieee80211_ioctl_setnwkeys() */
222d6390b08Sphessler static int
223d6390b08Sphessler ieee80211_ess_setnwkeys(struct ieee80211_ess *ess,
224d6390b08Sphessler     const struct ieee80211_nwkey *nwkey)
225d6390b08Sphessler {
226d6390b08Sphessler 	struct ieee80211_key *k;
2277a03e627Sphessler 	int error, i;
228d6390b08Sphessler 
229d6390b08Sphessler 	if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
230d6390b08Sphessler 		if (!(ess->flags & IEEE80211_F_WEPON))
231d6390b08Sphessler 			return 0;
232d6390b08Sphessler 		ess->flags &= ~IEEE80211_F_WEPON;
233d6390b08Sphessler 		return ENETRESET;
234d6390b08Sphessler 	}
235d6390b08Sphessler 	if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID)
236d6390b08Sphessler 		return EINVAL;
237d6390b08Sphessler 
238d6390b08Sphessler 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
239d6390b08Sphessler 		if (nwkey->i_key[i].i_keylen == 0 ||
240d6390b08Sphessler 		    nwkey->i_key[i].i_keydat == NULL)
241d6390b08Sphessler 			continue;	/* entry not set */
242d6390b08Sphessler 		if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE)
243d6390b08Sphessler 			return EINVAL;
244d6390b08Sphessler 
245d6390b08Sphessler 		/* map wep key to ieee80211_key */
246d6390b08Sphessler 		k = &ess->nw_keys[i];
247d6390b08Sphessler 		memset(k, 0, sizeof(*k));
248d6390b08Sphessler 		if (nwkey->i_key[i].i_keylen <= 5)
249d6390b08Sphessler 			k->k_cipher = IEEE80211_CIPHER_WEP40;
250d6390b08Sphessler 		else
251d6390b08Sphessler 			k->k_cipher = IEEE80211_CIPHER_WEP104;
252d6390b08Sphessler 		k->k_len = ieee80211_cipher_keylen(k->k_cipher);
253d6390b08Sphessler 		k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
2547a03e627Sphessler 		error = copyin(nwkey->i_key[i].i_keydat, k->k_key, k->k_len);
2557a03e627Sphessler 		if (error != 0)
2567a03e627Sphessler 			return error;
257d6390b08Sphessler 	}
258d6390b08Sphessler 	ess->def_txkey = nwkey->i_defkid - 1;
259d6390b08Sphessler 	ess->flags |= IEEE80211_F_WEPON;
260d6390b08Sphessler 
261d6390b08Sphessler 	return ENETRESET;
262d6390b08Sphessler }
263d6390b08Sphessler 
264d6390b08Sphessler 
265d6390b08Sphessler /* Keep in sync with ieee80211_ioctl.c:ieee80211_ioctl_setwpaparms() */
266d6390b08Sphessler static int
267d6390b08Sphessler ieee80211_ess_setwpaparms(struct ieee80211_ess *ess,
268d6390b08Sphessler     const struct ieee80211_wpaparams *wpa)
269d6390b08Sphessler {
270d6390b08Sphessler 	if (!wpa->i_enabled) {
271d6390b08Sphessler 		if (!(ess->flags & IEEE80211_F_RSNON))
272d6390b08Sphessler 			return 0;
273d6390b08Sphessler 		ess->flags &= ~IEEE80211_F_RSNON;
274d6390b08Sphessler 		ess->rsnprotos = 0;
275d6390b08Sphessler 		ess->rsnakms = 0;
276d6390b08Sphessler 		ess->rsngroupcipher = 0;
277d6390b08Sphessler 		ess->rsnciphers = 0;
278d6390b08Sphessler 		return ENETRESET;
279d6390b08Sphessler 	}
280d6390b08Sphessler 
281d6390b08Sphessler 	ess->rsnprotos = 0;
282d6390b08Sphessler 	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1)
283d6390b08Sphessler 		ess->rsnprotos |= IEEE80211_PROTO_WPA;
284d6390b08Sphessler 	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
285d6390b08Sphessler 		ess->rsnprotos |= IEEE80211_PROTO_RSN;
286d6390b08Sphessler 	if (ess->rsnprotos == 0)	/* set to default (RSN) */
287d6390b08Sphessler 		ess->rsnprotos = IEEE80211_PROTO_RSN;
288d6390b08Sphessler 
289d6390b08Sphessler 	ess->rsnakms = 0;
290d6390b08Sphessler 	if (wpa->i_akms & IEEE80211_WPA_AKM_PSK)
291d6390b08Sphessler 		ess->rsnakms |= IEEE80211_AKM_PSK;
292d6390b08Sphessler 	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_PSK)
293d6390b08Sphessler 		ess->rsnakms |= IEEE80211_AKM_SHA256_PSK;
294d6390b08Sphessler 	if (wpa->i_akms & IEEE80211_WPA_AKM_8021X)
295d6390b08Sphessler 		ess->rsnakms |= IEEE80211_AKM_8021X;
296d6390b08Sphessler 	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X)
297d6390b08Sphessler 		ess->rsnakms |= IEEE80211_AKM_SHA256_8021X;
298d6390b08Sphessler 	if (ess->rsnakms == 0)	/* set to default (PSK) */
299d6390b08Sphessler 		ess->rsnakms = IEEE80211_AKM_PSK;
300d6390b08Sphessler 
301d6390b08Sphessler 	if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40)
302d6390b08Sphessler 		ess->rsngroupcipher = IEEE80211_CIPHER_WEP40;
303d6390b08Sphessler 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP)
304d6390b08Sphessler 		ess->rsngroupcipher = IEEE80211_CIPHER_TKIP;
305d6390b08Sphessler 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP)
306d6390b08Sphessler 		ess->rsngroupcipher = IEEE80211_CIPHER_CCMP;
307d6390b08Sphessler 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104)
308d6390b08Sphessler 		ess->rsngroupcipher = IEEE80211_CIPHER_WEP104;
309d6390b08Sphessler 	else  {	/* set to default */
310d6390b08Sphessler 		if (ess->rsnprotos & IEEE80211_PROTO_WPA)
311d6390b08Sphessler 			ess->rsngroupcipher = IEEE80211_CIPHER_TKIP;
312d6390b08Sphessler 		else
313d6390b08Sphessler 			ess->rsngroupcipher = IEEE80211_CIPHER_CCMP;
314d6390b08Sphessler 	}
315d6390b08Sphessler 
316d6390b08Sphessler 	ess->rsnciphers = 0;
317d6390b08Sphessler 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP)
318d6390b08Sphessler 		ess->rsnciphers |= IEEE80211_CIPHER_TKIP;
319d6390b08Sphessler 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP)
320d6390b08Sphessler 		ess->rsnciphers |= IEEE80211_CIPHER_CCMP;
321d6390b08Sphessler 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP)
322d6390b08Sphessler 		ess->rsnciphers = IEEE80211_CIPHER_USEGROUP;
323d6390b08Sphessler 	if (ess->rsnciphers == 0) { /* set to default (CCMP, TKIP if WPA1) */
324d6390b08Sphessler 		ess->rsnciphers = IEEE80211_CIPHER_CCMP;
325d6390b08Sphessler 		if (ess->rsnprotos & IEEE80211_PROTO_WPA)
326d6390b08Sphessler 			ess->rsnciphers |= IEEE80211_CIPHER_TKIP;
327d6390b08Sphessler 	}
328d6390b08Sphessler 
329d6390b08Sphessler 	ess->flags |= IEEE80211_F_RSNON;
330d6390b08Sphessler 
331d7eb32e3Sphessler 	if (ess->rsnakms &
332d7eb32e3Sphessler 	    (IEEE80211_AKM_8021X|IEEE80211_WPA_AKM_SHA256_8021X))
333d7eb32e3Sphessler 		ess->flags |= IEEE80211_JOIN_8021X;
334d7eb32e3Sphessler 
335d6390b08Sphessler 	return ENETRESET;
336d6390b08Sphessler }
337d6390b08Sphessler 
3388a36895fSphessler static void
3398a36895fSphessler ieee80211_ess_clear_wep(struct ieee80211_ess *ess)
3408a36895fSphessler {
3418a36895fSphessler 	int i;
3428a36895fSphessler 
3438a36895fSphessler 	/* Disable WEP */
3448a36895fSphessler 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
3458a36895fSphessler 		explicit_bzero(&ess->nw_keys[i], sizeof(ess->nw_keys[0]));
3468a36895fSphessler 	}
3478a36895fSphessler 	ess->def_txkey = 0;
3488a36895fSphessler 	ess->flags &= ~IEEE80211_F_WEPON;
3498a36895fSphessler }
3508a36895fSphessler 
3518a36895fSphessler static void
3528a36895fSphessler ieee80211_ess_clear_wpa(struct ieee80211_ess *ess)
3538a36895fSphessler {
3548a36895fSphessler 	/* Disable WPA */
3558a36895fSphessler 	ess->rsnprotos = ess->rsnakms = ess->rsngroupcipher =
3568a36895fSphessler 	    ess->rsnciphers = 0;
3578a36895fSphessler 	explicit_bzero(ess->psk, sizeof(ess->psk));
3588a36895fSphessler 	ess->flags &= ~(IEEE80211_F_PSK | IEEE80211_F_RSNON);
3598a36895fSphessler }
3608a36895fSphessler 
361020402a2Sphessler int
362d6390b08Sphessler ieee80211_add_ess(struct ieee80211com *ic, struct ieee80211_join *join)
363020402a2Sphessler {
364020402a2Sphessler 	struct ieee80211_ess *ess;
3658a36895fSphessler 	int new = 0, ness = 0;
366020402a2Sphessler 
3678cc58491Sphessler 	/* only valid for station (aka, client) mode */
3688cc58491Sphessler 	if (ic->ic_opmode != IEEE80211_M_STA)
3698cc58491Sphessler 		return (0);
3708cc58491Sphessler 
371020402a2Sphessler 	TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
372d6390b08Sphessler 		if (ess->esslen == join->i_len &&
373d6390b08Sphessler 		    memcmp(ess->essid, join->i_nwid, ess->esslen) == 0)
374020402a2Sphessler 			break;
375020402a2Sphessler 		ness++;
376020402a2Sphessler 	}
377020402a2Sphessler 
378020402a2Sphessler 	if (ess == NULL) {
379020402a2Sphessler 		/* if not found, and wpa/wep are set, then return */
380d6390b08Sphessler 		if ((join->i_flags & IEEE80211_JOIN_WPA) &&
381d6390b08Sphessler 		    (join->i_flags & IEEE80211_JOIN_NWKEY)) {
382d6390b08Sphessler 			return (EINVAL);
383020402a2Sphessler 		}
384020402a2Sphessler 		if (ness > IEEE80211_CACHE_SIZE)
385020402a2Sphessler 			return (ERANGE);
386020402a2Sphessler 		new = 1;
387020402a2Sphessler 		ess = malloc(sizeof(*ess), M_DEVBUF, M_NOWAIT|M_ZERO);
388020402a2Sphessler 		if (ess == NULL)
389020402a2Sphessler 			return (ENOMEM);
390d6390b08Sphessler 		memcpy(ess->essid, join->i_nwid, join->i_len);
391d6390b08Sphessler 		ess->esslen = join->i_len;
39249658e0cSflorian 	}
393020402a2Sphessler 
394d6390b08Sphessler 	if (join->i_flags & IEEE80211_JOIN_WPA) {
395d6390b08Sphessler 		if (join->i_wpaparams.i_enabled) {
396cc834d24Sjsg 			if (!(ic->ic_caps & IEEE80211_C_RSN)) {
397cc834d24Sjsg 				free(ess, M_DEVBUF, sizeof(*ess));
398d6390b08Sphessler 				return ENODEV;
399cc834d24Sjsg 			}
400d6390b08Sphessler 			ieee80211_ess_setwpaparms(ess,
401d6390b08Sphessler 			    &join->i_wpaparams);
402d6390b08Sphessler 			if (join->i_flags & IEEE80211_JOIN_WPAPSK) {
403020402a2Sphessler 				ess->flags |= IEEE80211_F_PSK;
404020402a2Sphessler 				explicit_bzero(ess->psk, sizeof(ess->psk));
405d6390b08Sphessler 				memcpy(ess->psk, &join->i_wpapsk.i_psk,
406d6390b08Sphessler 				    sizeof(ess->psk));
407d6390b08Sphessler 			}
4088a36895fSphessler 			ieee80211_ess_clear_wep(ess);
409020402a2Sphessler 		} else {
4108a36895fSphessler 			ieee80211_ess_clear_wpa(ess);
411020402a2Sphessler 		}
412d6390b08Sphessler 	} else if (join->i_flags & IEEE80211_JOIN_NWKEY) {
413d6390b08Sphessler 		if (join->i_nwkey.i_wepon) {
414cc834d24Sjsg 			if (!(ic->ic_caps & IEEE80211_C_WEP)) {
415cc834d24Sjsg 				free(ess, M_DEVBUF, sizeof(*ess));
416d6390b08Sphessler 				return ENODEV;
417cc834d24Sjsg 			}
418d6390b08Sphessler 			ieee80211_ess_setnwkeys(ess, &join->i_nwkey);
4198a36895fSphessler 			ieee80211_ess_clear_wpa(ess);
420020402a2Sphessler 		} else {
4218a36895fSphessler 			ieee80211_ess_clear_wep(ess);
422020402a2Sphessler 		}
423020402a2Sphessler 	}
424020402a2Sphessler 
425020402a2Sphessler 	if (new)
426020402a2Sphessler 		TAILQ_INSERT_TAIL(&ic->ic_ess, ess, ess_next);
427020402a2Sphessler 
428020402a2Sphessler 	return (0);
429020402a2Sphessler }
430020402a2Sphessler 
4317d35c188Sstsp uint8_t
4327d35c188Sstsp ieee80211_ess_adjust_rssi(struct ieee80211com *ic, struct ieee80211_node *ni)
4337d35c188Sstsp {
4347d35c188Sstsp 	uint8_t rssi = ni->ni_rssi;
4357d35c188Sstsp 
4367d35c188Sstsp 	/*
4377d35c188Sstsp 	 * Slightly punish 2 GHz RSSI values since they are usually
4387d35c188Sstsp 	 * stronger than 5 GHz RSSI values.
4397d35c188Sstsp 	 */
4407d35c188Sstsp 	if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
4417d35c188Sstsp 		if (ic->ic_max_rssi) {
4427d35c188Sstsp 			uint8_t p = (5 * ic->ic_max_rssi) / 100;
4437d35c188Sstsp 	 		if (rssi >= p)
4447d35c188Sstsp 				rssi -= p; /* punish by 5% */
4457d35c188Sstsp 		} else  {
4467d35c188Sstsp 			if (rssi >= 8)
4477d35c188Sstsp 				rssi -= 8; /* punish by 8 dBm */
4487d35c188Sstsp 		}
4497d35c188Sstsp 	}
4507d35c188Sstsp 
4517d35c188Sstsp 	return rssi;
4527d35c188Sstsp }
4537d35c188Sstsp 
454020402a2Sphessler int
455af1eef60Sphessler ieee80211_ess_calculate_score(struct ieee80211com *ic,
456af1eef60Sphessler     struct ieee80211_node *ni)
4577d35c188Sstsp {
458af1eef60Sphessler 	int score = 0;
459af1eef60Sphessler 	uint8_t	min_5ghz_rssi;
4607d35c188Sstsp 
461af1eef60Sphessler 	if (ic->ic_max_rssi)
462af1eef60Sphessler 		min_5ghz_rssi = IEEE80211_RSSI_THRES_RATIO_5GHZ;
463af1eef60Sphessler 	else
464af1eef60Sphessler 		min_5ghz_rssi = (uint8_t)IEEE80211_RSSI_THRES_5GHZ;
4657d35c188Sstsp 
4668a6c2968Sphessler 	/* not using join any */
4678a6c2968Sphessler 	if (ieee80211_get_ess(ic, ni->ni_essid, ni->ni_esslen))
4688a6c2968Sphessler 		score += 32;
4698a6c2968Sphessler 
470af1eef60Sphessler 	/* Calculate the crypto score */
471af1eef60Sphessler 	if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)
472af1eef60Sphessler 		score += 16;
473af1eef60Sphessler 	if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)
474af1eef60Sphessler 		score += 8;
475af1eef60Sphessler 	if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
476af1eef60Sphessler 		score += 4;
477af1eef60Sphessler 
478af1eef60Sphessler 	/* 5GHz with a good signal */
479af1eef60Sphessler 	if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) &&
480af1eef60Sphessler 	    ni->ni_rssi > min_5ghz_rssi)
481af1eef60Sphessler 		score += 2;
482af1eef60Sphessler 
4834c926d56Sstsp 	/* HT/VHT available */
4844c926d56Sstsp 	if (ieee80211_node_supports_ht(ni))
4854c926d56Sstsp 		score++;
4864c926d56Sstsp 	if (ieee80211_node_supports_vht(ni))
4874c926d56Sstsp 		score++;
4884c926d56Sstsp 
4896b9ba65eSstsp 	/* Boost this AP if it had no auth/assoc failures in the past. */
4906b9ba65eSstsp 	if (ni->ni_fails == 0)
4916b9ba65eSstsp 		score += 21;
4926b9ba65eSstsp 
493af1eef60Sphessler 	return score;
4947d35c188Sstsp }
4957d35c188Sstsp 
4967d35c188Sstsp /*
4977d35c188Sstsp  * Given two APs, determine the "better" one of the two.
4987d35c188Sstsp  * We compute a score based on the following attributes:
4997d35c188Sstsp  *
5007d35c188Sstsp  *  crypto: wpa2 > wpa1 > wep > open
5017d35c188Sstsp  *  band: 5 GHz > 2 GHz provided 5 GHz rssi is above threshold
5024c926d56Sstsp  *  supported standard revisions: 11ac > 11n > 11a/b/g
5037d35c188Sstsp  *  rssi: rssi1 > rssi2 as a numeric comparison with a slight
5047d35c188Sstsp  *         disadvantage for 2 GHz APs
5057d35c188Sstsp  *
5067d35c188Sstsp  * Crypto carries most weight, followed by band, followed by rssi.
5077d35c188Sstsp  */
5087d35c188Sstsp int
5097d35c188Sstsp ieee80211_ess_is_better(struct ieee80211com *ic,
5107d35c188Sstsp     struct ieee80211_node *nicur, struct ieee80211_node *nican)
5117d35c188Sstsp {
512af1eef60Sphessler 	struct ifnet		*ifp = &ic->ic_if;
5137d35c188Sstsp 	int			 score_cur = 0, score_can = 0;
514af1eef60Sphessler 	int			 cur_rssi, can_rssi;
5157d35c188Sstsp 
516af1eef60Sphessler 	score_cur = ieee80211_ess_calculate_score(ic, nicur);
517af1eef60Sphessler 	score_can = ieee80211_ess_calculate_score(ic, nican);
5187d35c188Sstsp 
519af1eef60Sphessler 	cur_rssi = ieee80211_ess_adjust_rssi(ic, nicur);
520af1eef60Sphessler 	can_rssi = ieee80211_ess_adjust_rssi(ic, nican);
5217d35c188Sstsp 
522af1eef60Sphessler 	if (can_rssi > cur_rssi)
523af1eef60Sphessler 		score_can++;
524af1eef60Sphessler 
525af1eef60Sphessler 	if ((ifp->if_flags & IFF_DEBUG) && (score_can <= score_cur)) {
526af1eef60Sphessler 		printf("%s: AP %s ", ifp->if_xname,
527af1eef60Sphessler 		    ether_sprintf(nican->ni_bssid));
528af1eef60Sphessler 		ieee80211_print_essid(nican->ni_essid, nican->ni_esslen);
5294c31e3a2Sphessler 		printf(" score %d\n", score_can);
5307d35c188Sstsp 	}
5317d35c188Sstsp 
5327d35c188Sstsp 	return score_can > score_cur;
5337d35c188Sstsp }
5347d35c188Sstsp 
5357d35c188Sstsp /* Determine whether a candidate AP belongs to a given ESS. */
5367d35c188Sstsp int
5377d35c188Sstsp ieee80211_match_ess(struct ieee80211_ess *ess, struct ieee80211_node *ni)
5387d35c188Sstsp {
5398a6c2968Sphessler 	if (ess->esslen != 0 &&
5408a6c2968Sphessler 	    (ess->esslen != ni->ni_esslen ||
541799b58a5Sstsp 	    memcmp(ess->essid, ni->ni_essid, ess->esslen) != 0)) {
542799b58a5Sstsp 		ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_ESSID;
5437d35c188Sstsp 		return 0;
544799b58a5Sstsp 	}
5457d35c188Sstsp 
5467d35c188Sstsp 	if (ess->flags & (IEEE80211_F_PSK | IEEE80211_F_RSNON)) {
5477d35c188Sstsp 		/* Ensure same WPA version. */
5487d35c188Sstsp 		if ((ni->ni_rsnprotos & IEEE80211_PROTO_RSN) &&
549799b58a5Sstsp 		    (ess->rsnprotos & IEEE80211_PROTO_RSN) == 0) {
550799b58a5Sstsp 			ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
5517d35c188Sstsp 			return 0;
552799b58a5Sstsp 		}
5537d35c188Sstsp 		if ((ni->ni_rsnprotos & IEEE80211_PROTO_WPA) &&
554799b58a5Sstsp 		    (ess->rsnprotos & IEEE80211_PROTO_WPA) == 0) {
555799b58a5Sstsp 			ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
5567d35c188Sstsp 			return 0;
557799b58a5Sstsp 		}
5587d35c188Sstsp 	} else if (ess->flags & IEEE80211_F_WEPON) {
559799b58a5Sstsp 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) {
560799b58a5Sstsp 			ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
5617d35c188Sstsp 			return 0;
562799b58a5Sstsp 		}
563490a20a2Sphessler 	} else {
564799b58a5Sstsp 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0) {
565799b58a5Sstsp 			ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
566490a20a2Sphessler 			return 0;
5677d35c188Sstsp 		}
568799b58a5Sstsp 	}
5697d35c188Sstsp 
5708a6c2968Sphessler 	if (ess->esslen == 0 &&
571799b58a5Sstsp 	    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0) {
572799b58a5Sstsp 		ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
5738a6c2968Sphessler 		return 0;
574799b58a5Sstsp 	}
5758a6c2968Sphessler 
5767d35c188Sstsp 	return 1;
5777d35c188Sstsp }
5787d35c188Sstsp 
5797d35c188Sstsp void
5807d35c188Sstsp ieee80211_switch_ess(struct ieee80211com *ic)
581020402a2Sphessler {
582020402a2Sphessler 	struct ifnet		*ifp = &ic->ic_if;
583020402a2Sphessler 	struct ieee80211_ess	*ess, *seless = NULL;
584020402a2Sphessler 	struct ieee80211_node	*ni, *selni = NULL;
585020402a2Sphessler 
586020402a2Sphessler 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
5877d35c188Sstsp 		return;
588020402a2Sphessler 
5897d35c188Sstsp 	/* Find the best AP matching an entry on our ESS join list. */
590020402a2Sphessler 	RBT_FOREACH(ni, ieee80211_tree, &ic->ic_tree) {
591d27bcab3Sphessler 		if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
592d27bcab3Sphessler 		    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
593d27bcab3Sphessler 			continue;
594d27bcab3Sphessler 
5957d35c188Sstsp 		TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
5967d35c188Sstsp 			if (ieee80211_match_ess(ess, ni))
5977d35c188Sstsp 				break;
5987d35c188Sstsp 		}
5997d35c188Sstsp 		if (ess == NULL)
6007d35c188Sstsp 			continue;
6017d35c188Sstsp 
602b2cf04c7Sstsp 		/*
603b2cf04c7Sstsp 		 * Operate only on ic_des_essid if auto-join is disabled.
604b2cf04c7Sstsp 		 * We might have a password stored for this network.
605b2cf04c7Sstsp 		 */
606b2cf04c7Sstsp 		if (!ISSET(ic->ic_flags, IEEE80211_F_AUTO_JOIN)) {
6073db57d68Sphessler 			if (ic->ic_des_esslen == ni->ni_esslen &&
6083db57d68Sphessler 			    memcmp(ic->ic_des_essid, ni->ni_essid,
6093db57d68Sphessler 			    ni->ni_esslen) == 0) {
6103db57d68Sphessler 				ieee80211_set_ess(ic, ess, ni);
611b2cf04c7Sstsp 				return;
612b2cf04c7Sstsp 			}
613b2cf04c7Sstsp 			continue;
614b2cf04c7Sstsp 		}
615b2cf04c7Sstsp 
6167d35c188Sstsp 		if (selni == NULL) {
617020402a2Sphessler 			seless = ess;
618020402a2Sphessler 			selni = ni;
6197d35c188Sstsp 			continue;
620020402a2Sphessler 		}
6217d35c188Sstsp 
6227d35c188Sstsp 		if (ieee80211_ess_is_better(ic, selni, ni)) {
6237d35c188Sstsp 			seless = ess;
6247d35c188Sstsp 			selni = ni;
625020402a2Sphessler 		}
626020402a2Sphessler 	}
627020402a2Sphessler 
6283db57d68Sphessler 	if (selni && seless && !(selni->ni_esslen == ic->ic_des_esslen &&
6293db57d68Sphessler 	    (memcmp(ic->ic_des_essid, selni->ni_essid,
630020402a2Sphessler 	     IEEE80211_NWID_LEN) == 0))) {
6317d35c188Sstsp 		if (ifp->if_flags & IFF_DEBUG) {
632af1eef60Sphessler 			printf("%s: best AP %s ", ifp->if_xname,
633af1eef60Sphessler 			    ether_sprintf(selni->ni_bssid));
634af1eef60Sphessler 			ieee80211_print_essid(selni->ni_essid,
635af1eef60Sphessler 			    selni->ni_esslen);
6364c31e3a2Sphessler 			printf(" score %d\n",
637af1eef60Sphessler 			    ieee80211_ess_calculate_score(ic, selni));
6387d35c188Sstsp 			printf("%s: switching to network ", ifp->if_xname);
6393db57d68Sphessler 			ieee80211_print_essid(selni->ni_essid,
6403db57d68Sphessler 			    selni->ni_esslen);
6418a6c2968Sphessler 			if (seless->esslen == 0)
6428a6c2968Sphessler 				printf(" via join any");
6437d35c188Sstsp 			printf("\n");
6447d35c188Sstsp 
6457d35c188Sstsp 		}
6463db57d68Sphessler 		ieee80211_set_ess(ic, seless, selni);
6477d35c188Sstsp 	}
648020402a2Sphessler }
649020402a2Sphessler 
650020402a2Sphessler void
6513db57d68Sphessler ieee80211_set_ess(struct ieee80211com *ic, struct ieee80211_ess *ess,
6523db57d68Sphessler     struct ieee80211_node *ni)
653020402a2Sphessler {
654020402a2Sphessler 	memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
6553db57d68Sphessler 	ic->ic_des_esslen = ni->ni_esslen;
6563db57d68Sphessler 	memcpy(ic->ic_des_essid, ni->ni_essid, ic->ic_des_esslen);
657020402a2Sphessler 
658020402a2Sphessler 	ieee80211_disable_wep(ic);
659020402a2Sphessler 	ieee80211_disable_rsn(ic);
6603db57d68Sphessler 
661020402a2Sphessler 	if (ess->flags & IEEE80211_F_RSNON) {
662020402a2Sphessler 		explicit_bzero(ic->ic_psk, sizeof(ic->ic_psk));
663020402a2Sphessler 		memcpy(ic->ic_psk, ess->psk, sizeof(ic->ic_psk));
664020402a2Sphessler 
665020402a2Sphessler 		ic->ic_rsnprotos = ess->rsnprotos;
666020402a2Sphessler 		ic->ic_rsnakms = ess->rsnakms;
667020402a2Sphessler 		ic->ic_rsngroupcipher = ess->rsngroupcipher;
668020402a2Sphessler 		ic->ic_rsnciphers = ess->rsnciphers;
669020402a2Sphessler 		ic->ic_flags |= IEEE80211_F_RSNON;
670020402a2Sphessler 		if (ess->flags & IEEE80211_F_PSK)
671020402a2Sphessler 			ic->ic_flags |= IEEE80211_F_PSK;
672020402a2Sphessler 	} else if (ess->flags & IEEE80211_F_WEPON) {
673020402a2Sphessler 		struct ieee80211_key	*k;
674020402a2Sphessler 		int			 i;
675020402a2Sphessler 
676020402a2Sphessler 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
677020402a2Sphessler 			k = &ic->ic_nw_keys[i];
678020402a2Sphessler 			if (k->k_cipher != IEEE80211_CIPHER_NONE)
679020402a2Sphessler 				(*ic->ic_delete_key)(ic, NULL, k);
680020402a2Sphessler 			memcpy(&ic->ic_nw_keys[i], &ess->nw_keys[i],
681020402a2Sphessler 			    sizeof(struct ieee80211_key));
682b7a49a7bSkrw 			if (k->k_cipher != IEEE80211_CIPHER_NONE)
683020402a2Sphessler 				(*ic->ic_set_key)(ic, NULL, k);
684020402a2Sphessler 		}
685020402a2Sphessler 		ic->ic_def_txkey = ess->def_txkey;
686020402a2Sphessler 		ic->ic_flags |= IEEE80211_F_WEPON;
687020402a2Sphessler 	}
688020402a2Sphessler }
689020402a2Sphessler 
69091b2158bSmillert void
6916b9ba65eSstsp ieee80211_deselect_ess(struct ieee80211com *ic)
6926b9ba65eSstsp {
6936b9ba65eSstsp 	memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
6946b9ba65eSstsp 	ic->ic_des_esslen = 0;
6956b9ba65eSstsp 	ieee80211_disable_wep(ic);
6966b9ba65eSstsp 	ieee80211_disable_rsn(ic);
6976b9ba65eSstsp }
6986b9ba65eSstsp 
6996b9ba65eSstsp void
70091b2158bSmillert ieee80211_node_attach(struct ifnet *ifp)
70191b2158bSmillert {
70291b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
703171ac09aSdamien #ifndef IEEE80211_STA_ONLY
7040fd4e251Sreyk 	int size;
705171ac09aSdamien #endif
70691b2158bSmillert 
7078529d8f0Sdlg 	RBT_INIT(ieee80211_tree, &ic->ic_tree);
70891b2158bSmillert 	ic->ic_node_alloc = ieee80211_node_alloc;
70991b2158bSmillert 	ic->ic_node_free = ieee80211_node_free;
71091b2158bSmillert 	ic->ic_node_copy = ieee80211_node_copy;
71191b2158bSmillert 	ic->ic_node_getrssi = ieee80211_node_getrssi;
71206e069b5Sstsp 	ic->ic_node_checkrssi = ieee80211_node_checkrssi;
71391b2158bSmillert 	ic->ic_scangen = 1;
7140fd4e251Sreyk 	ic->ic_max_nnodes = ieee80211_cache_size;
7150fd4e251Sreyk 
7160fd4e251Sreyk 	if (ic->ic_max_aid == 0)
7170fd4e251Sreyk 		ic->ic_max_aid = IEEE80211_AID_DEF;
7180fd4e251Sreyk 	else if (ic->ic_max_aid > IEEE80211_AID_MAX)
7190fd4e251Sreyk 		ic->ic_max_aid = IEEE80211_AID_MAX;
720171ac09aSdamien #ifndef IEEE80211_STA_ONLY
7210fd4e251Sreyk 	size = howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t);
722aec33cadSdamien 	ic->ic_aid_bitmap = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
7230fd4e251Sreyk 	if (ic->ic_aid_bitmap == NULL) {
7240fd4e251Sreyk 		/* XXX no way to recover */
7250fd4e251Sreyk 		printf("%s: no memory for AID bitmap!\n", __func__);
7260fd4e251Sreyk 		ic->ic_max_aid = 0;
727aec33cadSdamien 	}
728ece40bdcSdamien 	if (ic->ic_caps & (IEEE80211_C_HOSTAP | IEEE80211_C_IBSS)) {
729ece40bdcSdamien 		ic->ic_tim_len = howmany(ic->ic_max_aid, 8);
730aec33cadSdamien 		ic->ic_tim_bitmap = malloc(ic->ic_tim_len, M_DEVBUF,
731aec33cadSdamien 		    M_NOWAIT | M_ZERO);
732ece40bdcSdamien 		if (ic->ic_tim_bitmap == NULL) {
733ece40bdcSdamien 			printf("%s: no memory for TIM bitmap!\n", __func__);
734ece40bdcSdamien 			ic->ic_tim_len = 0;
735aec33cadSdamien 		} else
736158c4605Sdamien 			ic->ic_set_tim = ieee80211_set_tim;
737e03e709cSdamien 		timeout_set(&ic->ic_rsn_timeout,
738e03e709cSdamien 		    ieee80211_gtk_rekey_timeout, ic);
7399c2641a5Sstsp 		timeout_set(&ic->ic_inact_timeout,
7409c2641a5Sstsp 		    ieee80211_inact_timeout, ic);
7419c2641a5Sstsp 		timeout_set(&ic->ic_node_cache_timeout,
7429c2641a5Sstsp 		    ieee80211_node_cache_timeout, ic);
743158c4605Sdamien 	}
744171ac09aSdamien #endif
745020402a2Sphessler 	TAILQ_INIT(&ic->ic_ess);
746ece40bdcSdamien }
7470fd4e251Sreyk 
748250085e6Sdamien struct ieee80211_node *
7490fd4e251Sreyk ieee80211_alloc_node_helper(struct ieee80211com *ic)
7500fd4e251Sreyk {
7510fd4e251Sreyk 	struct ieee80211_node *ni;
7520fd4e251Sreyk 	if (ic->ic_nnodes >= ic->ic_max_nnodes)
7539c2641a5Sstsp 		ieee80211_clean_nodes(ic, 0);
7540fd4e251Sreyk 	if (ic->ic_nnodes >= ic->ic_max_nnodes)
7550fd4e251Sreyk 		return NULL;
7560fd4e251Sreyk 	ni = (*ic->ic_node_alloc)(ic);
7570fd4e251Sreyk 	return ni;
75891b2158bSmillert }
75991b2158bSmillert 
76091b2158bSmillert void
76191b2158bSmillert ieee80211_node_lateattach(struct ifnet *ifp)
76291b2158bSmillert {
76391b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
76491b2158bSmillert 	struct ieee80211_node *ni;
76591b2158bSmillert 
7660fd4e251Sreyk 	ni = ieee80211_alloc_node_helper(ic);
767fe6a7506Sjsg 	if (ni == NULL)
768678831beSjsg 		panic("unable to setup initial BSS node");
76991b2158bSmillert 	ni->ni_chan = IEEE80211_CHAN_ANYC;
7700fd4e251Sreyk 	ic->ic_bss = ieee80211_ref_node(ni);
77191b2158bSmillert 	ic->ic_txpower = IEEE80211_TXPOWER_MAX;
772450fcf58Skettenis #ifndef IEEE80211_STA_ONLY
773351e1934Sdlg 	mq_init(&ni->ni_savedq, IEEE80211_PS_MAX_QUEUE, IPL_NET);
774450fcf58Skettenis #endif
77591b2158bSmillert }
77691b2158bSmillert 
77791b2158bSmillert void
77891b2158bSmillert ieee80211_node_detach(struct ifnet *ifp)
77991b2158bSmillert {
78091b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
78191b2158bSmillert 
7820fd4e251Sreyk 	if (ic->ic_bss != NULL) {
78391b2158bSmillert 		(*ic->ic_node_free)(ic, ic->ic_bss);
7840fd4e251Sreyk 		ic->ic_bss = NULL;
7850fd4e251Sreyk 	}
786157eb8fdSphessler 	ieee80211_del_ess(ic, NULL, 0, 1);
787d466420eSstsp 	ieee80211_free_allnodes(ic, 1);
78896c2d967Sdamien #ifndef IEEE80211_STA_ONLY
7894adcc1c9Stb 	free(ic->ic_aid_bitmap, M_DEVBUF,
7904adcc1c9Stb 	    howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t));
7914adcc1c9Stb 	free(ic->ic_tim_bitmap, M_DEVBUF, ic->ic_tim_len);
7929c2641a5Sstsp 	timeout_del(&ic->ic_inact_timeout);
7939c2641a5Sstsp 	timeout_del(&ic->ic_node_cache_timeout);
794dd6ea6d2Sstsp 	timeout_del(&ic->ic_tkip_micfail_timeout);
79596c2d967Sdamien #endif
796187eb87cSmk 	timeout_del(&ic->ic_rsn_timeout);
79791b2158bSmillert }
79891b2158bSmillert 
79991b2158bSmillert /*
80091b2158bSmillert  * AP scanning support.
80191b2158bSmillert  */
80291b2158bSmillert 
80391b2158bSmillert /*
80491b2158bSmillert  * Initialize the active channel set based on the set
80591b2158bSmillert  * of available channels and the current PHY mode.
80691b2158bSmillert  */
807a0f904e4Sreyk void
80891b2158bSmillert ieee80211_reset_scan(struct ifnet *ifp)
80991b2158bSmillert {
81091b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
81191b2158bSmillert 
81291b2158bSmillert 	memcpy(ic->ic_chan_scan, ic->ic_chan_active,
81391b2158bSmillert 		sizeof(ic->ic_chan_active));
81491b2158bSmillert 	/* NB: hack, setup so next_scan starts with the first channel */
815a0f904e4Sreyk 	if (ic->ic_bss != NULL && ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC)
81691b2158bSmillert 		ic->ic_bss->ni_chan = &ic->ic_channels[IEEE80211_CHAN_MAX];
81791b2158bSmillert }
81891b2158bSmillert 
81991b2158bSmillert /*
820799b58a5Sstsp  * Increase a node's inactivity counter.
8216a173c79Sstsp  * This counter get reset to zero if a frame is received.
8226a173c79Sstsp  * This function is intended for station mode only.
8236a173c79Sstsp  * See ieee80211_node_cache_timeout() for hostap mode.
8246a173c79Sstsp  */
8256a173c79Sstsp void
8266a173c79Sstsp ieee80211_node_raise_inact(void *arg, struct ieee80211_node *ni)
8276a173c79Sstsp {
8286a173c79Sstsp 	if (ni->ni_refcnt == 0 && ni->ni_inact < IEEE80211_INACT_SCAN)
8296a173c79Sstsp 		ni->ni_inact++;
8306a173c79Sstsp }
8316a173c79Sstsp 
8326a173c79Sstsp /*
83391b2158bSmillert  * Begin an active scan.
83491b2158bSmillert  */
83591b2158bSmillert void
83691b2158bSmillert ieee80211_begin_scan(struct ifnet *ifp)
83791b2158bSmillert {
83891b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
83991b2158bSmillert 
84091b2158bSmillert 	/*
84191b2158bSmillert 	 * In all but hostap mode scanning starts off in
84291b2158bSmillert 	 * an active mode before switching to passive.
84391b2158bSmillert 	 */
844171ac09aSdamien #ifndef IEEE80211_STA_ONLY
845171ac09aSdamien 	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
846171ac09aSdamien #endif
847171ac09aSdamien 	{
84891b2158bSmillert 		ic->ic_flags |= IEEE80211_F_ASCAN;
84991b2158bSmillert 		ic->ic_stats.is_scan_active++;
850171ac09aSdamien 	}
851171ac09aSdamien #ifndef IEEE80211_STA_ONLY
852171ac09aSdamien 	else
85391b2158bSmillert 		ic->ic_stats.is_scan_passive++;
854171ac09aSdamien #endif
85591b2158bSmillert 	if (ifp->if_flags & IFF_DEBUG)
856a0068c42Sjsg 		printf("%s: begin %s scan\n", ifp->if_xname,
85791b2158bSmillert 			(ic->ic_flags & IEEE80211_F_ASCAN) ?
85891b2158bSmillert 				"active" : "passive");
859a0f904e4Sreyk 
8606a173c79Sstsp 
8616a173c79Sstsp 	if (ic->ic_opmode == IEEE80211_M_STA) {
8626a173c79Sstsp 		ieee80211_node_cleanup(ic, ic->ic_bss);
8636a173c79Sstsp 		ieee80211_iterate_nodes(ic, ieee80211_node_raise_inact, NULL);
8646a173c79Sstsp 	}
86591b2158bSmillert 
866a0f904e4Sreyk 	/*
867a0f904e4Sreyk 	 * Reset the current mode. Setting the current mode will also
868a0f904e4Sreyk 	 * reset scan state.
869a0f904e4Sreyk 	 */
870f4348f20Sstsp 	if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO)
871d424122bSreyk 		ic->ic_curmode = IEEE80211_MODE_AUTO;
872d424122bSreyk 	ieee80211_setmode(ic, ic->ic_curmode);
873d424122bSreyk 
87414207dadSreyk 	ic->ic_scan_count = 0;
87514207dadSreyk 
87691b2158bSmillert 	/* Scan the next channel. */
87791b2158bSmillert 	ieee80211_next_scan(ifp);
87891b2158bSmillert }
87991b2158bSmillert 
88091b2158bSmillert /*
88191b2158bSmillert  * Switch to the next channel marked for scanning.
88291b2158bSmillert  */
88391b2158bSmillert void
88491b2158bSmillert ieee80211_next_scan(struct ifnet *ifp)
88591b2158bSmillert {
88691b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
88791b2158bSmillert 	struct ieee80211_channel *chan;
88891b2158bSmillert 
88991b2158bSmillert 	chan = ic->ic_bss->ni_chan;
89091b2158bSmillert 	for (;;) {
89191b2158bSmillert 		if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX])
89291b2158bSmillert 			chan = &ic->ic_channels[0];
89391b2158bSmillert 		if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) {
89491b2158bSmillert 			/*
895efb3b202Sdamien 			 * Ignore channels marked passive-only
89691b2158bSmillert 			 * during an active scan.
89791b2158bSmillert 			 */
89891b2158bSmillert 			if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 ||
89991b2158bSmillert 			    (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
90091b2158bSmillert 				break;
90191b2158bSmillert 		}
90291b2158bSmillert 		if (chan == ic->ic_bss->ni_chan) {
90391b2158bSmillert 			ieee80211_end_scan(ifp);
90491b2158bSmillert 			return;
90591b2158bSmillert 		}
90691b2158bSmillert 	}
90791b2158bSmillert 	clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
908932b9027Sdamien 	DPRINTF(("chan %d->%d\n",
90991b2158bSmillert 	    ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
91091b2158bSmillert 	    ieee80211_chan2ieee(ic, chan)));
91191b2158bSmillert 	ic->ic_bss->ni_chan = chan;
91291b2158bSmillert 	ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
91391b2158bSmillert }
91491b2158bSmillert 
915171ac09aSdamien #ifndef IEEE80211_STA_ONLY
91691b2158bSmillert void
91791b2158bSmillert ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
91891b2158bSmillert {
91969746424Sstsp 	enum ieee80211_phymode mode;
92091b2158bSmillert 	struct ieee80211_node *ni;
92191b2158bSmillert 	struct ifnet *ifp = &ic->ic_if;
92291b2158bSmillert 
92391b2158bSmillert 	ni = ic->ic_bss;
92491b2158bSmillert 	if (ifp->if_flags & IFF_DEBUG)
925a0068c42Sjsg 		printf("%s: creating ibss\n", ifp->if_xname);
92691b2158bSmillert 	ic->ic_flags |= IEEE80211_F_SIBSS;
92791b2158bSmillert 	ni->ni_chan = chan;
92869746424Sstsp 	if ((ic->ic_flags & IEEE80211_F_VHTON) && IEEE80211_IS_CHAN_5GHZ(chan))
92969746424Sstsp 		mode = IEEE80211_MODE_11AC;
93069746424Sstsp 	else if (ic->ic_flags & IEEE80211_F_HTON)
93169746424Sstsp 		mode = IEEE80211_MODE_11N;
93269746424Sstsp 	else
93369746424Sstsp 		mode = ieee80211_chan2mode(ic, ni->ni_chan);
93469746424Sstsp 	ieee80211_setmode(ic, mode);
93569746424Sstsp 	/* Pick an appropriate mode for supported legacy rates. */
93669746424Sstsp 	if (ic->ic_curmode == IEEE80211_MODE_11AC) {
93769746424Sstsp 		mode = IEEE80211_MODE_11A;
93869746424Sstsp 	} else if (ic->ic_curmode == IEEE80211_MODE_11N) {
93969746424Sstsp 		if (IEEE80211_IS_CHAN_5GHZ(chan))
94069746424Sstsp 			mode = IEEE80211_MODE_11A;
94169746424Sstsp 		else
94269746424Sstsp 			mode = IEEE80211_MODE_11G;
94369746424Sstsp 	} else {
94469746424Sstsp 		mode = ic->ic_curmode;
94569746424Sstsp 	}
94669746424Sstsp 	ni->ni_rates = ic->ic_sup_rates[mode];
947d8fc5796Sstsp 	ni->ni_txrate = 0;
94891b2158bSmillert 	IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
94991b2158bSmillert 	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
9500fd4e251Sreyk 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
9510fd4e251Sreyk 		if ((ic->ic_flags & IEEE80211_F_DESBSSID) != 0)
9520fd4e251Sreyk 			IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
9530fd4e251Sreyk 		else
95491b2158bSmillert 			ni->ni_bssid[0] |= 0x02;	/* local bit for IBSS */
9550fd4e251Sreyk 	}
95691b2158bSmillert 	ni->ni_esslen = ic->ic_des_esslen;
95791b2158bSmillert 	memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
95891b2158bSmillert 	ni->ni_rssi = 0;
95991b2158bSmillert 	ni->ni_rstamp = 0;
96091b2158bSmillert 	memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
96191b2158bSmillert 	ni->ni_intval = ic->ic_lintval;
96291b2158bSmillert 	ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
96391b2158bSmillert 	if (ic->ic_flags & IEEE80211_F_WEPON)
96491b2158bSmillert 		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
965a2ee12ecSstsp 	if (ic->ic_flags & IEEE80211_F_HTON) {
966e8f8f56cSstsp 		const struct ieee80211_edca_ac_params *ac_qap;
967e8f8f56cSstsp 		struct ieee80211_edca_ac_params *ac;
968e8f8f56cSstsp 		int aci;
969e8f8f56cSstsp 
970a2ee12ecSstsp 		/*
9711c062f30Sstsp 		 * Configure HT protection. This will be updated later
9721c062f30Sstsp 		 * based on the number of non-HT nodes in the node cache.
973a2ee12ecSstsp 		 */
9741c062f30Sstsp 		ic->ic_protmode = IEEE80211_PROT_NONE;
9751c062f30Sstsp 		ni->ni_htop1 = IEEE80211_HTPROT_NONE;
9761c062f30Sstsp 		/* Disallow Greenfield mode. None of our drivers support it. */
9771c062f30Sstsp 		ni->ni_htop1 |= IEEE80211_HTOP1_NONGF_STA;
97809268e1fSstsp 		if (ic->ic_updateprot)
97909268e1fSstsp 			ic->ic_updateprot(ic);
980e8f8f56cSstsp 
981e8f8f56cSstsp 		/* Configure QoS EDCA parameters. */
982e8f8f56cSstsp 		for (aci = 0; aci < EDCA_NUM_AC; aci++) {
983e8f8f56cSstsp 			ac = &ic->ic_edca_ac[aci];
984e8f8f56cSstsp 			ac_qap = &ieee80211_qap_edca_table[ic->ic_curmode][aci];
985e8f8f56cSstsp 			ac->ac_acm       = ac_qap->ac_acm;
986e8f8f56cSstsp 			ac->ac_aifsn     = ac_qap->ac_aifsn;
987e8f8f56cSstsp 			ac->ac_ecwmin    = ac_qap->ac_ecwmin;
988e8f8f56cSstsp 			ac->ac_ecwmax    = ac_qap->ac_ecwmax;
989e8f8f56cSstsp 			ac->ac_txoplimit = ac_qap->ac_txoplimit;
990e8f8f56cSstsp 		}
991e8f8f56cSstsp 		if (ic->ic_updateedca)
992e8f8f56cSstsp 			(*ic->ic_updateedca)(ic);
993a2ee12ecSstsp 	}
994e03e709cSdamien 	if (ic->ic_flags & IEEE80211_F_RSNON) {
995e03e709cSdamien 		struct ieee80211_key *k;
996e03e709cSdamien 
997e03e709cSdamien 		/* initialize 256-bit global key counter to a random value */
998780f39a5Sdjm 		arc4random_buf(ic->ic_globalcnt, EAPOL_KEY_NONCE_LEN);
999e03e709cSdamien 
1000e03e709cSdamien 		ni->ni_rsnprotos = ic->ic_rsnprotos;
1001e03e709cSdamien 		ni->ni_rsnakms = ic->ic_rsnakms;
1002e03e709cSdamien 		ni->ni_rsnciphers = ic->ic_rsnciphers;
1003e03e709cSdamien 		ni->ni_rsngroupcipher = ic->ic_rsngroupcipher;
1004e1f2336eSdamien 		ni->ni_rsngroupmgmtcipher = ic->ic_rsngroupmgmtcipher;
1005e03e709cSdamien 		ni->ni_rsncaps = 0;
1006db011a80Sdamien 		if (ic->ic_caps & IEEE80211_C_MFP) {
1007db011a80Sdamien 			ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPC;
1008db011a80Sdamien 			if (ic->ic_flags & IEEE80211_F_MFPR)
1009db011a80Sdamien 				ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPR;
1010db011a80Sdamien 		}
1011e03e709cSdamien 
1012e03e709cSdamien 		ic->ic_def_txkey = 1;
1013dd6ea6d2Sstsp 		ic->ic_flags &= ~IEEE80211_F_COUNTERM;
1014e03e709cSdamien 		k = &ic->ic_nw_keys[ic->ic_def_txkey];
1015625598c1Sdamien 		memset(k, 0, sizeof(*k));
1016625598c1Sdamien 		k->k_id = ic->ic_def_txkey;
1017625598c1Sdamien 		k->k_cipher = ni->ni_rsngroupcipher;
1018625598c1Sdamien 		k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
1019625598c1Sdamien 		k->k_len = ieee80211_cipher_keylen(k->k_cipher);
1020625598c1Sdamien 		arc4random_buf(k->k_key, k->k_len);
1021e03e709cSdamien 		(*ic->ic_set_key)(ic, ni, k);	/* XXX */
1022e03e709cSdamien 
1023302e5949Sdamien 		if (ic->ic_caps & IEEE80211_C_MFP) {
1024302e5949Sdamien 			ic->ic_igtk_kid = 4;
1025302e5949Sdamien 			k = &ic->ic_nw_keys[ic->ic_igtk_kid];
1026302e5949Sdamien 			memset(k, 0, sizeof(*k));
1027302e5949Sdamien 			k->k_id = ic->ic_igtk_kid;
1028302e5949Sdamien 			k->k_cipher = ni->ni_rsngroupmgmtcipher;
1029302e5949Sdamien 			k->k_flags = IEEE80211_KEY_IGTK | IEEE80211_KEY_TX;
1030302e5949Sdamien 			k->k_len = 16;
1031302e5949Sdamien 			arc4random_buf(k->k_key, k->k_len);
1032302e5949Sdamien 			(*ic->ic_set_key)(ic, ni, k);	/* XXX */
1033302e5949Sdamien 		}
1034e03e709cSdamien 		/*
1035e03e709cSdamien 		 * In HostAP mode, multicast traffic is sent using ic_bss
1036e03e709cSdamien 		 * as the Tx node, so mark our node as valid so we can send
1037e03e709cSdamien 		 * multicast frames using the group key we've just configured.
1038e03e709cSdamien 		 */
1039e03e709cSdamien 		ni->ni_port_valid = 1;
104001ad6d9fSdamien 		ni->ni_flags |= IEEE80211_NODE_TXPROT;
1041e03e709cSdamien 
1042db011a80Sdamien 		/* schedule a GTK/IGTK rekeying after 3600s */
104329e86e5eSblambert 		timeout_add_sec(&ic->ic_rsn_timeout, 3600);
1044e03e709cSdamien 	}
10459c2641a5Sstsp 	timeout_add_sec(&ic->ic_inact_timeout, IEEE80211_INACT_WAIT);
10469c2641a5Sstsp 	timeout_add_sec(&ic->ic_node_cache_timeout, IEEE80211_CACHE_WAIT);
104791b2158bSmillert 	ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
104891b2158bSmillert }
1049171ac09aSdamien #endif	/* IEEE80211_STA_ONLY */
105091b2158bSmillert 
105191b2158bSmillert int
1052799b58a5Sstsp ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni,
1053799b58a5Sstsp     int bgscan)
105491b2158bSmillert {
105591b2158bSmillert 	u_int8_t rate;
105691b2158bSmillert 	int fail;
105791b2158bSmillert 
105891b2158bSmillert 	fail = 0;
1059ef1d73a0Sstsp 	if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0 &&
1060ef1d73a0Sstsp 	    isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
1061799b58a5Sstsp 		fail |= IEEE80211_NODE_ASSOCFAIL_CHAN;
106291b2158bSmillert 	if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
106391b2158bSmillert 	    ni->ni_chan != ic->ic_des_chan)
1064799b58a5Sstsp 		fail |= IEEE80211_NODE_ASSOCFAIL_CHAN;
1065171ac09aSdamien #ifndef IEEE80211_STA_ONLY
106691b2158bSmillert 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
106791b2158bSmillert 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
1068799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_IBSS;
1069171ac09aSdamien 	} else
1070171ac09aSdamien #endif
1071171ac09aSdamien 	{
107291b2158bSmillert 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
1073799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_IBSS;
107491b2158bSmillert 	}
1075e03e709cSdamien 	if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) {
107691b2158bSmillert 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
1077799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
107891b2158bSmillert 	} else {
107991b2158bSmillert 		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
1080799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
108191b2158bSmillert 	}
1082e03e709cSdamien 
108391b2158bSmillert 	rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
108491b2158bSmillert 	if (rate & IEEE80211_RATE_BASIC)
1085799b58a5Sstsp 		fail |= IEEE80211_NODE_ASSOCFAIL_BASIC_RATE;
1086dc90783bSstsp 	if (ic->ic_des_esslen == 0)
1087799b58a5Sstsp 		fail |= IEEE80211_NODE_ASSOCFAIL_ESSID;
108891b2158bSmillert 	if (ic->ic_des_esslen != 0 &&
108991b2158bSmillert 	    (ni->ni_esslen != ic->ic_des_esslen ||
109091b2158bSmillert 	     memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0))
1091799b58a5Sstsp 		fail |= IEEE80211_NODE_ASSOCFAIL_ESSID;
109291b2158bSmillert 	if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
109391b2158bSmillert 	    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
1094799b58a5Sstsp 		fail |= IEEE80211_NODE_ASSOCFAIL_BSSID;
1095e03e709cSdamien 
1096e03e709cSdamien 	if (ic->ic_flags & IEEE80211_F_RSNON) {
1097e03e709cSdamien 		/*
1098e03e709cSdamien 		 * If at least one RSN IE field from the AP's RSN IE fails
1099e03e709cSdamien 		 * to overlap with any value the STA supports, the STA shall
1100e03e709cSdamien 		 * decline to associate with that AP.
1101e03e709cSdamien 		 */
1102e03e709cSdamien 		if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0)
1103799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1104e03e709cSdamien 		if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0)
1105799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1106f91ff320Sdamien 		if ((ni->ni_rsnakms & ic->ic_rsnakms &
1107f91ff320Sdamien 		     ~(IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK)) == 0) {
1108f91ff320Sdamien 			/* AP only supports PSK AKMPs */
1109f91ff320Sdamien 			if (!(ic->ic_flags & IEEE80211_F_PSK))
1110799b58a5Sstsp 				fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1111f91ff320Sdamien 		}
11125f0cba21Sdamien 		if (ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP40 &&
11135f0cba21Sdamien 		    ni->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP &&
11145f0cba21Sdamien 		    ni->ni_rsngroupcipher != IEEE80211_CIPHER_CCMP &&
11155f0cba21Sdamien 		    ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP104)
1116799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1117e03e709cSdamien 		if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0)
1118799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1119db011a80Sdamien 
112045eec175Sdamien 		/* we only support BIP as the IGTK cipher */
1121db011a80Sdamien 		if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) &&
112245eec175Sdamien 		    ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_BIP)
1123799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1124db011a80Sdamien 
1125db011a80Sdamien 		/* we do not support MFP but AP requires it */
1126db011a80Sdamien 		if (!(ic->ic_caps & IEEE80211_C_MFP) &&
1127db011a80Sdamien 		    (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR))
1128799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1129db011a80Sdamien 
1130db011a80Sdamien 		/* we require MFP but AP does not support it */
1131db011a80Sdamien 		if ((ic->ic_caps & IEEE80211_C_MFP) &&
1132db011a80Sdamien 		    (ic->ic_flags & IEEE80211_F_MFPR) &&
1133db011a80Sdamien 		    !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC))
1134799b58a5Sstsp 			fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
1135e03e709cSdamien 	}
1136e03e709cSdamien 
113791b2158bSmillert 	if (ic->ic_if.if_flags & IFF_DEBUG) {
11385d3f9684Sstsp 		printf("%s: %c %s%c", ic->ic_if.if_xname, fail ? '-' : '+',
11394965e88fSstsp 		    ether_sprintf(ni->ni_bssid),
1140799b58a5Sstsp 		    fail & IEEE80211_NODE_ASSOCFAIL_BSSID ? '!' : ' ');
114191b2158bSmillert 		printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
1142799b58a5Sstsp 			fail & IEEE80211_NODE_ASSOCFAIL_CHAN ? '!' : ' ');
114391b2158bSmillert 		printf(" %+4d", ni->ni_rssi);
114491b2158bSmillert 		printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
1145799b58a5Sstsp 		    fail & IEEE80211_NODE_ASSOCFAIL_BASIC_RATE ? '!' : ' ');
114691b2158bSmillert 		printf(" %4s%c",
114791b2158bSmillert 		    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
114891b2158bSmillert 		    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
114991b2158bSmillert 		    "????",
1150799b58a5Sstsp 		    fail & IEEE80211_NODE_ASSOCFAIL_IBSS ? '!' : ' ');
1151e03e709cSdamien 		printf(" %7s%c ",
115291b2158bSmillert 		    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
1153e03e709cSdamien 		    "privacy" : "no",
1154799b58a5Sstsp 		    fail & IEEE80211_NODE_ASSOCFAIL_PRIVACY ? '!' : ' ');
1155e03e709cSdamien 		printf(" %3s%c ",
1156e03e709cSdamien 		    (ic->ic_flags & IEEE80211_F_RSNON) ?
1157e03e709cSdamien 		    "rsn" : "no",
1158799b58a5Sstsp 		    fail & IEEE80211_NODE_ASSOCFAIL_WPA_PROTO ? '!' : ' ');
115991b2158bSmillert 		ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
1160799b58a5Sstsp 		printf("%s\n",
1161799b58a5Sstsp 		    fail & IEEE80211_NODE_ASSOCFAIL_ESSID ? "!" : "");
116291b2158bSmillert 	}
11634965e88fSstsp 
1164799b58a5Sstsp 	/* We don't care about unrelated networks during background scans. */
1165799b58a5Sstsp 	if (bgscan) {
1166799b58a5Sstsp 		if ((fail & IEEE80211_NODE_ASSOCFAIL_ESSID) == 0)
1167799b58a5Sstsp 			ni->ni_assoc_fail = fail;
1168799b58a5Sstsp 	} else
1169799b58a5Sstsp 		ni->ni_assoc_fail = fail;
1170799b58a5Sstsp 	if ((fail & IEEE80211_NODE_ASSOCFAIL_ESSID) == 0)
1171799b58a5Sstsp 		ic->ic_bss->ni_assoc_fail = ni->ni_assoc_fail;
1172799b58a5Sstsp 
117391b2158bSmillert 	return fail;
117491b2158bSmillert }
117591b2158bSmillert 
117606e069b5Sstsp struct ieee80211_node_switch_bss_arg {
117706e069b5Sstsp 	u_int8_t cur_macaddr[IEEE80211_ADDR_LEN];
117806e069b5Sstsp 	u_int8_t sel_macaddr[IEEE80211_ADDR_LEN];
117906e069b5Sstsp };
118006e069b5Sstsp 
1181de9c1173Sstsp void
1182de9c1173Sstsp ieee80211_node_free_unref_cb(struct ieee80211_node *ni)
1183de9c1173Sstsp {
1184de9c1173Sstsp 	free(ni->ni_unref_arg, M_DEVBUF, ni->ni_unref_arg_size);
1185de9c1173Sstsp 
1186de9c1173Sstsp 	/* Guard against accidental reuse. */
1187de9c1173Sstsp 	ni->ni_unref_cb = NULL;
1188de9c1173Sstsp 	ni->ni_unref_arg = NULL;
1189de9c1173Sstsp 	ni->ni_unref_arg_size = 0;
1190de9c1173Sstsp }
1191de9c1173Sstsp 
1192de9c1173Sstsp /* Implements ni->ni_unref_cb(). */
1193de9c1173Sstsp void
1194de9c1173Sstsp ieee80211_node_tx_stopped(struct ieee80211com *ic,
1195de9c1173Sstsp     struct ieee80211_node *ni)
1196de9c1173Sstsp {
1197de9c1173Sstsp 	splassert(IPL_NET);
1198de9c1173Sstsp 
1199de9c1173Sstsp 	if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0)
1200de9c1173Sstsp 		return;
1201de9c1173Sstsp 
1202de9c1173Sstsp 	/*
1203de9c1173Sstsp 	 * Install a callback which will switch us to the new AP once
1204de9c1173Sstsp 	 * the de-auth frame has been processed by hardware.
1205de9c1173Sstsp 	 * Pass on the existing ni->ni_unref_arg argument.
1206de9c1173Sstsp 	 */
1207de9c1173Sstsp 	ic->ic_bss->ni_unref_cb = ieee80211_node_switch_bss;
1208de9c1173Sstsp 
1209de9c1173Sstsp 	/*
1210de9c1173Sstsp 	 * All data frames queued to hardware have been flushed and
1211de9c1173Sstsp 	 * A-MPDU Tx has been stopped. We are now going to switch APs.
1212de9c1173Sstsp 	 * Queue a de-auth frame addressed at our current AP.
1213de9c1173Sstsp 	 */
1214de9c1173Sstsp 	if (IEEE80211_SEND_MGMT(ic, ic->ic_bss,
1215de9c1173Sstsp 	    IEEE80211_FC0_SUBTYPE_DEAUTH,
1216de9c1173Sstsp 	    IEEE80211_REASON_AUTH_LEAVE) != 0) {
1217de9c1173Sstsp 		ic->ic_flags &= ~IEEE80211_F_BGSCAN;
1218de9c1173Sstsp 		ieee80211_node_free_unref_cb(ni);
1219de9c1173Sstsp 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1220de9c1173Sstsp 		return;
1221de9c1173Sstsp 	}
1222de9c1173Sstsp 
1223de9c1173Sstsp 	/* F_BGSCAN flag gets cleared in ieee80211_node_join_bss(). */
1224de9c1173Sstsp }
1225de9c1173Sstsp 
1226de9c1173Sstsp /* Implements ni->ni_unref_cb(). */
1227de9c1173Sstsp void
1228de9c1173Sstsp ieee80211_node_tx_flushed(struct ieee80211com *ic, struct ieee80211_node *ni)
1229de9c1173Sstsp {
1230de9c1173Sstsp 	splassert(IPL_NET);
1231de9c1173Sstsp 
1232de9c1173Sstsp 	if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0)
1233de9c1173Sstsp 		return;
1234de9c1173Sstsp 
1235de9c1173Sstsp 	/* All data frames queued to hardware have been flushed. */
1236de9c1173Sstsp 	if (ic->ic_caps & IEEE80211_C_TX_AMPDU) {
1237de9c1173Sstsp 		/*
1238de9c1173Sstsp 		 * Install a callback which will switch us to the
1239de9c1173Sstsp 		 * new AP once Tx agg sessions have been stopped,
1240de9c1173Sstsp 		 * which involves sending a DELBA frame.
1241de9c1173Sstsp 		 * Pass on the existing ni->ni_unref_arg argument.
1242de9c1173Sstsp 		 */
1243de9c1173Sstsp 		ic->ic_bss->ni_unref_cb = ieee80211_node_tx_stopped;
1244de9c1173Sstsp 		ieee80211_stop_ampdu_tx(ic, ic->ic_bss,
1245de9c1173Sstsp 		    IEEE80211_FC0_SUBTYPE_DEAUTH);
1246de9c1173Sstsp 	} else
1247de9c1173Sstsp 		ieee80211_node_tx_stopped(ic, ni);
1248de9c1173Sstsp }
1249de9c1173Sstsp 
125006e069b5Sstsp /* Implements ni->ni_unref_cb(). */
125106e069b5Sstsp void
125206e069b5Sstsp ieee80211_node_switch_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
125306e069b5Sstsp {
125406e069b5Sstsp 	struct ifnet *ifp = &ic->ic_if;
125506e069b5Sstsp 	struct ieee80211_node_switch_bss_arg *sba = ni->ni_unref_arg;
125606e069b5Sstsp 	struct ieee80211_node *curbs, *selbs;
125706e069b5Sstsp 
125806e069b5Sstsp 	splassert(IPL_NET);
125906e069b5Sstsp 
1260de9c1173Sstsp 	if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0)
126106e069b5Sstsp 		return;
126206e069b5Sstsp 
126306e069b5Sstsp 	ic->ic_xflags &= ~IEEE80211_F_TX_MGMT_ONLY;
126406e069b5Sstsp 
126506e069b5Sstsp 	selbs = ieee80211_find_node(ic, sba->sel_macaddr);
126606e069b5Sstsp 	if (selbs == NULL) {
1267de9c1173Sstsp 		ieee80211_node_free_unref_cb(ni);
126806e069b5Sstsp 		ic->ic_flags &= ~IEEE80211_F_BGSCAN;
126906e069b5Sstsp 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
127006e069b5Sstsp 		return;
127106e069b5Sstsp 	}
127206e069b5Sstsp 
127306e069b5Sstsp 	curbs = ieee80211_find_node(ic, sba->cur_macaddr);
127406e069b5Sstsp 	if (curbs == NULL) {
1275de9c1173Sstsp 		ieee80211_node_free_unref_cb(ni);
127606e069b5Sstsp 		ic->ic_flags &= ~IEEE80211_F_BGSCAN;
127706e069b5Sstsp 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
127806e069b5Sstsp 		return;
127906e069b5Sstsp 	}
128006e069b5Sstsp 
128106e069b5Sstsp 	if (ifp->if_flags & IFF_DEBUG) {
128206e069b5Sstsp 		printf("%s: roaming from %s chan %d ",
128306e069b5Sstsp 		    ifp->if_xname, ether_sprintf(curbs->ni_macaddr),
128406e069b5Sstsp 		    ieee80211_chan2ieee(ic, curbs->ni_chan));
128506e069b5Sstsp 		printf("to %s chan %d\n", ether_sprintf(selbs->ni_macaddr),
128606e069b5Sstsp 		    ieee80211_chan2ieee(ic, selbs->ni_chan));
128706e069b5Sstsp 	}
128806e069b5Sstsp 	ieee80211_node_newstate(curbs, IEEE80211_STA_CACHE);
1289de9c1173Sstsp 	/*
1290de9c1173Sstsp 	 * ieee80211_node_join_bss() frees arg and ic->ic_bss via
1291de9c1173Sstsp 	 * ic->ic_node_copy() in ieee80211_node_cleanup().
1292de9c1173Sstsp 	 */
1293de9c1173Sstsp 	ieee80211_node_join_bss(ic, selbs);
129406e069b5Sstsp }
129506e069b5Sstsp 
129606e069b5Sstsp void
129706e069b5Sstsp ieee80211_node_join_bss(struct ieee80211com *ic, struct ieee80211_node *selbs)
129806e069b5Sstsp {
129906e069b5Sstsp 	enum ieee80211_phymode mode;
130006e069b5Sstsp 	struct ieee80211_node *ni;
1301799b58a5Sstsp 	uint32_t assoc_fail = 0;
130206e069b5Sstsp 
130306e069b5Sstsp 	/* Reinitialize media mode and channels if needed. */
130406e069b5Sstsp 	mode = ieee80211_chan2mode(ic, selbs->ni_chan);
130506e069b5Sstsp 	if (mode != ic->ic_curmode)
130606e069b5Sstsp 		ieee80211_setmode(ic, mode);
130706e069b5Sstsp 
1308799b58a5Sstsp 	/* Keep recorded association failures for this BSS/ESS intact. */
1309799b58a5Sstsp 	if (IEEE80211_ADDR_EQ(ic->ic_bss->ni_macaddr, selbs->ni_macaddr) ||
1310799b58a5Sstsp 	    (ic->ic_des_esslen > 0 && ic->ic_des_esslen == selbs->ni_esslen &&
1311799b58a5Sstsp 	    memcmp(ic->ic_des_essid, selbs->ni_essid, selbs->ni_esslen) == 0))
1312799b58a5Sstsp 		assoc_fail = ic->ic_bss->ni_assoc_fail;
1313799b58a5Sstsp 
131406e069b5Sstsp 	(*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
131506e069b5Sstsp 	ni = ic->ic_bss;
1316799b58a5Sstsp 	ni->ni_assoc_fail |= assoc_fail;
1317799b58a5Sstsp 
1318799b58a5Sstsp 	ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan);
131906e069b5Sstsp 
132006e069b5Sstsp 	/* Make sure we send valid rates in an association request. */
132106e069b5Sstsp 	if (ic->ic_opmode == IEEE80211_M_STA)
132206e069b5Sstsp 		ieee80211_fix_rate(ic, ni,
132306e069b5Sstsp 		    IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
132406e069b5Sstsp 		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
132506e069b5Sstsp 
132606e069b5Sstsp 	if (ic->ic_flags & IEEE80211_F_RSNON)
132706e069b5Sstsp 		ieee80211_choose_rsnparams(ic);
132806e069b5Sstsp 	else if (ic->ic_flags & IEEE80211_F_WEPON)
132906e069b5Sstsp 		ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP;
133006e069b5Sstsp 
133106e069b5Sstsp 	ieee80211_node_newstate(selbs, IEEE80211_STA_BSS);
133206e069b5Sstsp #ifndef IEEE80211_STA_ONLY
133306e069b5Sstsp 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
133406e069b5Sstsp 		ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE |
133506e069b5Sstsp 		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
133606e069b5Sstsp 		if (ni->ni_rates.rs_nrates == 0) {
133706e069b5Sstsp 			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
133806e069b5Sstsp 			return;
133906e069b5Sstsp 		}
134006e069b5Sstsp 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
134106e069b5Sstsp 	} else
134206e069b5Sstsp #endif
134306e069b5Sstsp 	{
134406e069b5Sstsp 		int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) &&
134506e069b5Sstsp 		    ic->ic_opmode == IEEE80211_M_STA &&
134606e069b5Sstsp 		    ic->ic_state == IEEE80211_S_RUN);
134740dc231eSstsp 		int auth_next = (ic->ic_opmode == IEEE80211_M_STA &&
134840dc231eSstsp 		    ic->ic_state == IEEE80211_S_AUTH);
134940dc231eSstsp 		int mgt = -1;
135006e069b5Sstsp 
135106e069b5Sstsp 		timeout_del(&ic->ic_bgscan_timeout);
135206e069b5Sstsp 		ic->ic_flags &= ~IEEE80211_F_BGSCAN;
135306e069b5Sstsp 
135406e069b5Sstsp 		/*
135506e069b5Sstsp 		 * After a background scan, we have now switched APs.
135606e069b5Sstsp 		 * Pretend we were just de-authed, which makes
135706e069b5Sstsp 		 * ieee80211_new_state() try to re-auth and thus send
135806e069b5Sstsp 		 * an AUTH frame to our newly selected AP.
135906e069b5Sstsp 		 */
136040dc231eSstsp 		if (bgscan)
136140dc231eSstsp 			mgt = IEEE80211_FC0_SUBTYPE_DEAUTH;
136240dc231eSstsp 		/*
136340dc231eSstsp 		 * If we are trying another AP after the previous one
136440dc231eSstsp 		 * failed (state transition AUTH->AUTH), ensure that
136540dc231eSstsp 		 * ieee80211_new_state() tries to send another auth frame.
136640dc231eSstsp 		 */
136740dc231eSstsp 		else if (auth_next)
136840dc231eSstsp 			mgt = IEEE80211_FC0_SUBTYPE_AUTH;
136940dc231eSstsp 
137040dc231eSstsp 		ieee80211_new_state(ic, IEEE80211_S_AUTH, mgt);
137106e069b5Sstsp 	}
137206e069b5Sstsp }
137306e069b5Sstsp 
137440dc231eSstsp struct ieee80211_node *
137540dc231eSstsp ieee80211_node_choose_bss(struct ieee80211com *ic, int bgscan,
137640dc231eSstsp     struct ieee80211_node **curbs)
137740dc231eSstsp {
137840dc231eSstsp 	struct ieee80211_node *ni, *nextbs, *selbs = NULL,
137940dc231eSstsp 	    *selbs2 = NULL, *selbs5 = NULL;
138040dc231eSstsp 	uint8_t min_5ghz_rssi;
138140dc231eSstsp 
138240dc231eSstsp 	ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
138340dc231eSstsp 
138440dc231eSstsp 	for (; ni != NULL; ni = nextbs) {
138540dc231eSstsp 		nextbs = RBT_NEXT(ieee80211_tree, ni);
138640dc231eSstsp 		if (ni->ni_fails) {
138740dc231eSstsp 			/*
138840dc231eSstsp 			 * The configuration of the access points may change
138940dc231eSstsp 			 * during my scan.  So delete the entry for the AP
139040dc231eSstsp 			 * and retry to associate if there is another beacon.
139140dc231eSstsp 			 */
139240dc231eSstsp 			if (ni->ni_fails++ > 2)
139340dc231eSstsp 				ieee80211_free_node(ic, ni);
139440dc231eSstsp 			continue;
139540dc231eSstsp 		}
139640dc231eSstsp 
139740dc231eSstsp 		if (curbs && ieee80211_node_cmp(ic->ic_bss, ni) == 0)
139840dc231eSstsp 			*curbs = ni;
139940dc231eSstsp 
1400799b58a5Sstsp 		if (ieee80211_match_bss(ic, ni, bgscan) != 0)
140140dc231eSstsp 			continue;
140240dc231eSstsp 
140340dc231eSstsp 		if (ic->ic_caps & IEEE80211_C_SCANALLBAND) {
140440dc231eSstsp 			if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) &&
140540dc231eSstsp 			    (selbs2 == NULL || ni->ni_rssi > selbs2->ni_rssi))
140640dc231eSstsp 				selbs2 = ni;
140740dc231eSstsp 			else if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) &&
140840dc231eSstsp 			    (selbs5 == NULL || ni->ni_rssi > selbs5->ni_rssi))
140940dc231eSstsp 				selbs5 = ni;
141040dc231eSstsp 		} else if (selbs == NULL || ni->ni_rssi > selbs->ni_rssi)
141140dc231eSstsp 			selbs = ni;
141240dc231eSstsp 	}
141340dc231eSstsp 
141440dc231eSstsp 	if (ic->ic_max_rssi)
141540dc231eSstsp 		min_5ghz_rssi = IEEE80211_RSSI_THRES_RATIO_5GHZ;
141640dc231eSstsp 	else
141740dc231eSstsp 		min_5ghz_rssi = (uint8_t)IEEE80211_RSSI_THRES_5GHZ;
141840dc231eSstsp 
141940dc231eSstsp 	/*
142040dc231eSstsp 	 * Prefer a 5Ghz AP even if its RSSI is weaker than the best 2Ghz AP
142140dc231eSstsp 	 * (as long as it meets the minimum RSSI threshold) since the 5Ghz band
142240dc231eSstsp 	 * is usually less saturated.
142340dc231eSstsp 	 */
142497c37057Sstsp 	if (selbs5 && (*ic->ic_node_checkrssi)(ic, selbs5))
142540dc231eSstsp 		selbs = selbs5;
142640dc231eSstsp 	else if (selbs5 && selbs2)
142740dc231eSstsp 		selbs = (selbs5->ni_rssi >= selbs2->ni_rssi ? selbs5 : selbs2);
142840dc231eSstsp 	else if (selbs2)
142940dc231eSstsp 		selbs = selbs2;
143040dc231eSstsp 	else if (selbs5)
143140dc231eSstsp 		selbs = selbs5;
143240dc231eSstsp 
143340dc231eSstsp 	return selbs;
143440dc231eSstsp }
143540dc231eSstsp 
143691b2158bSmillert /*
143791b2158bSmillert  * Complete a scan of potential channels.
143891b2158bSmillert  */
143991b2158bSmillert void
144091b2158bSmillert ieee80211_end_scan(struct ifnet *ifp)
144191b2158bSmillert {
144291b2158bSmillert 	struct ieee80211com *ic = (void *)ifp;
144340dc231eSstsp 	struct ieee80211_node *ni, *selbs = NULL, *curbs = NULL;
144406e069b5Sstsp 	int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) &&
144506e069b5Sstsp 	    ic->ic_opmode == IEEE80211_M_STA &&
144606e069b5Sstsp 	    ic->ic_state == IEEE80211_S_RUN);
144791b2158bSmillert 
14480fd4e251Sreyk 	if (ifp->if_flags & IFF_DEBUG)
1449a0068c42Sjsg 		printf("%s: end %s scan\n", ifp->if_xname,
145006e069b5Sstsp 		    bgscan ? "background" :
145106e069b5Sstsp 		    ((ic->ic_flags & IEEE80211_F_ASCAN) ?
145206e069b5Sstsp 		    "active" : "passive"));
14530fd4e251Sreyk 
145414207dadSreyk 	if (ic->ic_scan_count)
145591b2158bSmillert 		ic->ic_flags &= ~IEEE80211_F_ASCAN;
145614207dadSreyk 
14576a173c79Sstsp 	if (ic->ic_opmode == IEEE80211_M_STA)
14586a173c79Sstsp 		ieee80211_clean_inactive_nodes(ic, IEEE80211_INACT_SCAN);
14596a173c79Sstsp 
14608529d8f0Sdlg 	ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
146191b2158bSmillert 
1462171ac09aSdamien #ifndef IEEE80211_STA_ONLY
146391b2158bSmillert 	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
146491b2158bSmillert 		/* XXX off stack? */
1465966ef700Sdamien 		u_char occupied[howmany(IEEE80211_CHAN_MAX, NBBY)];
1466171ac09aSdamien 		int i, fail;
1467171ac09aSdamien 
146891b2158bSmillert 		/*
146991b2158bSmillert 		 * The passive scan to look for existing AP's completed,
147091b2158bSmillert 		 * select a channel to camp on.  Identify the channels
147191b2158bSmillert 		 * that already have one or more AP's and try to locate
1472bae35bbcSsthen 		 * an unoccupied one.  If that fails, pick a random
147391b2158bSmillert 		 * channel from the active set.
147491b2158bSmillert 		 */
147597e63874Skrw 		memset(occupied, 0, sizeof(occupied));
14768529d8f0Sdlg 		RBT_FOREACH(ni, ieee80211_tree, &ic->ic_tree)
147791b2158bSmillert 			setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan));
147891b2158bSmillert 		for (i = 0; i < IEEE80211_CHAN_MAX; i++)
147991b2158bSmillert 			if (isset(ic->ic_chan_active, i) && isclr(occupied, i))
148091b2158bSmillert 				break;
148191b2158bSmillert 		if (i == IEEE80211_CHAN_MAX) {
148291b2158bSmillert 			fail = arc4random() & 3;	/* random 0-3 */
148391b2158bSmillert 			for (i = 0; i < IEEE80211_CHAN_MAX; i++)
148491b2158bSmillert 				if (isset(ic->ic_chan_active, i) && fail-- == 0)
148591b2158bSmillert 					break;
148691b2158bSmillert 		}
148791b2158bSmillert 		ieee80211_create_ibss(ic, &ic->ic_channels[i]);
14882fa6698eSpirofti 		return;
148991b2158bSmillert 	}
1490171ac09aSdamien #endif
149191b2158bSmillert 	if (ni == NULL) {
1492932b9027Sdamien 		DPRINTF(("no scan candidate\n"));
149391b2158bSmillert  notfound:
1494171ac09aSdamien 
1495171ac09aSdamien #ifndef IEEE80211_STA_ONLY
149691b2158bSmillert 		if (ic->ic_opmode == IEEE80211_M_IBSS &&
149791b2158bSmillert 		    (ic->ic_flags & IEEE80211_F_IBSSON) &&
149891b2158bSmillert 		    ic->ic_des_esslen != 0) {
149991b2158bSmillert 			ieee80211_create_ibss(ic, ic->ic_ibss_chan);
15002fa6698eSpirofti 			return;
150191b2158bSmillert 		}
1502171ac09aSdamien #endif
1503d424122bSreyk 		/*
1504f4348f20Sstsp 		 * Reset the list of channels to scan and scan the next mode
1505f4348f20Sstsp 		 * if nothing has been found.
150637adb543Sstsp 		 * If the device scans all bands in one fell swoop, return
150737adb543Sstsp 		 * current scan results to userspace regardless of mode.
1508f4348f20Sstsp 		 * This will loop forever until an access point is found.
1509d424122bSreyk 		 */
1510f4348f20Sstsp 		ieee80211_reset_scan(ifp);
151137adb543Sstsp 		if (ieee80211_next_mode(ifp) == IEEE80211_MODE_AUTO ||
1512ef574d6dSstsp 		    (ic->ic_caps & IEEE80211_C_SCANALLBAND))
151314207dadSreyk 			ic->ic_scan_count++;
1514d424122bSreyk 
151591b2158bSmillert 		ieee80211_next_scan(ifp);
151691b2158bSmillert 		return;
151791b2158bSmillert 	}
15180fd4e251Sreyk 
1519020402a2Sphessler 	/* Possibly switch which ssid we are associated with */
15208cc58491Sphessler 	if (!bgscan && ic->ic_opmode == IEEE80211_M_STA)
15217d35c188Sstsp 		ieee80211_switch_ess(ic);
1522020402a2Sphessler 
152340dc231eSstsp 	selbs = ieee80211_node_choose_bss(ic, bgscan, &curbs);
152406e069b5Sstsp 	if (bgscan) {
152506e069b5Sstsp 		struct ieee80211_node_switch_bss_arg *arg;
152606e069b5Sstsp 
152706e069b5Sstsp 		/* AP disappeared? Should not happen. */
152806e069b5Sstsp 		if (selbs == NULL || curbs == NULL) {
152906e069b5Sstsp 			ic->ic_flags &= ~IEEE80211_F_BGSCAN;
153091b2158bSmillert 			goto notfound;
153106e069b5Sstsp 		}
15321bb78573Sdamien 
153306e069b5Sstsp 		/*
153406e069b5Sstsp 		 * After a background scan we might end up choosing the
153505e5c691Sstsp 		 * same AP again. Or the newly selected AP's RSSI level
153605e5c691Sstsp 		 * might be low enough to trigger another background scan.
153705e5c691Sstsp 		 * Do not change ic->ic_bss in these cases and make
153805e5c691Sstsp 		 * background scans less frequent.
153906e069b5Sstsp 		 */
154005e5c691Sstsp 		if (selbs == curbs || !(*ic->ic_node_checkrssi)(ic, selbs)) {
15410140f0f1Sstsp 			if (ic->ic_bgscan_fail < IEEE80211_BGSCAN_FAIL_MAX) {
15420140f0f1Sstsp 				if (ic->ic_bgscan_fail <= 0)
15430140f0f1Sstsp 					ic->ic_bgscan_fail = 1;
15440140f0f1Sstsp 				else
15450140f0f1Sstsp 					ic->ic_bgscan_fail *= 2;
15460140f0f1Sstsp 			}
154706e069b5Sstsp 			ic->ic_flags &= ~IEEE80211_F_BGSCAN;
1548c72ef016Sstsp 
1549c72ef016Sstsp 			/*
1550c72ef016Sstsp 			 * HT is negotiated during association so we must use
1551c72ef016Sstsp 			 * ic_bss to check HT. The nodes tree was re-populated
1552c72ef016Sstsp 			 * during background scan and therefore selbs and curbs
1553c72ef016Sstsp 			 * may not carry HT information.
1554c72ef016Sstsp 			 */
1555c72ef016Sstsp 			ni = ic->ic_bss;
1556c72ef016Sstsp 			if (ni->ni_flags & IEEE80211_NODE_VHT)
1557c72ef016Sstsp 				ieee80211_setmode(ic, IEEE80211_MODE_11AC);
1558c72ef016Sstsp 			else if (ni->ni_flags & IEEE80211_NODE_HT)
1559c72ef016Sstsp 				ieee80211_setmode(ic, IEEE80211_MODE_11N);
1560c72ef016Sstsp 			else
1561c72ef016Sstsp 				ieee80211_setmode(ic,
1562c72ef016Sstsp 				    ieee80211_chan2mode(ic, ni->ni_chan));
15632fa6698eSpirofti 			return;
156406e069b5Sstsp 		}
1565b9a49307Sgerhard 
156606e069b5Sstsp 		arg = malloc(sizeof(*arg), M_DEVBUF, M_NOWAIT | M_ZERO);
156706e069b5Sstsp 		if (arg == NULL) {
156806e069b5Sstsp 			ic->ic_flags &= ~IEEE80211_F_BGSCAN;
15692fa6698eSpirofti 			return;
157006e069b5Sstsp 		}
1571960d072bSstsp 
157206e069b5Sstsp 		ic->ic_bgscan_fail = 0;
1573e03e709cSdamien 
157406e069b5Sstsp 		/* Prevent dispatch of additional data frames to hardware. */
157506e069b5Sstsp 		ic->ic_xflags |= IEEE80211_F_TX_MGMT_ONLY;
157606e069b5Sstsp 
1577de9c1173Sstsp 		IEEE80211_ADDR_COPY(arg->cur_macaddr, curbs->ni_macaddr);
1578de9c1173Sstsp 		IEEE80211_ADDR_COPY(arg->sel_macaddr, selbs->ni_macaddr);
1579de9c1173Sstsp 
1580de9c1173Sstsp 		if (ic->ic_bgscan_done) {
1581de9c1173Sstsp 			/*
1582de9c1173Sstsp 			 * The driver will flush its queues and allow roaming
1583de9c1173Sstsp 			 * to proceed once queues have been flushed.
1584de9c1173Sstsp 			 * On failure the driver will move back to SCAN state.
1585de9c1173Sstsp 			 */
1586de9c1173Sstsp 			ic->ic_bgscan_done(ic, arg, sizeof(*arg));
1587de9c1173Sstsp 			return;
1588de9c1173Sstsp 		}
1589de9c1173Sstsp 
159006e069b5Sstsp 		/*
159106e069b5Sstsp 		 * Install a callback which will switch us to the new AP once
159206e069b5Sstsp 		 * all dispatched frames have been processed by hardware.
159306e069b5Sstsp 		 */
159406e069b5Sstsp 		ic->ic_bss->ni_unref_arg = arg;
159506e069b5Sstsp 		ic->ic_bss->ni_unref_arg_size = sizeof(*arg);
1596de9c1173Sstsp 		if (ic->ic_bss->ni_refcnt > 0)
1597de9c1173Sstsp 			ic->ic_bss->ni_unref_cb = ieee80211_node_tx_flushed;
1598de9c1173Sstsp 		else
1599de9c1173Sstsp 			ieee80211_node_tx_flushed(ic, ni);
160006e069b5Sstsp 		/* F_BGSCAN flag gets cleared in ieee80211_node_join_bss(). */
16012fa6698eSpirofti 		return;
160206e069b5Sstsp 	} else if (selbs == NULL)
160391b2158bSmillert 		goto notfound;
160406e069b5Sstsp 
160506e069b5Sstsp 	ieee80211_node_join_bss(ic, selbs);
160691b2158bSmillert }
160791b2158bSmillert 
1608f91ff320Sdamien /*
1609f91ff320Sdamien  * Autoselect the best RSN parameters (protocol, AKMP, pairwise cipher...)
1610f91ff320Sdamien  * that are supported by both peers (STA mode only).
1611f91ff320Sdamien  */
1612f91ff320Sdamien void
1613f91ff320Sdamien ieee80211_choose_rsnparams(struct ieee80211com *ic)
1614f91ff320Sdamien {
1615f91ff320Sdamien 	struct ieee80211_node *ni = ic->ic_bss;
1616f91ff320Sdamien 	struct ieee80211_pmk *pmk;
1617f91ff320Sdamien 
1618f91ff320Sdamien 	/* filter out unsupported protocol versions */
1619f91ff320Sdamien 	ni->ni_rsnprotos &= ic->ic_rsnprotos;
1620f91ff320Sdamien 	/* prefer RSN (aka WPA2) over WPA */
1621f91ff320Sdamien 	if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)
1622f91ff320Sdamien 		ni->ni_rsnprotos = IEEE80211_PROTO_RSN;
1623f91ff320Sdamien 	else
1624f91ff320Sdamien 		ni->ni_rsnprotos = IEEE80211_PROTO_WPA;
1625f91ff320Sdamien 
1626f91ff320Sdamien 	/* filter out unsupported AKMPs */
1627f91ff320Sdamien 	ni->ni_rsnakms &= ic->ic_rsnakms;
1628f91ff320Sdamien 	/* prefer SHA-256 based AKMPs */
1629f91ff320Sdamien 	if ((ic->ic_flags & IEEE80211_F_PSK) && (ni->ni_rsnakms &
1630f91ff320Sdamien 	    (IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK))) {
1631f91ff320Sdamien 		/* AP supports PSK AKMP and a PSK is configured */
1632f91ff320Sdamien 		if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK)
1633f91ff320Sdamien 			ni->ni_rsnakms = IEEE80211_AKM_SHA256_PSK;
1634f91ff320Sdamien 		else
1635f91ff320Sdamien 			ni->ni_rsnakms = IEEE80211_AKM_PSK;
1636f91ff320Sdamien 	} else {
1637f91ff320Sdamien 		if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X)
1638f91ff320Sdamien 			ni->ni_rsnakms = IEEE80211_AKM_SHA256_8021X;
1639f91ff320Sdamien 		else
1640f91ff320Sdamien 			ni->ni_rsnakms = IEEE80211_AKM_8021X;
1641f91ff320Sdamien 		/* check if we have a cached PMK for this AP */
1642f91ff320Sdamien 		if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
1643f91ff320Sdamien 		    (pmk = ieee80211_pmksa_find(ic, ni, NULL)) != NULL) {
1644f91ff320Sdamien 			memcpy(ni->ni_pmkid, pmk->pmk_pmkid,
1645f91ff320Sdamien 			    IEEE80211_PMKID_LEN);
1646f91ff320Sdamien 			ni->ni_flags |= IEEE80211_NODE_PMKID;
1647f91ff320Sdamien 		}
1648f91ff320Sdamien 	}
1649f91ff320Sdamien 
1650f91ff320Sdamien 	/* filter out unsupported pairwise ciphers */
1651f91ff320Sdamien 	ni->ni_rsnciphers &= ic->ic_rsnciphers;
1652f91ff320Sdamien 	/* prefer CCMP over TKIP */
1653f91ff320Sdamien 	if (ni->ni_rsnciphers & IEEE80211_CIPHER_CCMP)
1654f91ff320Sdamien 		ni->ni_rsnciphers = IEEE80211_CIPHER_CCMP;
1655f91ff320Sdamien 	else
1656f91ff320Sdamien 		ni->ni_rsnciphers = IEEE80211_CIPHER_TKIP;
1657f91ff320Sdamien 	ni->ni_rsncipher = ni->ni_rsnciphers;
1658f91ff320Sdamien 
1659f91ff320Sdamien 	/* use MFP if we both support it */
1660f91ff320Sdamien 	if ((ic->ic_caps & IEEE80211_C_MFP) &&
1661f91ff320Sdamien 	    (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC))
1662f91ff320Sdamien 		ni->ni_flags |= IEEE80211_NODE_MFP;
1663f91ff320Sdamien }
1664f91ff320Sdamien 
166591b2158bSmillert int
166691b2158bSmillert ieee80211_get_rate(struct ieee80211com *ic)
166791b2158bSmillert {
166891b2158bSmillert 	u_int8_t (*rates)[IEEE80211_RATE_MAXSIZE];
166991b2158bSmillert 	int rate;
167091b2158bSmillert 
167191b2158bSmillert 	rates = &ic->ic_bss->ni_rates.rs_rates;
167291b2158bSmillert 
167391b2158bSmillert 	if (ic->ic_fixed_rate != -1)
167491b2158bSmillert 		rate = (*rates)[ic->ic_fixed_rate];
167591b2158bSmillert 	else if (ic->ic_state == IEEE80211_S_RUN)
167691b2158bSmillert 		rate = (*rates)[ic->ic_bss->ni_txrate];
167791b2158bSmillert 	else
167891b2158bSmillert 		rate = 0;
167991b2158bSmillert 
168091b2158bSmillert 	return rate & IEEE80211_RATE_VAL;
168191b2158bSmillert }
168291b2158bSmillert 
1683250085e6Sdamien struct ieee80211_node *
168491b2158bSmillert ieee80211_node_alloc(struct ieee80211com *ic)
168591b2158bSmillert {
16867fb98acfSstsp 	return malloc(sizeof(struct ieee80211_node), M_DEVBUF,
1687aec33cadSdamien 	    M_NOWAIT | M_ZERO);
168891b2158bSmillert }
168991b2158bSmillert 
1690250085e6Sdamien void
16910fd4e251Sreyk ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni)
169291b2158bSmillert {
1693e03e709cSdamien 	if (ni->ni_rsnie != NULL) {
1694e93df640Stb 		free(ni->ni_rsnie, M_DEVBUF, 2 + ni->ni_rsnie[1]);
1695e03e709cSdamien 		ni->ni_rsnie = NULL;
1696e03e709cSdamien 	}
1697633cd82cSstsp 	ieee80211_ba_del(ni);
1698539559bcSstsp #ifndef IEEE80211_STA_ONLY
1699539559bcSstsp 	mq_purge(&ni->ni_savedq);
1700539559bcSstsp #endif
1701de9c1173Sstsp 	ieee80211_node_free_unref_cb(ni);
17020fd4e251Sreyk }
17030fd4e251Sreyk 
1704250085e6Sdamien void
17050fd4e251Sreyk ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
17060fd4e251Sreyk {
17070fd4e251Sreyk 	ieee80211_node_cleanup(ic, ni);
1708dd168dc2Stedu 	free(ni, M_DEVBUF, 0);
170991b2158bSmillert }
171091b2158bSmillert 
1711250085e6Sdamien void
171291b2158bSmillert ieee80211_node_copy(struct ieee80211com *ic,
171391b2158bSmillert 	struct ieee80211_node *dst, const struct ieee80211_node *src)
171491b2158bSmillert {
17150fd4e251Sreyk 	ieee80211_node_cleanup(ic, dst);
171691b2158bSmillert 	*dst = *src;
1717e03e709cSdamien 	dst->ni_rsnie = NULL;
1718e03e709cSdamien 	if (src->ni_rsnie != NULL)
1719e03e709cSdamien 		ieee80211_save_ie(src->ni_rsnie, &dst->ni_rsnie);
1720aefc44daSstsp 	ieee80211_node_set_timeouts(dst);
1721aefc44daSstsp #ifndef IEEE80211_STA_ONLY
1722aefc44daSstsp 	mq_init(&dst->ni_savedq, IEEE80211_PS_MAX_QUEUE, IPL_NET);
1723aefc44daSstsp #endif
172491b2158bSmillert }
172591b2158bSmillert 
1726250085e6Sdamien u_int8_t
1727f22d9adcSdamien ieee80211_node_getrssi(struct ieee80211com *ic,
1728f22d9adcSdamien     const struct ieee80211_node *ni)
172991b2158bSmillert {
173091b2158bSmillert 	return ni->ni_rssi;
173191b2158bSmillert }
173291b2158bSmillert 
173306e069b5Sstsp int
173406e069b5Sstsp ieee80211_node_checkrssi(struct ieee80211com *ic,
173506e069b5Sstsp     const struct ieee80211_node *ni)
173606e069b5Sstsp {
173706e069b5Sstsp 	uint8_t thres;
173806e069b5Sstsp 
173949a206bdSstsp 	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
174049a206bdSstsp 		return 0;
174149a206bdSstsp 
174206e069b5Sstsp 	if (ic->ic_max_rssi) {
174306e069b5Sstsp 		thres = (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) ?
174406e069b5Sstsp 		    IEEE80211_RSSI_THRES_RATIO_2GHZ :
174506e069b5Sstsp 		    IEEE80211_RSSI_THRES_RATIO_5GHZ;
174606e069b5Sstsp 		return ((ni->ni_rssi * 100) / ic->ic_max_rssi >= thres);
174706e069b5Sstsp 	}
174806e069b5Sstsp 
174906e069b5Sstsp 	thres = (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) ?
175006e069b5Sstsp 	    IEEE80211_RSSI_THRES_2GHZ :
175106e069b5Sstsp 	    IEEE80211_RSSI_THRES_5GHZ;
175206e069b5Sstsp 	return (ni->ni_rssi >= (u_int8_t)thres);
175306e069b5Sstsp }
175406e069b5Sstsp 
1755250085e6Sdamien void
1756aefc44daSstsp ieee80211_node_set_timeouts(struct ieee80211_node *ni)
1757aefc44daSstsp {
1758aefc44daSstsp 	int i;
1759aefc44daSstsp 
1760aefc44daSstsp #ifndef IEEE80211_STA_ONLY
1761aefc44daSstsp 	timeout_set(&ni->ni_eapol_to, ieee80211_eapol_timeout, ni);
1762aefc44daSstsp 	timeout_set(&ni->ni_sa_query_to, ieee80211_sa_query_timeout, ni);
1763aefc44daSstsp #endif
1764aefc44daSstsp 	timeout_set(&ni->ni_addba_req_to[EDCA_AC_BE],
1765aefc44daSstsp 	    ieee80211_node_addba_request_ac_be_to, ni);
1766aefc44daSstsp 	timeout_set(&ni->ni_addba_req_to[EDCA_AC_BK],
1767aefc44daSstsp 	    ieee80211_node_addba_request_ac_bk_to, ni);
1768aefc44daSstsp 	timeout_set(&ni->ni_addba_req_to[EDCA_AC_VI],
1769aefc44daSstsp 	    ieee80211_node_addba_request_ac_vi_to, ni);
1770aefc44daSstsp 	timeout_set(&ni->ni_addba_req_to[EDCA_AC_VO],
1771aefc44daSstsp 	    ieee80211_node_addba_request_ac_vo_to, ni);
1772aefc44daSstsp 	for (i = 0; i < nitems(ni->ni_addba_req_intval); i++)
1773aefc44daSstsp 		ni->ni_addba_req_intval[i] = 1;
1774aefc44daSstsp }
1775aefc44daSstsp 
1776aefc44daSstsp void
177791b2158bSmillert ieee80211_setup_node(struct ieee80211com *ic,
1778f22d9adcSdamien 	struct ieee80211_node *ni, const u_int8_t *macaddr)
177991b2158bSmillert {
178025d2707aSpatrick 	int i, s;
17815d155c7eSdamien 
1782932b9027Sdamien 	DPRINTF(("%s\n", ether_sprintf((u_int8_t *)macaddr)));
178391b2158bSmillert 	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
17840fd4e251Sreyk 	ieee80211_node_newstate(ni, IEEE80211_STA_CACHE);
17850fd4e251Sreyk 
1786e03e709cSdamien 	ni->ni_ic = ic;	/* back-pointer */
178725d2707aSpatrick 	/* Initialize cached last sequence numbers with invalid values. */
178825d2707aSpatrick 	ni->ni_rxseq = 0xffffU;
178925d2707aSpatrick 	for (i=0; i < IEEE80211_NUM_TID; ++i)
179025d2707aSpatrick 		ni->ni_qos_rxseqs[i] = 0xffffU;
1791c720ca3cSdamien #ifndef IEEE80211_STA_ONLY
1792351e1934Sdlg 	mq_init(&ni->ni_savedq, IEEE80211_PS_MAX_QUEUE, IPL_NET);
1793c720ca3cSdamien #endif
1794aefc44daSstsp 	ieee80211_node_set_timeouts(ni);
1795aefc44daSstsp 
17965d155c7eSdamien 	s = splnet();
17978529d8f0Sdlg 	RBT_INSERT(ieee80211_tree, &ic->ic_tree, ni);
1798937967bbSstsp 	ic->ic_nnodes++;
17995d155c7eSdamien 	splx(s);
180091b2158bSmillert }
180191b2158bSmillert 
180291b2158bSmillert struct ieee80211_node *
1803f22d9adcSdamien ieee80211_alloc_node(struct ieee80211com *ic, const u_int8_t *macaddr)
180491b2158bSmillert {
18050fd4e251Sreyk 	struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic);
180691b2158bSmillert 	if (ni != NULL)
180791b2158bSmillert 		ieee80211_setup_node(ic, ni, macaddr);
180891b2158bSmillert 	else
180991b2158bSmillert 		ic->ic_stats.is_rx_nodealloc++;
181091b2158bSmillert 	return ni;
181191b2158bSmillert }
181291b2158bSmillert 
181391b2158bSmillert struct ieee80211_node *
1814f22d9adcSdamien ieee80211_dup_bss(struct ieee80211com *ic, const u_int8_t *macaddr)
181591b2158bSmillert {
18160fd4e251Sreyk 	struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic);
181791b2158bSmillert 	if (ni != NULL) {
181891b2158bSmillert 		ieee80211_setup_node(ic, ni, macaddr);
181991b2158bSmillert 		/*
182091b2158bSmillert 		 * Inherit from ic_bss.
182191b2158bSmillert 		 */
182291b2158bSmillert 		IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
182391b2158bSmillert 		ni->ni_chan = ic->ic_bss->ni_chan;
182491b2158bSmillert 	} else
182591b2158bSmillert 		ic->ic_stats.is_rx_nodealloc++;
182691b2158bSmillert 	return ni;
182791b2158bSmillert }
182891b2158bSmillert 
182991b2158bSmillert struct ieee80211_node *
1830f22d9adcSdamien ieee80211_find_node(struct ieee80211com *ic, const u_int8_t *macaddr)
183191b2158bSmillert {
18329a4d53fcSdamien 	struct ieee80211_node *ni;
18339a4d53fcSdamien 	int cmp;
18349a4d53fcSdamien 
18358529d8f0Sdlg 	/* similar to RBT_FIND except we compare keys, not nodes */
18368529d8f0Sdlg 	ni = RBT_ROOT(ieee80211_tree, &ic->ic_tree);
18379a4d53fcSdamien 	while (ni != NULL) {
18389a4d53fcSdamien 		cmp = memcmp(macaddr, ni->ni_macaddr, IEEE80211_ADDR_LEN);
18399a4d53fcSdamien 		if (cmp < 0)
18408529d8f0Sdlg 			ni = RBT_LEFT(ieee80211_tree, ni);
18419a4d53fcSdamien 		else if (cmp > 0)
18428529d8f0Sdlg 			ni = RBT_RIGHT(ieee80211_tree, ni);
18439a4d53fcSdamien 		else
18449a4d53fcSdamien 			break;
18459a4d53fcSdamien 	}
18469a4d53fcSdamien 	return ni;
184791b2158bSmillert }
184891b2158bSmillert 
184991b2158bSmillert /*
185091b2158bSmillert  * Return a reference to the appropriate node for sending
185191b2158bSmillert  * a data frame.  This handles node discovery in adhoc networks.
18520fd4e251Sreyk  *
18530fd4e251Sreyk  * Drivers will call this, so increase the reference count before
18540fd4e251Sreyk  * returning the node.
185591b2158bSmillert  */
185691b2158bSmillert struct ieee80211_node *
1857f22d9adcSdamien ieee80211_find_txnode(struct ieee80211com *ic, const u_int8_t *macaddr)
185891b2158bSmillert {
1859171ac09aSdamien #ifndef IEEE80211_STA_ONLY
186091b2158bSmillert 	struct ieee80211_node *ni;
18615d155c7eSdamien 	int s;
1862171ac09aSdamien #endif
186391b2158bSmillert 
186491b2158bSmillert 	/*
186591b2158bSmillert 	 * The destination address should be in the node table
186691b2158bSmillert 	 * unless we are operating in station mode or this is a
186791b2158bSmillert 	 * multicast/broadcast frame.
186891b2158bSmillert 	 */
186991b2158bSmillert 	if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
18700fd4e251Sreyk 		return ieee80211_ref_node(ic->ic_bss);
187191b2158bSmillert 
1872171ac09aSdamien #ifndef IEEE80211_STA_ONLY
18735d155c7eSdamien 	s = splnet();
18743ce67372Sreyk 	ni = ieee80211_find_node(ic, macaddr);
18755d155c7eSdamien 	splx(s);
18760fd4e251Sreyk 	if (ni == NULL) {
18770fd4e251Sreyk 		if (ic->ic_opmode != IEEE80211_M_IBSS &&
18780fd4e251Sreyk 		    ic->ic_opmode != IEEE80211_M_AHDEMO)
18790fd4e251Sreyk 			return NULL;
18800fd4e251Sreyk 
188191b2158bSmillert 		/*
188291b2158bSmillert 		 * Fake up a node; this handles node discovery in
188391b2158bSmillert 		 * adhoc mode.  Note that for the driver's benefit
1884b3af768dSjsg 		 * we treat this like an association so the driver
18850f1683a6Smiod 		 * has an opportunity to setup its private state.
188691b2158bSmillert 		 *
188791b2158bSmillert 		 * XXX need better way to handle this; issue probe
188891b2158bSmillert 		 *     request so we can deduce rate set, etc.
188991b2158bSmillert 		 */
18900fd4e251Sreyk 		if ((ni = ieee80211_dup_bss(ic, macaddr)) == NULL)
18910fd4e251Sreyk 			return NULL;
189291b2158bSmillert 		/* XXX no rate negotiation; just dup */
189391b2158bSmillert 		ni->ni_rates = ic->ic_bss->ni_rates;
1894f1d7120cSstsp 		ni->ni_txrate = 0;
189591b2158bSmillert 		if (ic->ic_newassoc)
189691b2158bSmillert 			(*ic->ic_newassoc)(ic, ni, 1);
189791b2158bSmillert 	}
18980fd4e251Sreyk 	return ieee80211_ref_node(ni);
1899171ac09aSdamien #else
1900171ac09aSdamien 	return NULL;	/* can't get there */
1901171ac09aSdamien #endif	/* IEEE80211_STA_ONLY */
190291b2158bSmillert }
190391b2158bSmillert 
190491b2158bSmillert /*
19050fd4e251Sreyk  * It is usually desirable to process a Rx packet using its sender's
19060fd4e251Sreyk  * node-record instead of the BSS record.
190791b2158bSmillert  *
19080fd4e251Sreyk  * - AP mode: keep a node-record for every authenticated/associated
19090fd4e251Sreyk  *   station *in the BSS*. For future use, we also track neighboring
19100fd4e251Sreyk  *   APs, since they might belong to the same ESS.  APs in the same
19110fd4e251Sreyk  *   ESS may bridge packets to each other, forming a Wireless
19120fd4e251Sreyk  *   Distribution System (WDS).
191391b2158bSmillert  *
19140fd4e251Sreyk  * - IBSS mode: keep a node-record for every station *in the BSS*.
19150fd4e251Sreyk  *   Also track neighboring stations by their beacons/probe responses.
191691b2158bSmillert  *
19170fd4e251Sreyk  * - monitor mode: keep a node-record for every sender, regardless
19180fd4e251Sreyk  *   of BSS.
191991b2158bSmillert  *
192091b2158bSmillert  * - STA mode: the only available node-record is the BSS record,
192191b2158bSmillert  *   ic->ic_bss.
192291b2158bSmillert  *
192391b2158bSmillert  * Of all the 802.11 Control packets, only the node-records for
192491b2158bSmillert  * RTS packets node-record can be looked up.
192591b2158bSmillert  *
192691b2158bSmillert  * Return non-zero if the packet's node-record is kept, zero
192791b2158bSmillert  * otherwise.
192891b2158bSmillert  */
192991b2158bSmillert static __inline int
1930f22d9adcSdamien ieee80211_needs_rxnode(struct ieee80211com *ic,
1931f22d9adcSdamien     const struct ieee80211_frame *wh, const u_int8_t **bssid)
193291b2158bSmillert {
19330fd4e251Sreyk 	int monitor, rc = 0;
193491b2158bSmillert 
19350fd4e251Sreyk 	monitor = (ic->ic_opmode == IEEE80211_M_MONITOR);
193691b2158bSmillert 
193791b2158bSmillert 	*bssid = NULL;
193891b2158bSmillert 
193991b2158bSmillert 	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
194091b2158bSmillert 	case IEEE80211_FC0_TYPE_CTL:
19410fd4e251Sreyk 		if (!monitor)
19420fd4e251Sreyk 			break;
194391b2158bSmillert 		return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
194491b2158bSmillert 		    IEEE80211_FC0_SUBTYPE_RTS;
194591b2158bSmillert 	case IEEE80211_FC0_TYPE_MGT:
194691b2158bSmillert 		*bssid = wh->i_addr3;
19470fd4e251Sreyk 		switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
19480fd4e251Sreyk 		case IEEE80211_FC0_SUBTYPE_BEACON:
19490fd4e251Sreyk 		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
19500fd4e251Sreyk 			break;
19510fd4e251Sreyk 		default:
1952171ac09aSdamien #ifndef IEEE80211_STA_ONLY
19530fd4e251Sreyk 			if (ic->ic_opmode == IEEE80211_M_STA)
19540fd4e251Sreyk 				break;
1955171ac09aSdamien 			rc = IEEE80211_ADDR_EQ(*bssid, ic->ic_bss->ni_bssid) ||
19560fd4e251Sreyk 			     IEEE80211_ADDR_EQ(*bssid, etherbroadcastaddr);
1957171ac09aSdamien #endif
19580fd4e251Sreyk 			break;
19590fd4e251Sreyk 		}
196091b2158bSmillert 		break;
196191b2158bSmillert 	case IEEE80211_FC0_TYPE_DATA:
196291b2158bSmillert 		switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
196391b2158bSmillert 		case IEEE80211_FC1_DIR_NODS:
196491b2158bSmillert 			*bssid = wh->i_addr3;
1965171ac09aSdamien #ifndef IEEE80211_STA_ONLY
196691b2158bSmillert 			if (ic->ic_opmode == IEEE80211_M_IBSS ||
196791b2158bSmillert 			    ic->ic_opmode == IEEE80211_M_AHDEMO)
1968171ac09aSdamien 				rc = IEEE80211_ADDR_EQ(*bssid,
1969171ac09aSdamien 				    ic->ic_bss->ni_bssid);
1970171ac09aSdamien #endif
197191b2158bSmillert 			break;
197291b2158bSmillert 		case IEEE80211_FC1_DIR_TODS:
197391b2158bSmillert 			*bssid = wh->i_addr1;
1974171ac09aSdamien #ifndef IEEE80211_STA_ONLY
197591b2158bSmillert 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1976171ac09aSdamien 				rc = IEEE80211_ADDR_EQ(*bssid,
1977171ac09aSdamien 				    ic->ic_bss->ni_bssid);
1978171ac09aSdamien #endif
197991b2158bSmillert 			break;
198091b2158bSmillert 		case IEEE80211_FC1_DIR_FROMDS:
198191b2158bSmillert 		case IEEE80211_FC1_DIR_DSTODS:
198291b2158bSmillert 			*bssid = wh->i_addr2;
1983171ac09aSdamien #ifndef IEEE80211_STA_ONLY
198491b2158bSmillert 			rc = (ic->ic_opmode == IEEE80211_M_HOSTAP);
1985171ac09aSdamien #endif
198691b2158bSmillert 			break;
198791b2158bSmillert 		}
198891b2158bSmillert 		break;
198991b2158bSmillert 	}
19900fd4e251Sreyk 	return monitor || rc;
199191b2158bSmillert }
199291b2158bSmillert 
19930fd4e251Sreyk /*
19940fd4e251Sreyk  * Drivers call this, so increase the reference count before returning
19950fd4e251Sreyk  * the node.
19960fd4e251Sreyk  */
199791b2158bSmillert struct ieee80211_node *
1998f22d9adcSdamien ieee80211_find_rxnode(struct ieee80211com *ic,
1999f22d9adcSdamien     const struct ieee80211_frame *wh)
200091b2158bSmillert {
20013da4035cSdamien 	static const u_int8_t zero[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
200291b2158bSmillert 	struct ieee80211_node *ni;
2003f22d9adcSdamien 	const u_int8_t *bssid;
20045d155c7eSdamien 	int s;
200591b2158bSmillert 
200691b2158bSmillert 	if (!ieee80211_needs_rxnode(ic, wh, &bssid))
200791b2158bSmillert 		return ieee80211_ref_node(ic->ic_bss);
200891b2158bSmillert 
20095d155c7eSdamien 	s = splnet();
20103ce67372Sreyk 	ni = ieee80211_find_node(ic, wh->i_addr2);
20115d155c7eSdamien 	splx(s);
201291b2158bSmillert 
20130fd4e251Sreyk 	if (ni != NULL)
20140fd4e251Sreyk 		return ieee80211_ref_node(ni);
2015171ac09aSdamien #ifndef IEEE80211_STA_ONLY
20160fd4e251Sreyk 	if (ic->ic_opmode == IEEE80211_M_HOSTAP)
20170fd4e251Sreyk 		return ieee80211_ref_node(ic->ic_bss);
2018171ac09aSdamien #endif
201991b2158bSmillert 	/* XXX see remarks in ieee80211_find_txnode */
202091b2158bSmillert 	/* XXX no rate negotiation; just dup */
20210fd4e251Sreyk 	if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) == NULL)
20220fd4e251Sreyk 		return ieee80211_ref_node(ic->ic_bss);
20230fd4e251Sreyk 
20240fd4e251Sreyk 	IEEE80211_ADDR_COPY(ni->ni_bssid, (bssid != NULL) ? bssid : zero);
20250fd4e251Sreyk 
202691b2158bSmillert 	ni->ni_rates = ic->ic_bss->ni_rates;
2027f1d7120cSstsp 	ni->ni_txrate = 0;
202891b2158bSmillert 	if (ic->ic_newassoc)
202991b2158bSmillert 		(*ic->ic_newassoc)(ic, ni, 1);
20300fd4e251Sreyk 
2031932b9027Sdamien 	DPRINTF(("faked-up node %p for %s\n", ni,
2032f22d9adcSdamien 	    ether_sprintf((u_int8_t *)wh->i_addr2)));
20330fd4e251Sreyk 
20340fd4e251Sreyk 	return ieee80211_ref_node(ni);
203591b2158bSmillert }
203691b2158bSmillert 
2037633cd82cSstsp void
2038de9c1173Sstsp ieee80211_node_tx_ba_clear(struct ieee80211_node *ni, int tid)
2039de9c1173Sstsp {
2040de9c1173Sstsp 	struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
2041de9c1173Sstsp 
2042de9c1173Sstsp 	if (ba->ba_state != IEEE80211_BA_INIT) {
2043de9c1173Sstsp 		if (timeout_pending(&ba->ba_to))
2044de9c1173Sstsp 			timeout_del(&ba->ba_to);
2045de9c1173Sstsp 		ba->ba_state = IEEE80211_BA_INIT;
2046de9c1173Sstsp 	}
2047de9c1173Sstsp }
2048de9c1173Sstsp 
2049de9c1173Sstsp void
2050633cd82cSstsp ieee80211_ba_del(struct ieee80211_node *ni)
2051633cd82cSstsp {
2052633cd82cSstsp 	int tid;
2053633cd82cSstsp 
2054633cd82cSstsp 	for (tid = 0; tid < nitems(ni->ni_rx_ba); tid++) {
2055633cd82cSstsp 		struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
205620fce2ddSstsp 		if (ba->ba_state != IEEE80211_BA_INIT) {
2057633cd82cSstsp 			if (timeout_pending(&ba->ba_to))
2058633cd82cSstsp 				timeout_del(&ba->ba_to);
205920fce2ddSstsp 			if (timeout_pending(&ba->ba_gap_to))
206020fce2ddSstsp 				timeout_del(&ba->ba_gap_to);
2061633cd82cSstsp 			ba->ba_state = IEEE80211_BA_INIT;
2062633cd82cSstsp 		}
2063633cd82cSstsp 	}
2064633cd82cSstsp 
2065de9c1173Sstsp 	for (tid = 0; tid < nitems(ni->ni_tx_ba); tid++)
2066de9c1173Sstsp 		ieee80211_node_tx_ba_clear(ni, tid);
2067aefc44daSstsp 
2068aefc44daSstsp 	timeout_del(&ni->ni_addba_req_to[EDCA_AC_BE]);
2069aefc44daSstsp 	timeout_del(&ni->ni_addba_req_to[EDCA_AC_BK]);
2070aefc44daSstsp 	timeout_del(&ni->ni_addba_req_to[EDCA_AC_VI]);
2071aefc44daSstsp 	timeout_del(&ni->ni_addba_req_to[EDCA_AC_VO]);
2072633cd82cSstsp }
2073633cd82cSstsp 
2074250085e6Sdamien void
20750fd4e251Sreyk ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
207691b2158bSmillert {
2077fe6a7506Sjsg 	if (ni == ic->ic_bss)
2078fe6a7506Sjsg 		panic("freeing bss node");
207991b2158bSmillert 
2080937967bbSstsp 	splassert(IPL_NET);
2081937967bbSstsp 
2082932b9027Sdamien 	DPRINTF(("%s\n", ether_sprintf(ni->ni_macaddr)));
2083c720ca3cSdamien #ifndef IEEE80211_STA_ONLY
208445eec175Sdamien 	timeout_del(&ni->ni_eapol_to);
208545eec175Sdamien 	timeout_del(&ni->ni_sa_query_to);
208691b2158bSmillert 	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
208796c2d967Sdamien #endif
2088633cd82cSstsp 	ieee80211_ba_del(ni);
20898529d8f0Sdlg 	RBT_REMOVE(ieee80211_tree, &ic->ic_tree, ni);
20900fd4e251Sreyk 	ic->ic_nnodes--;
2091c720ca3cSdamien #ifndef IEEE80211_STA_ONLY
2092351e1934Sdlg 	if (mq_purge(&ni->ni_savedq) > 0) {
2093158c4605Sdamien 		if (ic->ic_set_tim != NULL)
20940fd4e251Sreyk 			(*ic->ic_set_tim)(ic, ni->ni_associd, 0);
209591b2158bSmillert 	}
2096c720ca3cSdamien #endif
209791b2158bSmillert 	(*ic->ic_node_free)(ic, ni);
20980fd4e251Sreyk 	/* TBD indicate to drivers that a new node can be allocated */
209991b2158bSmillert }
210091b2158bSmillert 
210191b2158bSmillert void
21020fd4e251Sreyk ieee80211_release_node(struct ieee80211com *ic, struct ieee80211_node *ni)
210391b2158bSmillert {
21045d155c7eSdamien 	int s;
2105de9c1173Sstsp 	void (*ni_unref_cb)(struct ieee80211com *, struct ieee80211_node *);
21065d155c7eSdamien 
21076eea240dSstsp 	DPRINTF(("%s refcnt %u\n", ether_sprintf(ni->ni_macaddr),
2108932b9027Sdamien 	    ni->ni_refcnt));
21099c582f02Sstsp 	s = splnet();
211006e069b5Sstsp 	if (ieee80211_node_decref(ni) == 0) {
211106e069b5Sstsp 		if (ni->ni_unref_cb) {
2112de9c1173Sstsp 			/* The callback may set ni->ni_unref_cb again. */
2113de9c1173Sstsp 			ni_unref_cb = ni->ni_unref_cb;
211406e069b5Sstsp 			ni->ni_unref_cb = NULL;
211506e069b5Sstsp  			/* Freed by callback if necessary: */
2116de9c1173Sstsp 			(*ni_unref_cb)(ic, ni);
211706e069b5Sstsp 		}
211806e069b5Sstsp 	    	if (ni->ni_state == IEEE80211_STA_COLLECT)
21190fd4e251Sreyk 			ieee80211_free_node(ic, ni);
212091b2158bSmillert 	}
21219c582f02Sstsp 	splx(s);
212291b2158bSmillert }
212391b2158bSmillert 
212491b2158bSmillert void
2125d466420eSstsp ieee80211_free_allnodes(struct ieee80211com *ic, int clear_ic_bss)
212691b2158bSmillert {
212791b2158bSmillert 	struct ieee80211_node *ni;
21285d155c7eSdamien 	int s;
212991b2158bSmillert 
2130932b9027Sdamien 	DPRINTF(("freeing all nodes\n"));
21315d155c7eSdamien 	s = splnet();
21328529d8f0Sdlg 	while ((ni = RBT_MIN(ieee80211_tree, &ic->ic_tree)) != NULL)
21330fd4e251Sreyk 		ieee80211_free_node(ic, ni);
21345d155c7eSdamien 	splx(s);
21350fd4e251Sreyk 
2136d466420eSstsp 	if (clear_ic_bss && ic->ic_bss != NULL)
2137539559bcSstsp 		ieee80211_node_cleanup(ic, ic->ic_bss);
213891b2158bSmillert }
213991b2158bSmillert 
214063375369Ssthen void
214163375369Ssthen ieee80211_clean_cached(struct ieee80211com *ic)
214263375369Ssthen {
214363375369Ssthen 	struct ieee80211_node *ni, *next_ni;
214463375369Ssthen 	int s;
214563375369Ssthen 
214663375369Ssthen 	s = splnet();
21478529d8f0Sdlg 	for (ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
214863375369Ssthen 	    ni != NULL; ni = next_ni) {
21498529d8f0Sdlg 		next_ni = RBT_NEXT(ieee80211_tree, ni);
215063375369Ssthen 		if (ni->ni_state == IEEE80211_STA_CACHE)
215163375369Ssthen 			ieee80211_free_node(ic, ni);
215263375369Ssthen 	}
215363375369Ssthen 	splx(s);
215463375369Ssthen }
215591b2158bSmillert /*
21565d155c7eSdamien  * Timeout inactive nodes.
21579c2641a5Sstsp  *
21589c2641a5Sstsp  * If called because of a cache timeout, which happens only in hostap and ibss
215931feabc1Sstsp  * modes, clean all inactive cached or authenticated nodes but don't de-auth
2160cfaefb40Sstsp  * any associated nodes. Also update HT protection settings.
21619c2641a5Sstsp  *
21629c2641a5Sstsp  * Else, this function is called because a new node must be allocated but the
21639c2641a5Sstsp  * node cache is full. In this case, return as soon as a free slot was made
21649c2641a5Sstsp  * available. If acting as hostap, clean cached nodes regardless of their
216534c991eaSstsp  * recent activity and also allow de-authing of authenticated nodes older
216634c991eaSstsp  * than one cache wait interval, and de-authing of inactive associated nodes.
216791b2158bSmillert  */
216891b2158bSmillert void
21699c2641a5Sstsp ieee80211_clean_nodes(struct ieee80211com *ic, int cache_timeout)
217091b2158bSmillert {
21710fd4e251Sreyk 	struct ieee80211_node *ni, *next_ni;
217291b2158bSmillert 	u_int gen = ic->ic_scangen++;		/* NB: ok 'cuz single-threaded*/
21735d155c7eSdamien 	int s;
2174937967bbSstsp #ifndef IEEE80211_STA_ONLY
2175cfaefb40Sstsp 	int nnodes = 0, nonht = 0, nonhtassoc = 0;
2176937967bbSstsp 	struct ifnet *ifp = &ic->ic_if;
2177cfaefb40Sstsp 	enum ieee80211_htprot htprot = IEEE80211_HTPROT_NONE;
2178cfaefb40Sstsp 	enum ieee80211_protmode protmode = IEEE80211_PROT_NONE;
2179937967bbSstsp #endif
218091b2158bSmillert 
21815d155c7eSdamien 	s = splnet();
21828529d8f0Sdlg 	for (ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
2183fb104bbdSreyk 	    ni != NULL; ni = next_ni) {
21848529d8f0Sdlg 		next_ni = RBT_NEXT(ieee80211_tree, ni);
21859c2641a5Sstsp 		if (!cache_timeout && ic->ic_nnodes < ic->ic_max_nnodes)
21860fd4e251Sreyk 			break;
218791b2158bSmillert 		if (ni->ni_scangen == gen)	/* previously handled */
218891b2158bSmillert 			continue;
2189937967bbSstsp #ifndef IEEE80211_STA_ONLY
2190937967bbSstsp 		nnodes++;
2191cfaefb40Sstsp 		if ((ic->ic_flags & IEEE80211_F_HTON) && cache_timeout) {
21921c062f30Sstsp 			/*
21931c062f30Sstsp 			 * Check if node supports 802.11n.
21941c062f30Sstsp 			 * Only require HT capabilities IE for this check.
21951c062f30Sstsp 			 * Nodes might never reveal their supported MCS to us
21961c062f30Sstsp 			 * unless they go through a full association sequence.
21971c062f30Sstsp 			 * ieee80211_node_supports_ht() could misclassify them.
21981c062f30Sstsp 			 */
21991c062f30Sstsp 			if ((ni->ni_flags & IEEE80211_NODE_HTCAP) == 0) {
2200cfaefb40Sstsp 				nonht++;
2201cfaefb40Sstsp 				if (ni->ni_state == IEEE80211_STA_ASSOC)
2202cfaefb40Sstsp 					nonhtassoc++;
2203cfaefb40Sstsp 			}
2204cfaefb40Sstsp 		}
2205937967bbSstsp #endif
220691b2158bSmillert 		ni->ni_scangen = gen;
22070fd4e251Sreyk 		if (ni->ni_refcnt > 0)
22080fd4e251Sreyk 			continue;
22099c2641a5Sstsp #ifndef IEEE80211_STA_ONLY
22109c2641a5Sstsp 		if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
22119c2641a5Sstsp 		    ic->ic_opmode == IEEE80211_M_IBSS) &&
22129c2641a5Sstsp 		    ic->ic_state == IEEE80211_S_RUN) {
22139c2641a5Sstsp 			if (cache_timeout) {
22149c2641a5Sstsp 				if (ni->ni_state != IEEE80211_STA_COLLECT &&
221531feabc1Sstsp 				    (ni->ni_state == IEEE80211_STA_ASSOC ||
22169c2641a5Sstsp 				    ni->ni_inact < IEEE80211_INACT_MAX))
22179c2641a5Sstsp 					continue;
22189c2641a5Sstsp 			} else {
221934c991eaSstsp 				if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
222034c991eaSstsp 				    ((ni->ni_state == IEEE80211_STA_ASSOC &&
222134c991eaSstsp 				    ni->ni_inact < IEEE80211_INACT_MAX) ||
222234c991eaSstsp 				    (ni->ni_state == IEEE80211_STA_AUTH &&
222334c991eaSstsp 				     ni->ni_inact == 0)))
222434c991eaSstsp 				    	continue;
222534c991eaSstsp 
222634c991eaSstsp 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
222734c991eaSstsp 				    ni->ni_state != IEEE80211_STA_COLLECT &&
22289c2641a5Sstsp 				    ni->ni_state != IEEE80211_STA_CACHE &&
22299c2641a5Sstsp 				    ni->ni_inact < IEEE80211_INACT_MAX)
22309c2641a5Sstsp 					continue;
22319c2641a5Sstsp 			}
22329c2641a5Sstsp 		}
22332f1a2544Sstsp 		if (ifp->if_flags & IFF_DEBUG)
22342f1a2544Sstsp 			printf("%s: station %s purged from node cache\n",
22352f1a2544Sstsp 			    ifp->if_xname, ether_sprintf(ni->ni_macaddr));
22369c2641a5Sstsp #endif
223791b2158bSmillert 		/*
22389c2641a5Sstsp 		 * If we're hostap and the node is authenticated, send
22399c2641a5Sstsp 		 * a deauthentication frame. The node will be freed when
22409c2641a5Sstsp 		 * the driver calls ieee80211_release_node().
224191b2158bSmillert 		 */
2242171ac09aSdamien #ifndef IEEE80211_STA_ONLY
2243937967bbSstsp 		nnodes--;
2244cfaefb40Sstsp 		if ((ic->ic_flags & IEEE80211_F_HTON) && cache_timeout) {
22451c062f30Sstsp 			if ((ni->ni_flags & IEEE80211_NODE_HTCAP) == 0) {
2246cfaefb40Sstsp 				nonht--;
2247cfaefb40Sstsp 				if (ni->ni_state == IEEE80211_STA_ASSOC)
2248cfaefb40Sstsp 					nonhtassoc--;
2249cfaefb40Sstsp 			}
2250cfaefb40Sstsp 		}
22519c2641a5Sstsp 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
22529c2641a5Sstsp 		    ni->ni_state >= IEEE80211_STA_AUTH &&
22539c2641a5Sstsp 		    ni->ni_state != IEEE80211_STA_COLLECT) {
225491b2158bSmillert 			IEEE80211_SEND_MGMT(ic, ni,
225591b2158bSmillert 			    IEEE80211_FC0_SUBTYPE_DEAUTH,
225691b2158bSmillert 			    IEEE80211_REASON_AUTH_EXPIRE);
22570fd4e251Sreyk 			ieee80211_node_leave(ic, ni);
22580fd4e251Sreyk 		} else
2259171ac09aSdamien #endif
226091b2158bSmillert 			ieee80211_free_node(ic, ni);
226191b2158bSmillert 		ic->ic_stats.is_node_timeout++;
226291b2158bSmillert 	}
2263937967bbSstsp 
2264937967bbSstsp #ifndef IEEE80211_STA_ONLY
2265cfaefb40Sstsp 	if ((ic->ic_flags & IEEE80211_F_HTON) && cache_timeout) {
22661c062f30Sstsp 		uint16_t htop1 = ic->ic_bss->ni_htop1;
22671c062f30Sstsp 
2268cfaefb40Sstsp 		/* Update HT protection settings. */
2269cfaefb40Sstsp 		if (nonht) {
22701c062f30Sstsp 			protmode = IEEE80211_PROT_CTSONLY;
2271cfaefb40Sstsp 			if (nonhtassoc)
2272cfaefb40Sstsp 				htprot = IEEE80211_HTPROT_NONHT_MIXED;
2273cfaefb40Sstsp 			else
2274cfaefb40Sstsp 				htprot = IEEE80211_HTPROT_NONMEMBER;
2275cfaefb40Sstsp 		}
22761c062f30Sstsp 		if ((htop1 & IEEE80211_HTOP1_PROT_MASK) != htprot) {
22771c062f30Sstsp 			htop1 &= ~IEEE80211_HTOP1_PROT_MASK;
22781c062f30Sstsp 			htop1 |= htprot;
2279193c6c4aSstsp 			ic->ic_bss->ni_htop1 = htop1;
2280cfaefb40Sstsp 			ic->ic_protmode = protmode;
228109268e1fSstsp 			if (ic->ic_updateprot)
228209268e1fSstsp 				ic->ic_updateprot(ic);
2283cfaefb40Sstsp 		}
2284cfaefb40Sstsp 	}
2285cfaefb40Sstsp 
2286937967bbSstsp 	/*
2287937967bbSstsp 	 * During a cache timeout we iterate over all nodes.
2288937967bbSstsp 	 * Check for node leaks by comparing the actual number of cached
2289937967bbSstsp 	 * nodes with the ic_nnodes count, which is maintained while adding
2290937967bbSstsp 	 * and removing nodes from the cache.
2291937967bbSstsp 	 */
2292937967bbSstsp 	if ((ifp->if_flags & IFF_DEBUG) && cache_timeout &&
2293937967bbSstsp 	    nnodes != ic->ic_nnodes)
2294937967bbSstsp 		printf("%s: number of cached nodes is %d, expected %d,"
2295937967bbSstsp 		    "possible nodes leak\n", ifp->if_xname, nnodes,
2296937967bbSstsp 		    ic->ic_nnodes);
2297937967bbSstsp #endif
22985d155c7eSdamien 	splx(s);
229991b2158bSmillert }
230091b2158bSmillert 
230191b2158bSmillert void
23026a173c79Sstsp ieee80211_clean_inactive_nodes(struct ieee80211com *ic, int inact_max)
23036a173c79Sstsp {
23046a173c79Sstsp 	struct ieee80211_node *ni, *next_ni;
23056a173c79Sstsp 	u_int gen = ic->ic_scangen++;	/* NB: ok 'cuz single-threaded*/
23066a173c79Sstsp 	int s;
23076a173c79Sstsp 
23086a173c79Sstsp 	s = splnet();
23096a173c79Sstsp 	for (ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
23106a173c79Sstsp 	    ni != NULL; ni = next_ni) {
23116a173c79Sstsp 		next_ni = RBT_NEXT(ieee80211_tree, ni);
23126a173c79Sstsp 		if (ni->ni_scangen == gen)	/* previously handled */
23136a173c79Sstsp 			continue;
23146a173c79Sstsp 		ni->ni_scangen = gen;
23156a173c79Sstsp 		if (ni->ni_refcnt > 0 || ni->ni_inact < inact_max)
23166a173c79Sstsp 			continue;
23176a173c79Sstsp 		ieee80211_free_node(ic, ni);
23186a173c79Sstsp 		ic->ic_stats.is_node_timeout++;
23196a173c79Sstsp 	}
23206a173c79Sstsp 
23216a173c79Sstsp 	splx(s);
23226a173c79Sstsp }
23236a173c79Sstsp 
23246a173c79Sstsp void
2325591d6357Sreyk ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f,
2326591d6357Sreyk     void *arg)
232791b2158bSmillert {
232891b2158bSmillert 	struct ieee80211_node *ni;
23295d155c7eSdamien 	int s;
233091b2158bSmillert 
23315d155c7eSdamien 	s = splnet();
23328529d8f0Sdlg 	RBT_FOREACH(ni, ieee80211_tree, &ic->ic_tree)
233391b2158bSmillert 		(*f)(arg, ni);
23345d155c7eSdamien 	splx(s);
23350fd4e251Sreyk }
23360fd4e251Sreyk 
2337fe8f5243Sstsp 
2338fe8f5243Sstsp /*
2339fe8f5243Sstsp  * Install received HT caps information in the node's state block.
2340fe8f5243Sstsp  */
2341fe8f5243Sstsp void
2342fe8f5243Sstsp ieee80211_setup_htcaps(struct ieee80211_node *ni, const uint8_t *data,
2343fe8f5243Sstsp     uint8_t len)
2344fe8f5243Sstsp {
2345fe8f5243Sstsp 	uint16_t rxrate;
2346fe8f5243Sstsp 
2347fe8f5243Sstsp 	if (len != 26)
2348fe8f5243Sstsp 		return;
2349fe8f5243Sstsp 
2350fe8f5243Sstsp 	ni->ni_htcaps = (data[0] | (data[1] << 8));
2351fe8f5243Sstsp 	ni->ni_ampdu_param = data[2];
2352fe8f5243Sstsp 
2353fe8f5243Sstsp 	memcpy(ni->ni_rxmcs, &data[3], sizeof(ni->ni_rxmcs));
2354fe8f5243Sstsp 	/* clear reserved bits */
2355fe8f5243Sstsp 	clrbit(ni->ni_rxmcs, 77);
2356fe8f5243Sstsp 	clrbit(ni->ni_rxmcs, 78);
2357fe8f5243Sstsp 	clrbit(ni->ni_rxmcs, 79);
2358fe8f5243Sstsp 
2359fe8f5243Sstsp 	/* Max MCS Rx rate in 1Mb/s units (0 means "not specified"). */
2360fe8f5243Sstsp 	rxrate = ((data[13] | (data[14]) << 8) & IEEE80211_MCS_RX_RATE_HIGH);
2361fe8f5243Sstsp 	if (rxrate < 1024)
2362fe8f5243Sstsp 		ni->ni_max_rxrate = rxrate;
2363fe8f5243Sstsp 
2364fe8f5243Sstsp 	ni->ni_tx_mcs_set = data[15];
2365fe8f5243Sstsp 	ni->ni_htxcaps = (data[19] | (data[20] << 8));
2366fe8f5243Sstsp 	ni->ni_txbfcaps = (data[21] | (data[22] << 8) | (data[23] << 16) |
2367fe8f5243Sstsp 		(data[24] << 24));
2368fe8f5243Sstsp 	ni->ni_aselcaps = data[25];
23691c062f30Sstsp 
23701c062f30Sstsp 	ni->ni_flags |= IEEE80211_NODE_HTCAP;
2371fe8f5243Sstsp }
2372fe8f5243Sstsp 
23732040b0e1Sstsp #ifndef IEEE80211_STA_ONLY
23742040b0e1Sstsp /*
23752040b0e1Sstsp  * Handle nodes switching from 11n into legacy modes.
23762040b0e1Sstsp  */
23772040b0e1Sstsp void
23782040b0e1Sstsp ieee80211_clear_htcaps(struct ieee80211_node *ni)
23792040b0e1Sstsp {
23802040b0e1Sstsp 	ni->ni_htcaps = 0;
23812040b0e1Sstsp 	ni->ni_ampdu_param = 0;
23822040b0e1Sstsp 	memset(ni->ni_rxmcs, 0, sizeof(ni->ni_rxmcs));
23832040b0e1Sstsp 	ni->ni_max_rxrate = 0;
23842040b0e1Sstsp 	ni->ni_tx_mcs_set = 0;
23852040b0e1Sstsp 	ni->ni_htxcaps = 0;
23862040b0e1Sstsp 	ni->ni_txbfcaps = 0;
23872040b0e1Sstsp 	ni->ni_aselcaps = 0;
23882040b0e1Sstsp 
2389b812c027Sstsp 	ni->ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_HT_SGI20 |
23901c062f30Sstsp 	    IEEE80211_NODE_HT_SGI40 | IEEE80211_NODE_HTCAP);
23912040b0e1Sstsp 
23922040b0e1Sstsp }
23932040b0e1Sstsp #endif
23942040b0e1Sstsp 
2395c484bc82Sstsp int
2396c484bc82Sstsp ieee80211_40mhz_valid_secondary_above(uint8_t primary_chan)
2397c484bc82Sstsp {
2398c484bc82Sstsp 	static const uint8_t valid_secondary_chan[] = {
2399243d6ddeSstsp 		5, 6, 7, 8, 9, 10, 11, 12, 13,
2400c484bc82Sstsp 		40, 48, 56, 64, 104, 112, 120, 128, 136, 144, 153, 161
2401c484bc82Sstsp 	};
2402c484bc82Sstsp 	uint8_t secondary_chan;
2403c484bc82Sstsp 	int i;
2404c484bc82Sstsp 
2405243d6ddeSstsp 	if ((primary_chan >= 1 && primary_chan <= 9) ||
2406243d6ddeSstsp 	    (primary_chan >= 36 && primary_chan <= 157))
2407c484bc82Sstsp 		secondary_chan = primary_chan + 4;
2408c484bc82Sstsp 	else
2409c484bc82Sstsp 		return 0;
2410c484bc82Sstsp 
2411c484bc82Sstsp 	for (i = 0; i < nitems(valid_secondary_chan); i++) {
2412c484bc82Sstsp 		if (secondary_chan == valid_secondary_chan[i])
2413c484bc82Sstsp 			return 1;
2414c484bc82Sstsp 	}
2415c484bc82Sstsp 
2416c484bc82Sstsp 	return 0;
2417c484bc82Sstsp }
2418c484bc82Sstsp 
2419c484bc82Sstsp int
2420c484bc82Sstsp ieee80211_40mhz_valid_secondary_below(uint8_t primary_chan)
2421c484bc82Sstsp {
2422c484bc82Sstsp 	static const uint8_t valid_secondary_chan[] = {
2423243d6ddeSstsp 		1, 2, 3, 4, 5, 6, 7, 8, 9,
2424c484bc82Sstsp 		36, 44, 52, 60, 100, 108, 116, 124, 132, 140, 149, 157
2425c484bc82Sstsp 	};
2426c484bc82Sstsp 	int8_t secondary_chan;
2427c484bc82Sstsp 	int i;
2428c484bc82Sstsp 
2429243d6ddeSstsp 	if ((primary_chan >= 5 && primary_chan <= 13) ||
2430243d6ddeSstsp 	    (primary_chan >= 40 && primary_chan <= 161))
2431c484bc82Sstsp 		secondary_chan = primary_chan - 4;
2432c484bc82Sstsp 	else
2433c484bc82Sstsp 		return 0;
2434c484bc82Sstsp 
2435c484bc82Sstsp 	for (i = 0; i < nitems(valid_secondary_chan); i++) {
2436c484bc82Sstsp 		if (secondary_chan == valid_secondary_chan[i])
2437c484bc82Sstsp 			return 1;
2438c484bc82Sstsp 	}
2439c484bc82Sstsp 
2440c484bc82Sstsp 	return 0;
2441c484bc82Sstsp }
2442c484bc82Sstsp 
2443c484bc82Sstsp /*
2444c484bc82Sstsp  * Only accept 40 MHz channel configurations that conform to
2445c484bc82Sstsp  * regulatory operating classes as defined by the 802.11ac spec.
2446c484bc82Sstsp  * Passing other configurations down to firmware can result in
2447*9593dc34Smglocker  * regulatory assertions being triggered, such as fatal firmware
2448c484bc82Sstsp  * error 14FD in iwm(4).
2449c484bc82Sstsp  *
2450c484bc82Sstsp  * See 802.11ac 2013, page 380, Tables E-1 to E-5.
2451c484bc82Sstsp  */
2452c484bc82Sstsp int
2453c484bc82Sstsp ieee80211_40mhz_center_freq_valid(uint8_t primary_chan, uint8_t htop0)
2454c484bc82Sstsp {
2455c484bc82Sstsp 	uint8_t sco;
2456c484bc82Sstsp 
2457c484bc82Sstsp 	sco = ((htop0 & IEEE80211_HTOP0_SCO_MASK) >> IEEE80211_HTOP0_SCO_SHIFT);
2458c484bc82Sstsp 	switch (sco) {
2459c484bc82Sstsp 	case IEEE80211_HTOP0_SCO_SCN:
2460c484bc82Sstsp 		return 1;
2461c484bc82Sstsp 	case IEEE80211_HTOP0_SCO_SCA:
2462c484bc82Sstsp 		return ieee80211_40mhz_valid_secondary_above(primary_chan);
2463c484bc82Sstsp 	case IEEE80211_HTOP0_SCO_SCB:
2464c484bc82Sstsp 		return ieee80211_40mhz_valid_secondary_below(primary_chan);
2465c484bc82Sstsp 	}
2466c484bc82Sstsp 
2467c484bc82Sstsp 	return 0;
2468c484bc82Sstsp }
2469c484bc82Sstsp 
2470fe8f5243Sstsp /*
2471fe8f5243Sstsp  * Install received HT op information in the node's state block.
2472fe8f5243Sstsp  */
24737a831903Sstsp int
2474fe8f5243Sstsp ieee80211_setup_htop(struct ieee80211_node *ni, const uint8_t *data,
2475f9214ef6Sstsp     uint8_t len, int isprobe)
2476fe8f5243Sstsp {
2477fe8f5243Sstsp 	if (len != 22)
24787a831903Sstsp 		return 0;
2479fe8f5243Sstsp 
2480c484bc82Sstsp 	ni->ni_primary_chan = data[0]; /* corresponds to ni_chan */
2481fe8f5243Sstsp 	ni->ni_htop0 = data[1];
2482c484bc82Sstsp 	if (!ieee80211_40mhz_center_freq_valid(data[0], data[1]))
2483c484bc82Sstsp 		ni->ni_htop0 &= ~IEEE80211_HTOP0_SCO_MASK;
2484fe8f5243Sstsp 	ni->ni_htop1 = (data[2] | (data[3] << 8));
2485fe8f5243Sstsp 	ni->ni_htop2 = (data[3] | (data[4] << 8));
2486fe8f5243Sstsp 
248771004272Sstsp 	/*
248871004272Sstsp 	 * According to 802.11-2012 Table 8-130 the Basic MCS set is
248971004272Sstsp 	 * only "present in Beacon, Probe Response, Mesh Peering Open
249071004272Sstsp 	 * and Mesh Peering Confirm frames. Otherwise reserved."
249171004272Sstsp 	 */
2492f9214ef6Sstsp 	if (isprobe)
2493fe8f5243Sstsp 		memcpy(ni->ni_basic_mcs, &data[6], sizeof(ni->ni_basic_mcs));
24947a831903Sstsp 
24957a831903Sstsp 	return 1;
2496fe8f5243Sstsp }
2497fe8f5243Sstsp 
24981bb78573Sdamien /*
249950e8fe1cSstsp  * Install received VHT caps information in the node's state block.
250050e8fe1cSstsp  */
250150e8fe1cSstsp void
250250e8fe1cSstsp ieee80211_setup_vhtcaps(struct ieee80211_node *ni, const uint8_t *data,
250350e8fe1cSstsp     uint8_t len)
250450e8fe1cSstsp {
250550e8fe1cSstsp 	if (len != 12)
250650e8fe1cSstsp 		return;
250750e8fe1cSstsp 
250850e8fe1cSstsp 	ni->ni_vhtcaps = (data[0] | (data[1] << 8) | data[2] << 16 |
250950e8fe1cSstsp 	    data[3] << 24);
251050e8fe1cSstsp 	ni->ni_vht_rxmcs = (data[4] | (data[5] << 8));
251150e8fe1cSstsp 	ni->ni_vht_rx_max_lgi_mbit_s = ((data[6] | (data[7] << 8)) &
251250e8fe1cSstsp 	    IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
251350e8fe1cSstsp 	ni->ni_vht_txmcs = (data[8] | (data[9] << 8));
251450e8fe1cSstsp 	ni->ni_vht_tx_max_lgi_mbit_s = ((data[10] | (data[11] << 8)) &
251550e8fe1cSstsp 	    IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
251650e8fe1cSstsp 
251750e8fe1cSstsp 	ni->ni_flags |= IEEE80211_NODE_VHTCAP;
251850e8fe1cSstsp }
251950e8fe1cSstsp 
252050e8fe1cSstsp /*
2521c484bc82Sstsp  * Only accept 80 MHz channel configurations that conform to
2522c484bc82Sstsp  * regulatory operating classes as defined by the 802.11ac spec.
2523c484bc82Sstsp  * Passing other configurations down to firmware can result in
2524*9593dc34Smglocker  * regulatory assertions being triggered, such as fatal firmware
2525c484bc82Sstsp  * error 14FD in iwm(4).
2526c484bc82Sstsp  *
2527c484bc82Sstsp  * See 802.11ac 2013, page 380, Tables E-1 to E-5.
2528c484bc82Sstsp  */
2529c484bc82Sstsp int
2530c484bc82Sstsp ieee80211_80mhz_center_freq_valid(const uint8_t chanidx)
2531c484bc82Sstsp {
2532c484bc82Sstsp 	static const uint8_t valid_center_chanidx[] = {
2533c484bc82Sstsp 		42, 50, 58, 106, 112, 114, 138, 155
2534c484bc82Sstsp 	};
2535c484bc82Sstsp 	int i;
2536c484bc82Sstsp 
2537c484bc82Sstsp 	for (i = 0; i < nitems(valid_center_chanidx); i++) {
2538c484bc82Sstsp 		if (chanidx == valid_center_chanidx[i])
2539c484bc82Sstsp 			return 1;
2540c484bc82Sstsp 	}
2541c484bc82Sstsp 
2542c484bc82Sstsp 	return 0;
2543c484bc82Sstsp }
2544c484bc82Sstsp 
2545c484bc82Sstsp /*
254650e8fe1cSstsp  * Install received VHT op information in the node's state block.
254750e8fe1cSstsp  */
254850e8fe1cSstsp int
254950e8fe1cSstsp ieee80211_setup_vhtop(struct ieee80211_node *ni, const uint8_t *data,
255050e8fe1cSstsp     uint8_t len, int isprobe)
255150e8fe1cSstsp {
2552c484bc82Sstsp 	uint8_t sco;
2553c484bc82Sstsp 	int have_40mhz;
255450e8fe1cSstsp 
255550e8fe1cSstsp 	if (len != 5)
255650e8fe1cSstsp 		return 0;
255750e8fe1cSstsp 
255850e8fe1cSstsp 	if (data[0] != IEEE80211_VHTOP0_CHAN_WIDTH_HT &&
255950e8fe1cSstsp 	    data[0] != IEEE80211_VHTOP0_CHAN_WIDTH_80 &&
256050e8fe1cSstsp 	    data[0] != IEEE80211_VHTOP0_CHAN_WIDTH_160 &&
256150e8fe1cSstsp 	    data[0] != IEEE80211_VHTOP0_CHAN_WIDTH_8080)
256250e8fe1cSstsp 		return 0;
256350e8fe1cSstsp 
2564c484bc82Sstsp 	sco = ((ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) >>
2565c484bc82Sstsp 	    IEEE80211_HTOP0_SCO_SHIFT);
2566c484bc82Sstsp 	have_40mhz = (sco == IEEE80211_HTOP0_SCO_SCA ||
2567c484bc82Sstsp 	    sco == IEEE80211_HTOP0_SCO_SCB);
2568c484bc82Sstsp 
2569c484bc82Sstsp 	if (have_40mhz && ieee80211_80mhz_center_freq_valid(data[1])) {
257050e8fe1cSstsp 		ni->ni_vht_chan_width = data[0];
257150e8fe1cSstsp 		ni->ni_vht_chan_center_freq_idx0 = data[1];
2572c484bc82Sstsp 
2573c484bc82Sstsp 		/* Only used in non-consecutive 80-80 160MHz configs. */
2574c484bc82Sstsp 		if (data[2] && ieee80211_80mhz_center_freq_valid(data[2]))
257550e8fe1cSstsp 			ni->ni_vht_chan_center_freq_idx1 = data[2];
2576c484bc82Sstsp 		else
2577c484bc82Sstsp 			ni->ni_vht_chan_center_freq_idx1 = 0;
2578c484bc82Sstsp 	} else {
2579c484bc82Sstsp 		ni->ni_vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_HT;
2580c484bc82Sstsp 		ni->ni_vht_chan_center_freq_idx0 = 0;
2581c484bc82Sstsp 		ni->ni_vht_chan_center_freq_idx1 = 0;
2582c484bc82Sstsp 	}
2583c484bc82Sstsp 
258450e8fe1cSstsp 	ni->ni_vht_basic_mcs = (data[3] | data[4] << 8);
258550e8fe1cSstsp 	return 1;
258650e8fe1cSstsp }
258750e8fe1cSstsp 
258850e8fe1cSstsp #ifndef IEEE80211_STA_ONLY
258950e8fe1cSstsp /*
259050e8fe1cSstsp  * Handle nodes switching from 11ac into legacy modes.
259150e8fe1cSstsp  */
259250e8fe1cSstsp void
259350e8fe1cSstsp ieee80211_clear_vhtcaps(struct ieee80211_node *ni)
259450e8fe1cSstsp {
259550e8fe1cSstsp 	ni->ni_vhtcaps = 0;
259650e8fe1cSstsp 	ni->ni_vht_rxmcs = 0;
259750e8fe1cSstsp 	ni->ni_vht_rx_max_lgi_mbit_s = 0;
259850e8fe1cSstsp 	ni->ni_vht_txmcs = 0;
259950e8fe1cSstsp 	ni->ni_vht_tx_max_lgi_mbit_s = 0;
260050e8fe1cSstsp 
260150e8fe1cSstsp 	ni->ni_flags &= ~(IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 |
260250e8fe1cSstsp 	    IEEE80211_NODE_VHT_SGI160 | IEEE80211_NODE_VHTCAP);
260350e8fe1cSstsp 
260450e8fe1cSstsp }
260550e8fe1cSstsp #endif
260650e8fe1cSstsp 
260750e8fe1cSstsp /*
26086de17962Sdamien  * Install received rate set information in the node's state block.
26096de17962Sdamien  */
26106de17962Sdamien int
26116de17962Sdamien ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
26126de17962Sdamien     const u_int8_t *rates, const u_int8_t *xrates, int flags)
26136de17962Sdamien {
26146de17962Sdamien 	struct ieee80211_rateset *rs = &ni->ni_rates;
26156de17962Sdamien 
26166de17962Sdamien 	memset(rs, 0, sizeof(*rs));
26176de17962Sdamien 	rs->rs_nrates = rates[1];
26186de17962Sdamien 	memcpy(rs->rs_rates, rates + 2, rs->rs_nrates);
26196de17962Sdamien 	if (xrates != NULL) {
26206de17962Sdamien 		u_int8_t nxrates;
26216de17962Sdamien 		/*
26226de17962Sdamien 		 * Tack on 11g extended supported rate element.
26236de17962Sdamien 		 */
26246de17962Sdamien 		nxrates = xrates[1];
26256de17962Sdamien 		if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
26266de17962Sdamien 			nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates;
2627932b9027Sdamien 			DPRINTF(("extended rate set too large; "
26286de17962Sdamien 			    "only using %u of %u rates\n",
2629932b9027Sdamien 			    nxrates, xrates[1]));
26306de17962Sdamien 			ic->ic_stats.is_rx_rstoobig++;
26316de17962Sdamien 		}
26326de17962Sdamien 		memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates);
26336de17962Sdamien 		rs->rs_nrates += nxrates;
26346de17962Sdamien 	}
26356de17962Sdamien 	return ieee80211_fix_rate(ic, ni, flags);
26366de17962Sdamien }
26376de17962Sdamien 
2638aefc44daSstsp void
2639aefc44daSstsp ieee80211_node_trigger_addba_req(struct ieee80211_node *ni, int tid)
2640aefc44daSstsp {
2641aefc44daSstsp 	if (ni->ni_tx_ba[tid].ba_state == IEEE80211_BA_INIT &&
2642aefc44daSstsp 	    !timeout_pending(&ni->ni_addba_req_to[tid])) {
2643aefc44daSstsp 		timeout_add_sec(&ni->ni_addba_req_to[tid],
2644aefc44daSstsp 		    ni->ni_addba_req_intval[tid]);
2645aefc44daSstsp 	}
2646aefc44daSstsp }
2647aefc44daSstsp 
2648aefc44daSstsp void
2649aefc44daSstsp ieee80211_node_addba_request(struct ieee80211_node *ni, int tid)
2650aefc44daSstsp {
2651aefc44daSstsp 	struct ieee80211com *ic = ni->ni_ic;
2652aefc44daSstsp 	uint16_t ssn = ni->ni_qos_txseqs[tid];
2653aefc44daSstsp 
2654aefc44daSstsp 	ieee80211_addba_request(ic, ni, ssn, tid);
2655aefc44daSstsp }
2656aefc44daSstsp 
2657aefc44daSstsp void
2658aefc44daSstsp ieee80211_node_addba_request_ac_be_to(void *arg)
2659aefc44daSstsp {
2660aefc44daSstsp 	struct ieee80211_node *ni = arg;
2661aefc44daSstsp 	ieee80211_node_addba_request(ni, EDCA_AC_BE);
2662aefc44daSstsp }
2663aefc44daSstsp 
2664aefc44daSstsp void
2665aefc44daSstsp ieee80211_node_addba_request_ac_bk_to(void *arg)
2666aefc44daSstsp {
2667aefc44daSstsp 	struct ieee80211_node *ni = arg;
2668aefc44daSstsp 	ieee80211_node_addba_request(ni, EDCA_AC_BK);
2669aefc44daSstsp }
2670aefc44daSstsp 
2671aefc44daSstsp void
2672aefc44daSstsp ieee80211_node_addba_request_ac_vi_to(void *arg)
2673aefc44daSstsp {
2674aefc44daSstsp 	struct ieee80211_node *ni = arg;
2675aefc44daSstsp 	ieee80211_node_addba_request(ni, EDCA_AC_VI);
2676aefc44daSstsp }
2677aefc44daSstsp 
2678aefc44daSstsp void
2679aefc44daSstsp ieee80211_node_addba_request_ac_vo_to(void *arg)
2680aefc44daSstsp {
2681aefc44daSstsp 	struct ieee80211_node *ni = arg;
2682aefc44daSstsp 	ieee80211_node_addba_request(ni, EDCA_AC_VO);
2683aefc44daSstsp }
2684aefc44daSstsp 
2685171ac09aSdamien #ifndef IEEE80211_STA_ONLY
26866de17962Sdamien /*
26871bb78573Sdamien  * Check if the specified node supports ERP.
26881bb78573Sdamien  */
26891bb78573Sdamien int
2690f22d9adcSdamien ieee80211_iserp_sta(const struct ieee80211_node *ni)
26911bb78573Sdamien {
2692b39feb1dSdamien 	static const u_int8_t rates[] = { 2, 4, 11, 22, 12, 24, 48 };
2693f22d9adcSdamien 	const struct ieee80211_rateset *rs = &ni->ni_rates;
26941bb78573Sdamien 	int i, j;
26951bb78573Sdamien 
26961bb78573Sdamien 	/*
26971bb78573Sdamien 	 * A STA supports ERP operation if it includes all the Clause 19
26981bb78573Sdamien 	 * mandatory rates in its supported rate set.
26991bb78573Sdamien 	 */
270004bf19f2Sjasper 	for (i = 0; i < nitems(rates); i++) {
27011bb78573Sdamien 		for (j = 0; j < rs->rs_nrates; j++) {
27021bb78573Sdamien 			if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == rates[i])
27031bb78573Sdamien 				break;
27041bb78573Sdamien 		}
27051bb78573Sdamien 		if (j == rs->rs_nrates)
27061bb78573Sdamien 			return 0;
27071bb78573Sdamien 	}
27081bb78573Sdamien 	return 1;
27091bb78573Sdamien }
27101bb78573Sdamien 
27111bb78573Sdamien /*
2712f91ff320Sdamien  * This function is called to notify the 802.1X PACP machine that a new
2713f91ff320Sdamien  * 802.1X port is enabled and must be authenticated. For 802.11, a port
2714f91ff320Sdamien  * becomes enabled whenever a STA successfully completes Open System
2715f91ff320Sdamien  * authentication with an AP.
2716f91ff320Sdamien  */
2717f91ff320Sdamien void
2718f91ff320Sdamien ieee80211_needs_auth(struct ieee80211com *ic, struct ieee80211_node *ni)
2719f91ff320Sdamien {
2720f91ff320Sdamien 	/*
2721f91ff320Sdamien 	 * XXX this could be done via the route socket of via a dedicated
2722f91ff320Sdamien 	 * EAP socket or another kernel->userland notification mechanism.
2723f91ff320Sdamien 	 * The notification should include the MAC address (ni_macaddr).
2724f91ff320Sdamien 	 */
2725f91ff320Sdamien }
2726f91ff320Sdamien 
272745eec175Sdamien /*
272845eec175Sdamien  * Handle an HT STA joining an HT network.
272945eec175Sdamien  */
273045eec175Sdamien void
273145eec175Sdamien ieee80211_node_join_ht(struct ieee80211com *ic, struct ieee80211_node *ni)
273245eec175Sdamien {
2733a2ee12ecSstsp 	enum ieee80211_htprot;
2734a2ee12ecSstsp 
2735a2ee12ecSstsp 	/* Update HT protection setting. */
2736a2ee12ecSstsp 	if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {
27371c062f30Sstsp 		uint16_t htop1 = ic->ic_bss->ni_htop1;
27381c062f30Sstsp 		htop1 &= ~IEEE80211_HTOP1_PROT_MASK;
27391c062f30Sstsp 		htop1 |= IEEE80211_HTPROT_NONHT_MIXED;
27401c062f30Sstsp 		ic->ic_bss->ni_htop1 = htop1;
274109268e1fSstsp 		if (ic->ic_updateprot)
274209268e1fSstsp 			ic->ic_updateprot(ic);
2743a2ee12ecSstsp 	}
274445eec175Sdamien }
274545eec175Sdamien 
2746f91ff320Sdamien /*
2747e03e709cSdamien  * Handle a station joining an RSN network.
2748e03e709cSdamien  */
2749e03e709cSdamien void
2750e03e709cSdamien ieee80211_node_join_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
2751e03e709cSdamien {
2752932b9027Sdamien 	DPRINTF(("station %s associated using proto %d akm 0x%x "
2753e03e709cSdamien 	    "cipher 0x%x groupcipher 0x%x\n", ether_sprintf(ni->ni_macaddr),
2754e03e709cSdamien 	    ni->ni_rsnprotos, ni->ni_rsnakms, ni->ni_rsnciphers,
2755e03e709cSdamien 	    ni->ni_rsngroupcipher));
2756e03e709cSdamien 
2757e03e709cSdamien 	ni->ni_rsn_state = RSNA_AUTHENTICATION;
2758e03e709cSdamien 
2759e03e709cSdamien 	ni->ni_key_count = 0;
2760e03e709cSdamien 	ni->ni_port_valid = 0;
276101ad6d9fSdamien 	ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
27622e40dd69Sstsp 	ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK;
2763e03e709cSdamien 	ni->ni_replaycnt = -1;	/* XXX */
2764e03e709cSdamien 	ni->ni_rsn_retries = 0;
2765e03e709cSdamien 	ni->ni_rsncipher = ni->ni_rsnciphers;
2766e03e709cSdamien 
2767e03e709cSdamien 	ni->ni_rsn_state = RSNA_AUTHENTICATION_2;
2768e03e709cSdamien 
2769e03e709cSdamien 	/* generate a new authenticator nonce (ANonce) */
2770780f39a5Sdjm 	arc4random_buf(ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
2771e03e709cSdamien 
2772f91ff320Sdamien 	if (!ieee80211_is_8021x_akm(ni->ni_rsnakms)) {
2773f91ff320Sdamien 		memcpy(ni->ni_pmk, ic->ic_psk, IEEE80211_PMK_LEN);
2774f91ff320Sdamien 		ni->ni_flags |= IEEE80211_NODE_PMK;
2775e03e709cSdamien 		(void)ieee80211_send_4way_msg1(ic, ni);
2776f91ff320Sdamien 	} else if (ni->ni_flags & IEEE80211_NODE_PMK) {
2777f91ff320Sdamien 		/* skip 802.1X auth if a cached PMK was found */
2778f91ff320Sdamien 		(void)ieee80211_send_4way_msg1(ic, ni);
2779f91ff320Sdamien 	} else {
2780f91ff320Sdamien 		/* no cached PMK found, needs full 802.1X auth */
2781f91ff320Sdamien 		ieee80211_needs_auth(ic, ni);
2782f91ff320Sdamien 	}
2783e03e709cSdamien }
2784e03e709cSdamien 
2785ca7fda7eSstsp void
2786ca7fda7eSstsp ieee80211_count_longslotsta(void *arg, struct ieee80211_node *ni)
2787ca7fda7eSstsp {
2788ca7fda7eSstsp 	int *longslotsta = arg;
2789ca7fda7eSstsp 
2790ca7fda7eSstsp 	if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT)
2791ca7fda7eSstsp 		return;
2792ca7fda7eSstsp 
2793ca7fda7eSstsp 	if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME))
2794ca7fda7eSstsp 		(*longslotsta)++;
2795ca7fda7eSstsp }
2796ca7fda7eSstsp 
2797ca7fda7eSstsp void
2798ca7fda7eSstsp ieee80211_count_nonerpsta(void *arg, struct ieee80211_node *ni)
2799ca7fda7eSstsp {
2800ca7fda7eSstsp 	int *nonerpsta = arg;
2801ca7fda7eSstsp 
2802ca7fda7eSstsp 	if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT)
2803ca7fda7eSstsp 		return;
2804ca7fda7eSstsp 
2805ca7fda7eSstsp 	if (!ieee80211_iserp_sta(ni))
2806ca7fda7eSstsp 		(*nonerpsta)++;
2807ca7fda7eSstsp }
2808ca7fda7eSstsp 
2809ca7fda7eSstsp void
2810ca7fda7eSstsp ieee80211_count_pssta(void *arg, struct ieee80211_node *ni)
2811ca7fda7eSstsp {
2812ca7fda7eSstsp 	int *pssta = arg;
2813ca7fda7eSstsp 
2814ca7fda7eSstsp 	if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT)
2815ca7fda7eSstsp 		return;
2816ca7fda7eSstsp 
2817ca7fda7eSstsp 	if (ni->ni_pwrsave == IEEE80211_PS_DOZE)
2818ca7fda7eSstsp 		(*pssta)++;
2819ca7fda7eSstsp }
2820ca7fda7eSstsp 
2821ca7fda7eSstsp void
2822ca7fda7eSstsp ieee80211_count_rekeysta(void *arg, struct ieee80211_node *ni)
2823ca7fda7eSstsp {
2824ca7fda7eSstsp 	int *rekeysta = arg;
2825ca7fda7eSstsp 
2826ca7fda7eSstsp 	if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT)
2827ca7fda7eSstsp 		return;
2828ca7fda7eSstsp 
2829ca7fda7eSstsp 	if (ni->ni_flags & IEEE80211_NODE_REKEY)
2830ca7fda7eSstsp 		(*rekeysta)++;
2831ca7fda7eSstsp }
2832ca7fda7eSstsp 
2833e03e709cSdamien /*
28341bb78573Sdamien  * Handle a station joining an 11g network.
28351bb78573Sdamien  */
2836250085e6Sdamien void
28371bb78573Sdamien ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
28381bb78573Sdamien {
2839ca7fda7eSstsp 	int longslotsta = 0, nonerpsta = 0;
2840ca7fda7eSstsp 
28411bb78573Sdamien 	if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) {
28421bb78573Sdamien 		/*
28431bb78573Sdamien 		 * Joining STA doesn't support short slot time.  We must
28441bb78573Sdamien 		 * disable the use of short slot time for all other associated
28451bb78573Sdamien 		 * STAs and give the driver a chance to reconfigure the
28461bb78573Sdamien 		 * hardware.
28471bb78573Sdamien 		 */
2848ca7fda7eSstsp 		ieee80211_iterate_nodes(ic,
2849ca7fda7eSstsp 		    ieee80211_count_longslotsta, &longslotsta);
2850ca7fda7eSstsp 		if (longslotsta == 1) {
28511bb78573Sdamien 			if (ic->ic_caps & IEEE80211_C_SHSLOT)
28521bb78573Sdamien 				ieee80211_set_shortslottime(ic, 0);
28531bb78573Sdamien 		}
2854932b9027Sdamien 		DPRINTF(("[%s] station needs long slot time, count %d\n",
2855ca7fda7eSstsp 		    ether_sprintf(ni->ni_macaddr), longslotsta));
28561bb78573Sdamien 	}
28571bb78573Sdamien 
28581bb78573Sdamien 	if (!ieee80211_iserp_sta(ni)) {
28591bb78573Sdamien 		/*
28601bb78573Sdamien 		 * Joining STA is non-ERP.
28611bb78573Sdamien 		 */
2862ca7fda7eSstsp 		ieee80211_iterate_nodes(ic,
2863ca7fda7eSstsp 		    ieee80211_count_nonerpsta, &nonerpsta);
2864932b9027Sdamien 		DPRINTF(("[%s] station is non-ERP, %d non-ERP "
28651bb78573Sdamien 		    "stations associated\n", ether_sprintf(ni->ni_macaddr),
2866ca7fda7eSstsp 		    nonerpsta));
28671bb78573Sdamien 		/* must enable the use of protection */
28681bb78573Sdamien 		if (ic->ic_protmode != IEEE80211_PROT_NONE) {
2869932b9027Sdamien 			DPRINTF(("enable use of protection\n"));
28701bb78573Sdamien 			ic->ic_flags |= IEEE80211_F_USEPROT;
28711bb78573Sdamien 		}
28721bb78573Sdamien 
28731bb78573Sdamien 		if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
28741bb78573Sdamien 			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
28751bb78573Sdamien 	} else
28761bb78573Sdamien 		ni->ni_flags |= IEEE80211_NODE_ERP;
28771bb78573Sdamien }
28781bb78573Sdamien 
28790fd4e251Sreyk void
28800fd4e251Sreyk ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
28810fd4e251Sreyk     int resp)
28820fd4e251Sreyk {
288363711141Sstsp 	int newassoc = (ni->ni_state != IEEE80211_STA_ASSOC);
28840fd4e251Sreyk 
28850fd4e251Sreyk 	if (ni->ni_associd == 0) {
28860fd4e251Sreyk 		u_int16_t aid;
28870fd4e251Sreyk 
28880fd4e251Sreyk 		/*
28890fd4e251Sreyk 		 * It would be clever to search the bitmap
28900fd4e251Sreyk 		 * more efficiently, but this will do for now.
28910fd4e251Sreyk 		 */
28920fd4e251Sreyk 		for (aid = 1; aid < ic->ic_max_aid; aid++) {
28930fd4e251Sreyk 			if (!IEEE80211_AID_ISSET(aid,
28940fd4e251Sreyk 			    ic->ic_aid_bitmap))
28950fd4e251Sreyk 				break;
28960fd4e251Sreyk 		}
28970fd4e251Sreyk 		if (aid >= ic->ic_max_aid) {
28980fd4e251Sreyk 			IEEE80211_SEND_MGMT(ic, ni, resp,
28990fd4e251Sreyk 			    IEEE80211_REASON_ASSOC_TOOMANY);
29000fd4e251Sreyk 			ieee80211_node_leave(ic, ni);
29010fd4e251Sreyk 			return;
29020fd4e251Sreyk 		}
29030fd4e251Sreyk 		ni->ni_associd = aid | 0xc000;
29040fd4e251Sreyk 		IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
29050126ded1Sstsp 		if (ic->ic_curmode == IEEE80211_MODE_11G ||
29060126ded1Sstsp 		    (ic->ic_curmode == IEEE80211_MODE_11N &&
29070126ded1Sstsp 		    IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan)))
29081bb78573Sdamien 			ieee80211_node_join_11g(ic, ni);
290963711141Sstsp 	}
29100fd4e251Sreyk 
2911932b9027Sdamien 	DPRINTF(("station %s %s associated at aid %d\n",
2912932b9027Sdamien 	    ether_sprintf(ni->ni_macaddr), newassoc ? "newly" : "already",
29130fd4e251Sreyk 	    ni->ni_associd & ~0xc000));
29140fd4e251Sreyk 
29155252ab4dSstsp 	ieee80211_ht_negotiate(ic, ni);
29165252ab4dSstsp 	if (ic->ic_flags & IEEE80211_F_HTON)
29175252ab4dSstsp 		ieee80211_node_join_ht(ic, ni);
29185252ab4dSstsp 
29190fd4e251Sreyk 	/* give driver a chance to setup state like ni_txrate */
29200fd4e251Sreyk 	if (ic->ic_newassoc)
29210fd4e251Sreyk 		(*ic->ic_newassoc)(ic, ni, newassoc);
29220fd4e251Sreyk 	IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
29230fd4e251Sreyk 	ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC);
2924b64f3d33Sreyk 
2925e03e709cSdamien 	if (!(ic->ic_flags & IEEE80211_F_RSNON)) {
2926e03e709cSdamien 		ni->ni_port_valid = 1;
2927e03e709cSdamien 		ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP;
2928e03e709cSdamien 	} else
2929e03e709cSdamien 		ieee80211_node_join_rsn(ic, ni);
2930e03e709cSdamien 
2931b64f3d33Sreyk #if NBRIDGE > 0
2932b64f3d33Sreyk 	/*
29332d18ef82Scamield 	 * If the parent interface is a bridge port, learn
2934b64f3d33Sreyk 	 * the node's address dynamically on this interface.
2935b64f3d33Sreyk 	 */
293696c4247cSmpi 	if (ic->ic_if.if_bridgeidx != 0)
2937b64f3d33Sreyk 		bridge_update(&ic->ic_if,
2938b64f3d33Sreyk 		    (struct ether_addr *)ni->ni_macaddr, 0);
2939b64f3d33Sreyk #endif
29400fd4e251Sreyk }
29410fd4e251Sreyk 
294245eec175Sdamien /*
294345eec175Sdamien  * Handle an HT STA leaving an HT network.
294445eec175Sdamien  */
294545eec175Sdamien void
294645eec175Sdamien ieee80211_node_leave_ht(struct ieee80211com *ic, struct ieee80211_node *ni)
294745eec175Sdamien {
2948ec69e05aSdamien 	struct ieee80211_rx_ba *ba;
294945eec175Sdamien 	u_int8_t tid;
295045eec175Sdamien 	int i;
295145eec175Sdamien 
295245eec175Sdamien 	/* free all Block Ack records */
29531cfdb13aSstsp 	ieee80211_ba_del(ni);
295445eec175Sdamien 	for (tid = 0; tid < IEEE80211_NUM_TID; tid++) {
2955ec69e05aSdamien 		ba = &ni->ni_rx_ba[tid];
295645eec175Sdamien 		if (ba->ba_buf != NULL) {
295745eec175Sdamien 			for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++)
295845eec175Sdamien 				m_freem(ba->ba_buf[i].m);
29594adcc1c9Stb 			free(ba->ba_buf, M_DEVBUF,
29604adcc1c9Stb 			    IEEE80211_BA_MAX_WINSZ * sizeof(*ba->ba_buf));
296145eec175Sdamien 			ba->ba_buf = NULL;
296245eec175Sdamien 		}
296345eec175Sdamien 	}
29642040b0e1Sstsp 
29652040b0e1Sstsp 	ieee80211_clear_htcaps(ni);
296645eec175Sdamien }
296745eec175Sdamien 
29680fd4e251Sreyk /*
296950e8fe1cSstsp  * Handle a VHT STA leaving a VHT network.
297050e8fe1cSstsp  */
297150e8fe1cSstsp void
297250e8fe1cSstsp ieee80211_node_leave_vht(struct ieee80211com *ic, struct ieee80211_node *ni)
297350e8fe1cSstsp {
297450e8fe1cSstsp 	ieee80211_clear_vhtcaps(ni);
297550e8fe1cSstsp }
297650e8fe1cSstsp 
297750e8fe1cSstsp /*
2978e03e709cSdamien  * Handle a station leaving an RSN network.
2979e03e709cSdamien  */
2980e03e709cSdamien void
2981e03e709cSdamien ieee80211_node_leave_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
2982e03e709cSdamien {
2983ca7fda7eSstsp 	int rekeysta = 0;
2984ca7fda7eSstsp 
2985e03e709cSdamien 	ni->ni_rsn_state = RSNA_INITIALIZE;
2986ca7fda7eSstsp 	if (ni->ni_flags & IEEE80211_NODE_REKEY) {
2987e03e709cSdamien 		ni->ni_flags &= ~IEEE80211_NODE_REKEY;
2988ca7fda7eSstsp 		ieee80211_iterate_nodes(ic,
2989ca7fda7eSstsp 		    ieee80211_count_rekeysta, &rekeysta);
2990ca7fda7eSstsp 		if (rekeysta == 0)
2991ca7fda7eSstsp 			ieee80211_setkeysdone(ic);
2992ca7fda7eSstsp 	}
2993f91ff320Sdamien 	ni->ni_flags &= ~IEEE80211_NODE_PMK;
2994e03e709cSdamien 	ni->ni_rsn_gstate = RSNA_IDLE;
2995e03e709cSdamien 
299645eec175Sdamien 	timeout_del(&ni->ni_eapol_to);
2997c720ca3cSdamien 	timeout_del(&ni->ni_sa_query_to);
2998b15efae8Sdamien 
2999e03e709cSdamien 	ni->ni_rsn_retries = 0;
300001ad6d9fSdamien 	ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
3001e03e709cSdamien 	ni->ni_port_valid = 0;
3002e03e709cSdamien 	(*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key);
3003e03e709cSdamien }
3004e03e709cSdamien 
3005e03e709cSdamien /*
30061bb78573Sdamien  * Handle a station leaving an 11g network.
30071bb78573Sdamien  */
3008250085e6Sdamien void
30091bb78573Sdamien ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
30101bb78573Sdamien {
3011ca7fda7eSstsp 	int longslotsta = 0, nonerpsta = 0;
3012ca7fda7eSstsp 
30131bb78573Sdamien 	if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) {
30141bb78573Sdamien 		/* leaving STA did not support short slot time */
3015ca7fda7eSstsp 		ieee80211_iterate_nodes(ic,
3016ca7fda7eSstsp 		    ieee80211_count_longslotsta, &longslotsta);
3017ca7fda7eSstsp 		if (longslotsta == 1) {
30181bb78573Sdamien 			/*
30191bb78573Sdamien 			 * All associated STAs now support short slot time, so
30201bb78573Sdamien 			 * enable this feature and give the driver a chance to
30211bb78573Sdamien 			 * reconfigure the hardware. Notice that IBSS always
30221bb78573Sdamien 			 * use a long slot time.
30231bb78573Sdamien 			 */
30241bb78573Sdamien 			if ((ic->ic_caps & IEEE80211_C_SHSLOT) &&
30251bb78573Sdamien 			    ic->ic_opmode != IEEE80211_M_IBSS)
30261bb78573Sdamien 				ieee80211_set_shortslottime(ic, 1);
30271bb78573Sdamien 		}
3028932b9027Sdamien 		DPRINTF(("[%s] long slot time station leaves, count %d\n",
3029ca7fda7eSstsp 		    ether_sprintf(ni->ni_macaddr), longslotsta));
30301bb78573Sdamien 	}
30311bb78573Sdamien 
30321bb78573Sdamien 	if (!(ni->ni_flags & IEEE80211_NODE_ERP)) {
30331bb78573Sdamien 		/* leaving STA was non-ERP */
3034ca7fda7eSstsp 		ieee80211_iterate_nodes(ic,
3035ca7fda7eSstsp 		    ieee80211_count_nonerpsta, &nonerpsta);
3036ca7fda7eSstsp 		if (nonerpsta == 1) {
30371bb78573Sdamien 			/*
30381bb78573Sdamien 			 * All associated STAs are now ERP capable, disable use
30391bb78573Sdamien 			 * of protection and re-enable short preamble support.
30401bb78573Sdamien 			 */
30411bb78573Sdamien 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
30421bb78573Sdamien 			if (ic->ic_caps & IEEE80211_C_SHPREAMBLE)
30431bb78573Sdamien 				ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
30441bb78573Sdamien 		}
3045932b9027Sdamien 		DPRINTF(("[%s] non-ERP station leaves, count %d\n",
3046ca7fda7eSstsp 		    ether_sprintf(ni->ni_macaddr), nonerpsta));
30471bb78573Sdamien 	}
30481bb78573Sdamien }
30491bb78573Sdamien 
3050a6224a8bSstsp void
3051a6224a8bSstsp ieee80211_node_leave_pwrsave(struct ieee80211com *ic,
3052a6224a8bSstsp     struct ieee80211_node *ni)
3053a6224a8bSstsp {
3054a6224a8bSstsp 	struct mbuf_queue keep = MBUF_QUEUE_INITIALIZER(IFQ_MAXLEN, IPL_NET);
3055a6224a8bSstsp 	struct mbuf *m;
3056a6224a8bSstsp 
3057a6224a8bSstsp 	if (ni->ni_pwrsave == IEEE80211_PS_DOZE)
3058a6224a8bSstsp 		ni->ni_pwrsave = IEEE80211_PS_AWAKE;
3059a6224a8bSstsp 
3060a6224a8bSstsp 	if (mq_len(&ni->ni_savedq) > 0) {
3061a6224a8bSstsp 		if (ic->ic_set_tim != NULL)
3062a6224a8bSstsp 			(*ic->ic_set_tim)(ic, ni->ni_associd, 0);
3063a6224a8bSstsp 	}
3064a6224a8bSstsp 	while ((m = mq_dequeue(&ni->ni_savedq)) != NULL) {
3065a6224a8bSstsp 		if (ni->ni_refcnt > 0)
3066a6224a8bSstsp 			ieee80211_node_decref(ni);
3067a6224a8bSstsp 		m_freem(m);
3068a6224a8bSstsp 	}
3069a6224a8bSstsp 
3070a6224a8bSstsp 	/* Purge frames queued for transmission during DTIM. */
3071a6224a8bSstsp 	while ((m = mq_dequeue(&ic->ic_pwrsaveq)) != NULL) {
3072a6224a8bSstsp 		if (m->m_pkthdr.ph_cookie == ni) {
3073a6224a8bSstsp 			if (ni->ni_refcnt > 0)
3074a6224a8bSstsp 				ieee80211_node_decref(ni);
3075a6224a8bSstsp 			m_freem(m);
3076a6224a8bSstsp 		} else
3077a6224a8bSstsp 			mq_enqueue(&keep, m);
3078a6224a8bSstsp 	}
3079a6224a8bSstsp 	while ((m = mq_dequeue(&keep)) != NULL)
3080a6224a8bSstsp 		mq_enqueue(&ic->ic_pwrsaveq, m);
3081a6224a8bSstsp }
3082a6224a8bSstsp 
30831bb78573Sdamien /*
30840fd4e251Sreyk  * Handle bookkeeping for station deauthentication/disassociation
30850fd4e251Sreyk  * when operating as an ap.
30860fd4e251Sreyk  */
30870fd4e251Sreyk void
30880fd4e251Sreyk ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
30890fd4e251Sreyk {
3090fe6a7506Sjsg 	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
3091fe6a7506Sjsg 		panic("not in ap mode, mode %u", ic->ic_opmode);
30927d6afa51Sstsp 
30937d6afa51Sstsp 	if (ni->ni_state == IEEE80211_STA_COLLECT)
30947d6afa51Sstsp 		return;
30950fd4e251Sreyk 	/*
3096b15efae8Sdamien 	 * If node wasn't previously associated all we need to do is
3097b15efae8Sdamien 	 * reclaim the reference.
30980fd4e251Sreyk 	 */
30996bbde753Sstsp 	if (ni->ni_associd == 0) {
31006bbde753Sstsp 		ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT);
31010fd4e251Sreyk 		return;
31026bbde753Sstsp 	}
31031bb78573Sdamien 
3104a6224a8bSstsp 	ieee80211_node_leave_pwrsave(ic, ni);
31053945a2e1Sdamien 
3106e03e709cSdamien 	if (ic->ic_flags & IEEE80211_F_RSNON)
3107e03e709cSdamien 		ieee80211_node_leave_rsn(ic, ni);
3108e03e709cSdamien 
31090126ded1Sstsp 	if (ic->ic_curmode == IEEE80211_MODE_11G ||
31100126ded1Sstsp 	    (ic->ic_curmode == IEEE80211_MODE_11N &&
31110126ded1Sstsp 	    IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan)))
31121bb78573Sdamien 		ieee80211_node_leave_11g(ic, ni);
31131bb78573Sdamien 
311445eec175Sdamien 	if (ni->ni_flags & IEEE80211_NODE_HT)
311545eec175Sdamien 		ieee80211_node_leave_ht(ic, ni);
311650e8fe1cSstsp 	if (ni->ni_flags & IEEE80211_NODE_VHT)
311750e8fe1cSstsp 		ieee80211_node_leave_vht(ic, ni);
311845eec175Sdamien 
3119a2be7d77Sdamien 	if (ic->ic_node_leave != NULL)
3120a2be7d77Sdamien 		(*ic->ic_node_leave)(ic, ni);
3121a2be7d77Sdamien 
31220fd4e251Sreyk 	ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT);
3123b64f3d33Sreyk 
3124b64f3d33Sreyk #if NBRIDGE > 0
3125b64f3d33Sreyk 	/*
31262d18ef82Scamield 	 * If the parent interface is a bridge port, delete
3127b64f3d33Sreyk 	 * any dynamically learned address for this node.
3128b64f3d33Sreyk 	 */
312996c4247cSmpi 	if (ic->ic_if.if_bridgeidx != 0)
3130b64f3d33Sreyk 		bridge_update(&ic->ic_if,
3131b64f3d33Sreyk 		    (struct ether_addr *)ni->ni_macaddr, 1);
3132b64f3d33Sreyk #endif
313391b2158bSmillert }
31343ce67372Sreyk 
3135bb8892d0Sdamien static int
3136bb8892d0Sdamien ieee80211_do_slow_print(struct ieee80211com *ic, int *did_print)
3137bb8892d0Sdamien {
3138bb8892d0Sdamien 	static const struct timeval merge_print_intvl = {
3139bb8892d0Sdamien 		.tv_sec = 1, .tv_usec = 0
3140bb8892d0Sdamien 	};
3141bb8892d0Sdamien 	if ((ic->ic_if.if_flags & IFF_LINK0) == 0)
3142bb8892d0Sdamien 		return 0;
3143bb8892d0Sdamien 	if (!*did_print && (ic->ic_if.if_flags & IFF_DEBUG) == 0 &&
3144bb8892d0Sdamien 	    !ratecheck(&ic->ic_last_merge_print, &merge_print_intvl))
3145bb8892d0Sdamien 		return 0;
3146bb8892d0Sdamien 
3147bb8892d0Sdamien 	*did_print = 1;
3148bb8892d0Sdamien 	return 1;
3149bb8892d0Sdamien }
3150bb8892d0Sdamien 
3151bb8892d0Sdamien /* ieee80211_ibss_merge helps merge 802.11 ad hoc networks.  The
3152bb8892d0Sdamien  * convention, set by the Wireless Ethernet Compatibility Alliance
3153bb8892d0Sdamien  * (WECA), is that an 802.11 station will change its BSSID to match
3154bb8892d0Sdamien  * the "oldest" 802.11 ad hoc network, on the same channel, that
3155bb8892d0Sdamien  * has the station's desired SSID.  The "oldest" 802.11 network
3156bb8892d0Sdamien  * sends beacons with the greatest TSF timestamp.
3157bb8892d0Sdamien  *
3158bb8892d0Sdamien  * Return ENETRESET if the BSSID changed, 0 otherwise.
3159bb8892d0Sdamien  *
3160bb8892d0Sdamien  * XXX Perhaps we should compensate for the time that elapses
3161bb8892d0Sdamien  * between the MAC receiving the beacon and the host processing it
3162bb8892d0Sdamien  * in ieee80211_ibss_merge.
3163bb8892d0Sdamien  */
3164bb8892d0Sdamien int
3165bb8892d0Sdamien ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni,
3166bb8892d0Sdamien     u_int64_t local_tsft)
3167bb8892d0Sdamien {
3168bb8892d0Sdamien 	u_int64_t beacon_tsft;
3169bb8892d0Sdamien 	int did_print = 0, sign;
3170bb8892d0Sdamien 	union {
3171bb8892d0Sdamien 		u_int64_t	word;
3172bb8892d0Sdamien 		u_int8_t	tstamp[8];
3173bb8892d0Sdamien 	} u;
3174bb8892d0Sdamien 
3175bb8892d0Sdamien 	/* ensure alignment */
3176bb8892d0Sdamien 	(void)memcpy(&u, &ni->ni_tstamp[0], sizeof(u));
3177bb8892d0Sdamien 	beacon_tsft = letoh64(u.word);
3178bb8892d0Sdamien 
3179bb8892d0Sdamien 	/* we are faster, let the other guy catch up */
3180bb8892d0Sdamien 	if (beacon_tsft < local_tsft)
3181bb8892d0Sdamien 		sign = -1;
3182bb8892d0Sdamien 	else
3183bb8892d0Sdamien 		sign = 1;
3184bb8892d0Sdamien 
3185bb8892d0Sdamien 	if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
3186bb8892d0Sdamien 		if (!ieee80211_do_slow_print(ic, &did_print))
3187bb8892d0Sdamien 			return 0;
3188bb8892d0Sdamien 		printf("%s: tsft offset %s%llu\n", ic->ic_if.if_xname,
3189bb8892d0Sdamien 		    (sign < 0) ? "-" : "",
3190bb8892d0Sdamien 		    (sign < 0)
3191bb8892d0Sdamien 			? (local_tsft - beacon_tsft)
3192bb8892d0Sdamien 			: (beacon_tsft - local_tsft));
3193bb8892d0Sdamien 		return 0;
3194bb8892d0Sdamien 	}
3195bb8892d0Sdamien 
3196bb8892d0Sdamien 	if (sign < 0)
3197bb8892d0Sdamien 		return 0;
3198bb8892d0Sdamien 
3199799b58a5Sstsp 	if (ieee80211_match_bss(ic, ni, 0) != 0)
3200bb8892d0Sdamien 		return 0;
3201bb8892d0Sdamien 
3202bb8892d0Sdamien 	if (ieee80211_do_slow_print(ic, &did_print)) {
3203bb8892d0Sdamien 		printf("%s: ieee80211_ibss_merge: bssid mismatch %s\n",
3204bb8892d0Sdamien 		    ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid));
3205bb8892d0Sdamien 		printf("%s: my tsft %llu beacon tsft %llu\n",
3206bb8892d0Sdamien 		    ic->ic_if.if_xname, local_tsft, beacon_tsft);
3207bb8892d0Sdamien 		printf("%s: sync TSF with %s\n",
3208bb8892d0Sdamien 		    ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
3209bb8892d0Sdamien 	}
3210bb8892d0Sdamien 
3211bb8892d0Sdamien 	ic->ic_flags &= ~IEEE80211_F_SIBSS;
3212bb8892d0Sdamien 
3213bb8892d0Sdamien 	/* negotiate rates with new IBSS */
3214bb8892d0Sdamien 	ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE |
3215bb8892d0Sdamien 	    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
3216bb8892d0Sdamien 	if (ni->ni_rates.rs_nrates == 0) {
3217bb8892d0Sdamien 		if (ieee80211_do_slow_print(ic, &did_print)) {
3218bb8892d0Sdamien 			printf("%s: rates mismatch, BSSID %s\n",
3219bb8892d0Sdamien 			    ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid));
3220bb8892d0Sdamien 		}
3221bb8892d0Sdamien 		return 0;
3222bb8892d0Sdamien 	}
3223bb8892d0Sdamien 
3224bb8892d0Sdamien 	if (ieee80211_do_slow_print(ic, &did_print)) {
3225bb8892d0Sdamien 		printf("%s: sync BSSID %s -> ",
3226bb8892d0Sdamien 		    ic->ic_if.if_xname, ether_sprintf(ic->ic_bss->ni_bssid));
3227bb8892d0Sdamien 		printf("%s ", ether_sprintf(ni->ni_bssid));
3228bb8892d0Sdamien 		printf("(from %s)\n", ether_sprintf(ni->ni_macaddr));
3229bb8892d0Sdamien 	}
3230bb8892d0Sdamien 
3231bb8892d0Sdamien 	ieee80211_node_newstate(ni, IEEE80211_STA_BSS);
3232bb8892d0Sdamien 	(*ic->ic_node_copy)(ic, ic->ic_bss, ni);
3233bb8892d0Sdamien 
3234bb8892d0Sdamien 	return ENETRESET;
3235bb8892d0Sdamien }
3236bb8892d0Sdamien 
3237158c4605Sdamien void
3238158c4605Sdamien ieee80211_set_tim(struct ieee80211com *ic, int aid, int set)
3239158c4605Sdamien {
3240158c4605Sdamien 	if (set)
3241158c4605Sdamien 		setbit(ic->ic_tim_bitmap, aid & ~0xc000);
3242158c4605Sdamien 	else
3243158c4605Sdamien 		clrbit(ic->ic_tim_bitmap, aid & ~0xc000);
3244158c4605Sdamien }
32454e05de32Sdamien 
32464e05de32Sdamien /*
32474e05de32Sdamien  * This function shall be called by drivers immediately after every DTIM.
32484e05de32Sdamien  * Transmit all group addressed MSDUs buffered at the AP.
32494e05de32Sdamien  */
32504e05de32Sdamien void
32514e05de32Sdamien ieee80211_notify_dtim(struct ieee80211com *ic)
32524e05de32Sdamien {
32534e05de32Sdamien 	/* NB: group addressed MSDUs are buffered in ic_bss */
32544e05de32Sdamien 	struct ieee80211_node *ni = ic->ic_bss;
32554e05de32Sdamien 	struct ifnet *ifp = &ic->ic_if;
32564e05de32Sdamien 	struct ieee80211_frame *wh;
32574e05de32Sdamien 	struct mbuf *m;
32584e05de32Sdamien 
32594e05de32Sdamien 	KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP);
32604e05de32Sdamien 
3261351e1934Sdlg 	while ((m = mq_dequeue(&ni->ni_savedq)) != NULL) {
3262351e1934Sdlg 		if (!mq_empty(&ni->ni_savedq)) {
32634e05de32Sdamien 			/* more queued frames, set the more data bit */
32644e05de32Sdamien 			wh = mtod(m, struct ieee80211_frame *);
32654e05de32Sdamien 			wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
32664e05de32Sdamien 		}
3267351e1934Sdlg 		mq_enqueue(&ic->ic_pwrsaveq, m);
326867de757dSmpi 		if_start(ifp);
32694e05de32Sdamien 	}
32704e05de32Sdamien 	/* XXX assumes everything has been sent */
32714e05de32Sdamien 	ic->ic_tim_mcast_pending = 0;
32724e05de32Sdamien }
3273171ac09aSdamien #endif	/* IEEE80211_STA_ONLY */
3274158c4605Sdamien 
32753ce67372Sreyk /*
32763ce67372Sreyk  * Compare nodes in the tree by lladdr
32773ce67372Sreyk  */
32783ce67372Sreyk int
3279f22d9adcSdamien ieee80211_node_cmp(const struct ieee80211_node *b1,
3280f22d9adcSdamien     const struct ieee80211_node *b2)
32813ce67372Sreyk {
32823ce67372Sreyk 	return (memcmp(b1->ni_macaddr, b2->ni_macaddr, IEEE80211_ADDR_LEN));
32833ce67372Sreyk }
32843ce67372Sreyk 
32853ce67372Sreyk /*
3286020402a2Sphessler  * Compare nodes in the tree by essid
3287020402a2Sphessler  */
3288020402a2Sphessler int
3289020402a2Sphessler ieee80211_ess_cmp(const struct ieee80211_ess_rbt *b1,
3290020402a2Sphessler     const struct ieee80211_ess_rbt *b2)
3291020402a2Sphessler {
3292020402a2Sphessler 	return (memcmp(b1->essid, b2->essid, IEEE80211_NWID_LEN));
3293020402a2Sphessler }
3294020402a2Sphessler 
3295020402a2Sphessler /*
32963ce67372Sreyk  * Generate red-black tree function logic
32973ce67372Sreyk  */
32988529d8f0Sdlg RBT_GENERATE(ieee80211_tree, ieee80211_node, ni_node, ieee80211_node_cmp);
3299020402a2Sphessler RBT_GENERATE(ieee80211_ess_tree, ieee80211_ess_rbt, ess_rbt, ieee80211_ess_cmp);
3300