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