1f186073cSJoerg Sonnenberger /* 2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 3*841ab66cSSepherosa Ziehau * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 4f186073cSJoerg Sonnenberger * All rights reserved. 5f186073cSJoerg Sonnenberger * 6f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 7f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions 8f186073cSJoerg Sonnenberger * are met: 9f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 10f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 11f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 12f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 13f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 14f186073cSJoerg Sonnenberger * 3. The name of the author may not be used to endorse or promote products 15f186073cSJoerg Sonnenberger * derived from this software without specific prior written permission. 16f186073cSJoerg Sonnenberger * 17f186073cSJoerg Sonnenberger * Alternatively, this software may be distributed under the terms of the 18f186073cSJoerg Sonnenberger * GNU General Public License ("GPL") version 2 as published by the Free 19f186073cSJoerg Sonnenberger * Software Foundation. 20f186073cSJoerg Sonnenberger * 21f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31f186073cSJoerg Sonnenberger * 32*841ab66cSSepherosa Ziehau * $FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.48.2.10 2006/03/13 03:05:47 sam Exp $ 33*841ab66cSSepherosa Ziehau * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.2 2006/05/18 13:51:46 sephe Exp $ 34f186073cSJoerg Sonnenberger */ 35f186073cSJoerg Sonnenberger 36f186073cSJoerg Sonnenberger #include <sys/param.h> 37f186073cSJoerg Sonnenberger #include <sys/systm.h> 38f186073cSJoerg Sonnenberger #include <sys/mbuf.h> 39f186073cSJoerg Sonnenberger #include <sys/malloc.h> 40f186073cSJoerg Sonnenberger #include <sys/kernel.h> 41f186073cSJoerg Sonnenberger 42*841ab66cSSepherosa Ziehau #include <sys/socket.h> 43f186073cSJoerg Sonnenberger 44f186073cSJoerg Sonnenberger #include <net/if.h> 45f186073cSJoerg Sonnenberger #include <net/if_arp.h> 46*841ab66cSSepherosa Ziehau #include <net/if_media.h> 47f186073cSJoerg Sonnenberger #include <net/ethernet.h> 48f186073cSJoerg Sonnenberger 49f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h> 50f186073cSJoerg Sonnenberger 51f186073cSJoerg Sonnenberger #include <net/bpf.h> 52f186073cSJoerg Sonnenberger 53*841ab66cSSepherosa Ziehau /* 54*841ab66cSSepherosa Ziehau * Association id's are managed with a bit vector. 55*841ab66cSSepherosa Ziehau */ 56*841ab66cSSepherosa Ziehau #define IEEE80211_AID_SET(b, w) \ 57*841ab66cSSepherosa Ziehau ((w)[IEEE80211_AID(b) / 32] |= (1 << (IEEE80211_AID(b) % 32))) 58*841ab66cSSepherosa Ziehau #define IEEE80211_AID_CLR(b, w) \ 59*841ab66cSSepherosa Ziehau ((w)[IEEE80211_AID(b) / 32] &= ~(1 << (IEEE80211_AID(b) % 32))) 60*841ab66cSSepherosa Ziehau #define IEEE80211_AID_ISSET(b, w) \ 61*841ab66cSSepherosa Ziehau ((w)[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32))) 62f186073cSJoerg Sonnenberger 63*841ab66cSSepherosa Ziehau static struct ieee80211_node *node_alloc(struct ieee80211_node_table *); 64*841ab66cSSepherosa Ziehau static void node_cleanup(struct ieee80211_node *); 65*841ab66cSSepherosa Ziehau static void node_free(struct ieee80211_node *); 66*841ab66cSSepherosa Ziehau static uint8_t node_getrssi(const struct ieee80211_node *); 67f186073cSJoerg Sonnenberger 68*841ab66cSSepherosa Ziehau static void ieee80211_setup_node(struct ieee80211_node_table *, 69*841ab66cSSepherosa Ziehau struct ieee80211_node *, const uint8_t *); 70*841ab66cSSepherosa Ziehau static void _ieee80211_free_node(struct ieee80211_node *); 71*841ab66cSSepherosa Ziehau static void ieee80211_free_allnodes(struct ieee80211_node_table *); 72*841ab66cSSepherosa Ziehau 73*841ab66cSSepherosa Ziehau static void ieee80211_timeout_scan_candidates(struct ieee80211_node_table *); 74*841ab66cSSepherosa Ziehau static void ieee80211_timeout_stations(struct ieee80211_node_table *); 75*841ab66cSSepherosa Ziehau 76*841ab66cSSepherosa Ziehau static void ieee80211_set_tim(struct ieee80211_node *, int set); 77*841ab66cSSepherosa Ziehau 78*841ab66cSSepherosa Ziehau static void ieee80211_node_table_init(struct ieee80211com *ic, 79*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, const char *name, 80*841ab66cSSepherosa Ziehau int inact, int keyixmax, 81*841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)); 82*841ab66cSSepherosa Ziehau static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 83f186073cSJoerg Sonnenberger 84f186073cSJoerg Sonnenberger MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 85f186073cSJoerg Sonnenberger 86f186073cSJoerg Sonnenberger void 87*841ab66cSSepherosa Ziehau ieee80211_node_attach(struct ieee80211com *ic) 88f186073cSJoerg Sonnenberger { 89*841ab66cSSepherosa Ziehau ic->ic_node_alloc = node_alloc; 90*841ab66cSSepherosa Ziehau ic->ic_node_free = node_free; 91*841ab66cSSepherosa Ziehau ic->ic_node_cleanup = node_cleanup; 92*841ab66cSSepherosa Ziehau ic->ic_node_getrssi = node_getrssi; 93f186073cSJoerg Sonnenberger 94*841ab66cSSepherosa Ziehau /* default station inactivity timer setings */ 95*841ab66cSSepherosa Ziehau ic->ic_inact_init = IEEE80211_INACT_INIT; 96*841ab66cSSepherosa Ziehau ic->ic_inact_auth = IEEE80211_INACT_AUTH; 97*841ab66cSSepherosa Ziehau ic->ic_inact_run = IEEE80211_INACT_RUN; 98*841ab66cSSepherosa Ziehau ic->ic_inact_probe = IEEE80211_INACT_PROBE; 99*841ab66cSSepherosa Ziehau 100*841ab66cSSepherosa Ziehau /* NB: driver should override */ 101*841ab66cSSepherosa Ziehau ic->ic_max_aid = IEEE80211_AID_DEF; 102*841ab66cSSepherosa Ziehau ic->ic_set_tim = ieee80211_set_tim; 103f186073cSJoerg Sonnenberger } 104f186073cSJoerg Sonnenberger 105f186073cSJoerg Sonnenberger void 106*841ab66cSSepherosa Ziehau ieee80211_node_lateattach(struct ieee80211com *ic) 107f186073cSJoerg Sonnenberger { 108*841ab66cSSepherosa Ziehau struct ieee80211_rsnparms *rsn; 109f186073cSJoerg Sonnenberger 110*841ab66cSSepherosa Ziehau if (ic->ic_max_aid > IEEE80211_AID_MAX) 111*841ab66cSSepherosa Ziehau ic->ic_max_aid = IEEE80211_AID_MAX; 112*841ab66cSSepherosa Ziehau 113*841ab66cSSepherosa Ziehau ic->ic_aid_bitmap = 114*841ab66cSSepherosa Ziehau malloc(howmany(ic->ic_max_aid, 32) * sizeof(uint32_t), 115*841ab66cSSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 116*841ab66cSSepherosa Ziehau 117*841ab66cSSepherosa Ziehau /* XXX defer until using hostap/ibss mode */ 118*841ab66cSSepherosa Ziehau ic->ic_tim_len = howmany(ic->ic_max_aid, 8) * sizeof(uint8_t); 119*841ab66cSSepherosa Ziehau ic->ic_tim_bitmap = malloc(ic->ic_tim_len, M_DEVBUF, 120*841ab66cSSepherosa Ziehau M_WAITOK | M_ZERO); 121*841ab66cSSepherosa Ziehau 122*841ab66cSSepherosa Ziehau ieee80211_node_table_init(ic, &ic->ic_sta, "station", 123*841ab66cSSepherosa Ziehau IEEE80211_INACT_INIT, ic->ic_crypto.cs_max_keyix, 124*841ab66cSSepherosa Ziehau ieee80211_timeout_stations); 125*841ab66cSSepherosa Ziehau ieee80211_node_table_init(ic, &ic->ic_scan, "scan", 126*841ab66cSSepherosa Ziehau IEEE80211_INACT_SCAN, 0, 127*841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates); 128*841ab66cSSepherosa Ziehau 129*841ab66cSSepherosa Ziehau ieee80211_reset_bss(ic); 130*841ab66cSSepherosa Ziehau /* 131*841ab66cSSepherosa Ziehau * Setup "global settings" in the bss node so that 132*841ab66cSSepherosa Ziehau * each new station automatically inherits them. 133*841ab66cSSepherosa Ziehau */ 134*841ab66cSSepherosa Ziehau rsn = &ic->ic_bss->ni_rsn; 135*841ab66cSSepherosa Ziehau /* WEP, TKIP, and AES-CCM are always supported */ 136*841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_WEP; 137*841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_TKIP; 138*841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_CCM; 139*841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_AES) 140*841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_OCB; 141*841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_CKIP) 142*841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_CKIP; 143*841ab66cSSepherosa Ziehau /* 144*841ab66cSSepherosa Ziehau * Default unicast cipher to WEP for 802.1x use. If 145*841ab66cSSepherosa Ziehau * WPA is enabled the management code will set these 146*841ab66cSSepherosa Ziehau * values to reflect. 147*841ab66cSSepherosa Ziehau */ 148*841ab66cSSepherosa Ziehau rsn->rsn_ucastcipher = IEEE80211_CIPHER_WEP; 149*841ab66cSSepherosa Ziehau rsn->rsn_ucastkeylen = 104 / NBBY; 150*841ab66cSSepherosa Ziehau /* 151*841ab66cSSepherosa Ziehau * WPA says the multicast cipher is the lowest unicast 152*841ab66cSSepherosa Ziehau * cipher supported. But we skip WEP which would 153*841ab66cSSepherosa Ziehau * otherwise be used based on this criteria. 154*841ab66cSSepherosa Ziehau */ 155*841ab66cSSepherosa Ziehau rsn->rsn_mcastcipher = IEEE80211_CIPHER_TKIP; 156*841ab66cSSepherosa Ziehau rsn->rsn_mcastkeylen = 128 / NBBY; 157*841ab66cSSepherosa Ziehau 158*841ab66cSSepherosa Ziehau /* 159*841ab66cSSepherosa Ziehau * We support both WPA-PSK and 802.1x; the one used 160*841ab66cSSepherosa Ziehau * is determined by the authentication mode and the 161*841ab66cSSepherosa Ziehau * setting of the PSK state. 162*841ab66cSSepherosa Ziehau */ 163*841ab66cSSepherosa Ziehau rsn->rsn_keymgmtset = WPA_ASE_8021X_UNSPEC | WPA_ASE_8021X_PSK; 164*841ab66cSSepherosa Ziehau rsn->rsn_keymgmt = WPA_ASE_8021X_PSK; 165*841ab66cSSepherosa Ziehau 166*841ab66cSSepherosa Ziehau ic->ic_auth = ieee80211_authenticator_get(ic->ic_bss->ni_authmode); 167f186073cSJoerg Sonnenberger } 168f186073cSJoerg Sonnenberger 169f186073cSJoerg Sonnenberger void 170*841ab66cSSepherosa Ziehau ieee80211_node_detach(struct ieee80211com *ic) 171f186073cSJoerg Sonnenberger { 172*841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) { 173*841ab66cSSepherosa Ziehau ieee80211_free_node(ic->ic_bss); 174*841ab66cSSepherosa Ziehau ic->ic_bss = NULL; 175*841ab66cSSepherosa Ziehau } 176*841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_scan); 177*841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_sta); 178*841ab66cSSepherosa Ziehau if (ic->ic_aid_bitmap != NULL) { 179*841ab66cSSepherosa Ziehau free(ic->ic_aid_bitmap, M_DEVBUF); 180*841ab66cSSepherosa Ziehau ic->ic_aid_bitmap = NULL; 181*841ab66cSSepherosa Ziehau } 182*841ab66cSSepherosa Ziehau if (ic->ic_tim_bitmap != NULL) { 183*841ab66cSSepherosa Ziehau free(ic->ic_tim_bitmap, M_DEVBUF); 184*841ab66cSSepherosa Ziehau ic->ic_tim_bitmap = NULL; 185*841ab66cSSepherosa Ziehau } 186*841ab66cSSepherosa Ziehau } 187f186073cSJoerg Sonnenberger 188*841ab66cSSepherosa Ziehau /* 189*841ab66cSSepherosa Ziehau * Port authorize/unauthorize interfaces for use by an authenticator. 190*841ab66cSSepherosa Ziehau */ 191*841ab66cSSepherosa Ziehau 192*841ab66cSSepherosa Ziehau void 193*841ab66cSSepherosa Ziehau ieee80211_node_authorize(struct ieee80211_node *ni) 194*841ab66cSSepherosa Ziehau { 195*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 196*841ab66cSSepherosa Ziehau 197*841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_AUTH; 198*841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_run; 199*841ab66cSSepherosa Ziehau } 200*841ab66cSSepherosa Ziehau 201*841ab66cSSepherosa Ziehau void 202*841ab66cSSepherosa Ziehau ieee80211_node_unauthorize(struct ieee80211_node *ni) 203*841ab66cSSepherosa Ziehau { 204*841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AUTH; 205*841ab66cSSepherosa Ziehau } 206*841ab66cSSepherosa Ziehau 207*841ab66cSSepherosa Ziehau /* 208*841ab66cSSepherosa Ziehau * Set/change the channel. The rate set is also updated as 209*841ab66cSSepherosa Ziehau * to insure a consistent view by drivers. 210*841ab66cSSepherosa Ziehau */ 211*841ab66cSSepherosa Ziehau static void 212*841ab66cSSepherosa Ziehau ieee80211_set_chan(struct ieee80211com *ic, 213*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, struct ieee80211_channel *chan) 214*841ab66cSSepherosa Ziehau { 215*841ab66cSSepherosa Ziehau if (chan == IEEE80211_CHAN_ANYC) /* XXX while scanning */ 216*841ab66cSSepherosa Ziehau chan = ic->ic_curchan; 217*841ab66cSSepherosa Ziehau ni->ni_chan = chan; 218*841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 219f186073cSJoerg Sonnenberger } 220f186073cSJoerg Sonnenberger 221f186073cSJoerg Sonnenberger /* 222f186073cSJoerg Sonnenberger * AP scanning support. 223f186073cSJoerg Sonnenberger */ 224f186073cSJoerg Sonnenberger 225*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 226*841ab66cSSepherosa Ziehau static void 227*841ab66cSSepherosa Ziehau dump_chanlist(const u_char chans[]) 228*841ab66cSSepherosa Ziehau { 229*841ab66cSSepherosa Ziehau const char *sep; 230*841ab66cSSepherosa Ziehau int i; 231*841ab66cSSepherosa Ziehau 232*841ab66cSSepherosa Ziehau sep = " "; 233*841ab66cSSepherosa Ziehau for (i = 0; i < IEEE80211_CHAN_MAX; i++) 234*841ab66cSSepherosa Ziehau if (isset(chans, i)) { 235*841ab66cSSepherosa Ziehau printf("%s%u", sep, i); 236*841ab66cSSepherosa Ziehau sep = ", "; 237*841ab66cSSepherosa Ziehau } 238*841ab66cSSepherosa Ziehau } 239*841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 240*841ab66cSSepherosa Ziehau 241f186073cSJoerg Sonnenberger /* 242*841ab66cSSepherosa Ziehau * Initialize the channel set to scan based on the 243f186073cSJoerg Sonnenberger * of available channels and the current PHY mode. 244f186073cSJoerg Sonnenberger */ 245f186073cSJoerg Sonnenberger static void 246*841ab66cSSepherosa Ziehau ieee80211_reset_scan(struct ieee80211com *ic) 247f186073cSJoerg Sonnenberger { 248f186073cSJoerg Sonnenberger 249*841ab66cSSepherosa Ziehau /* XXX ic_des_chan should be handled with ic_chan_active */ 250*841ab66cSSepherosa Ziehau if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 251*841ab66cSSepherosa Ziehau memset(ic->ic_chan_scan, 0, sizeof(ic->ic_chan_scan)); 252*841ab66cSSepherosa Ziehau setbit(ic->ic_chan_scan, 253*841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_des_chan)); 254*841ab66cSSepherosa Ziehau } else 255f186073cSJoerg Sonnenberger memcpy(ic->ic_chan_scan, ic->ic_chan_active, 256f186073cSJoerg Sonnenberger sizeof(ic->ic_chan_active)); 257*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 258*841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 259*841ab66cSSepherosa Ziehau printf("%s: scan set:", __func__); 260*841ab66cSSepherosa Ziehau dump_chanlist(ic->ic_chan_scan); 261*841ab66cSSepherosa Ziehau printf(" start chan %u\n", 262*841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan)); 263*841ab66cSSepherosa Ziehau } 264*841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 265f186073cSJoerg Sonnenberger } 266f186073cSJoerg Sonnenberger 267f186073cSJoerg Sonnenberger /* 268f186073cSJoerg Sonnenberger * Begin an active scan. 269f186073cSJoerg Sonnenberger */ 270f186073cSJoerg Sonnenberger void 271*841ab66cSSepherosa Ziehau ieee80211_begin_scan(struct ieee80211com *ic, int reset) 272f186073cSJoerg Sonnenberger { 273*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 274f186073cSJoerg Sonnenberger 275f186073cSJoerg Sonnenberger /* 276f186073cSJoerg Sonnenberger * In all but hostap mode scanning starts off in 277f186073cSJoerg Sonnenberger * an active mode before switching to passive. 278f186073cSJoerg Sonnenberger */ 279f186073cSJoerg Sonnenberger if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 280f186073cSJoerg Sonnenberger ic->ic_flags |= IEEE80211_F_ASCAN; 281f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_active++; 282f186073cSJoerg Sonnenberger } else 283f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_passive++; 284*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 285*841ab66cSSepherosa Ziehau "begin %s scan in %s mode\n", 286*841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive", 287*841ab66cSSepherosa Ziehau ieee80211_phymode_name[ic->ic_curmode]); 288f186073cSJoerg Sonnenberger /* 289*841ab66cSSepherosa Ziehau * Clear scan state and flush any previously seen AP's. 290f186073cSJoerg Sonnenberger */ 291*841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 292*841ab66cSSepherosa Ziehau if (reset) 293*841ab66cSSepherosa Ziehau ieee80211_free_allnodes(&ic->ic_scan); 294*841ab66cSSepherosa Ziehau 295*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 296f186073cSJoerg Sonnenberger 297f186073cSJoerg Sonnenberger /* Scan the next channel. */ 298*841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 299f186073cSJoerg Sonnenberger } 300f186073cSJoerg Sonnenberger 301f186073cSJoerg Sonnenberger /* 302f186073cSJoerg Sonnenberger * Switch to the next channel marked for scanning. 303f186073cSJoerg Sonnenberger */ 304*841ab66cSSepherosa Ziehau int 305*841ab66cSSepherosa Ziehau ieee80211_next_scan(struct ieee80211com *ic) 306f186073cSJoerg Sonnenberger { 307f186073cSJoerg Sonnenberger struct ieee80211_channel *chan; 308f186073cSJoerg Sonnenberger 309*841ab66cSSepherosa Ziehau /* 310*841ab66cSSepherosa Ziehau * Insure any previous mgt frame timeouts don't fire. 311*841ab66cSSepherosa Ziehau * This assumes the driver does the right thing in 312*841ab66cSSepherosa Ziehau * flushing anything queued in the driver and below. 313*841ab66cSSepherosa Ziehau */ 314*841ab66cSSepherosa Ziehau ic->ic_mgt_timer = 0; 315*841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 316*841ab66cSSepherosa Ziehau 317*841ab66cSSepherosa Ziehau chan = ic->ic_curchan; 318*841ab66cSSepherosa Ziehau do { 319f186073cSJoerg Sonnenberger if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) 320f186073cSJoerg Sonnenberger chan = &ic->ic_channels[0]; 321f186073cSJoerg Sonnenberger if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) { 322f186073cSJoerg Sonnenberger clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); 323*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 324*841ab66cSSepherosa Ziehau "%s: chan %d->%d\n", __func__, 325*841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 326*841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, chan)); 327*841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 328*841ab66cSSepherosa Ziehau /* 329*841ab66cSSepherosa Ziehau * XXX drivers should do this as needed, 330*841ab66cSSepherosa Ziehau * XXX for now maintain compatibility 331*841ab66cSSepherosa Ziehau */ 332*841ab66cSSepherosa Ziehau ic->ic_bss->ni_rates = 333*841ab66cSSepherosa Ziehau ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 334f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 335*841ab66cSSepherosa Ziehau return 1; 336*841ab66cSSepherosa Ziehau } 337*841ab66cSSepherosa Ziehau } while (chan != ic->ic_curchan); 338*841ab66cSSepherosa Ziehau ieee80211_end_scan(ic); 339*841ab66cSSepherosa Ziehau return 0; 340*841ab66cSSepherosa Ziehau } 341*841ab66cSSepherosa Ziehau 342*841ab66cSSepherosa Ziehau /* 343*841ab66cSSepherosa Ziehau * Probe the curent channel, if allowed, while scanning. 344*841ab66cSSepherosa Ziehau * If the channel is not marked passive-only then send 345*841ab66cSSepherosa Ziehau * a probe request immediately. Otherwise mark state and 346*841ab66cSSepherosa Ziehau * listen for beacons on the channel; if we receive something 347*841ab66cSSepherosa Ziehau * then we'll transmit a probe request. 348*841ab66cSSepherosa Ziehau */ 349*841ab66cSSepherosa Ziehau void 350*841ab66cSSepherosa Ziehau ieee80211_probe_curchan(struct ieee80211com *ic, int force) 351*841ab66cSSepherosa Ziehau { 352*841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 353*841ab66cSSepherosa Ziehau 354*841ab66cSSepherosa Ziehau if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 || force) { 355*841ab66cSSepherosa Ziehau /* 356*841ab66cSSepherosa Ziehau * XXX send both broadcast+directed probe request 357*841ab66cSSepherosa Ziehau */ 358*841ab66cSSepherosa Ziehau ieee80211_send_probereq(ic->ic_bss, 359*841ab66cSSepherosa Ziehau ic->ic_myaddr, ifp->if_broadcastaddr, 360*841ab66cSSepherosa Ziehau ifp->if_broadcastaddr, 361*841ab66cSSepherosa Ziehau ic->ic_des_essid, ic->ic_des_esslen, 362*841ab66cSSepherosa Ziehau ic->ic_opt_ie, ic->ic_opt_ie_len); 363*841ab66cSSepherosa Ziehau } else 364*841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN; 365*841ab66cSSepherosa Ziehau } 366*841ab66cSSepherosa Ziehau 367*841ab66cSSepherosa Ziehau static __inline void 368*841ab66cSSepherosa Ziehau copy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 369*841ab66cSSepherosa Ziehau { 370*841ab66cSSepherosa Ziehau /* propagate useful state */ 371*841ab66cSSepherosa Ziehau nbss->ni_authmode = obss->ni_authmode; 372*841ab66cSSepherosa Ziehau nbss->ni_txpower = obss->ni_txpower; 373*841ab66cSSepherosa Ziehau nbss->ni_vlan = obss->ni_vlan; 374*841ab66cSSepherosa Ziehau nbss->ni_rsn = obss->ni_rsn; 375*841ab66cSSepherosa Ziehau /* XXX statistics? */ 376f186073cSJoerg Sonnenberger } 377f186073cSJoerg Sonnenberger 378f186073cSJoerg Sonnenberger void 379f186073cSJoerg Sonnenberger ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) 380f186073cSJoerg Sonnenberger { 381*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 382f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 383f186073cSJoerg Sonnenberger 384*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 385*841ab66cSSepherosa Ziehau 386*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 387*841ab66cSSepherosa Ziehau "%s: creating ibss\n", __func__); 388*841ab66cSSepherosa Ziehau 389*841ab66cSSepherosa Ziehau /* 390*841ab66cSSepherosa Ziehau * Create the station/neighbor table. Note that for adhoc 391*841ab66cSSepherosa Ziehau * mode we make the initial inactivity timer longer since 392*841ab66cSSepherosa Ziehau * we create nodes only through discovery and they typically 393*841ab66cSSepherosa Ziehau * are long-lived associations. 394*841ab66cSSepherosa Ziehau */ 395*841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 396*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 397*841ab66cSSepherosa Ziehau nt->nt_name = "station"; 398*841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_init; 399*841ab66cSSepherosa Ziehau } else { 400*841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 401*841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 402*841ab66cSSepherosa Ziehau } 403*841ab66cSSepherosa Ziehau 404*841ab66cSSepherosa Ziehau ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr); 405*841ab66cSSepherosa Ziehau if (ni == NULL) { 406*841ab66cSSepherosa Ziehau /* XXX recovery? */ 407*841ab66cSSepherosa Ziehau return; 408*841ab66cSSepherosa Ziehau } 409f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); 410f186073cSJoerg Sonnenberger ni->ni_esslen = ic->ic_des_esslen; 411f186073cSJoerg Sonnenberger memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); 412*841ab66cSSepherosa Ziehau copy_bss(ni, ic->ic_bss); 413*841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 414*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) 415f186073cSJoerg Sonnenberger ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 416f186073cSJoerg Sonnenberger if (ic->ic_phytype == IEEE80211_T_FH) { 417f186073cSJoerg Sonnenberger ni->ni_fhdwell = 200; /* XXX */ 418f186073cSJoerg Sonnenberger ni->ni_fhindex = 1; 419f186073cSJoerg Sonnenberger } 420*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS) { 421*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SIBSS; 422*841ab66cSSepherosa Ziehau ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 423*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 424*841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 425*841ab66cSSepherosa Ziehau else 426*841ab66cSSepherosa Ziehau ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ 427*841ab66cSSepherosa Ziehau } else if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 428*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 429*841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 430*841ab66cSSepherosa Ziehau else 431*841ab66cSSepherosa Ziehau memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 432*841ab66cSSepherosa Ziehau } 433*841ab66cSSepherosa Ziehau /* 434*841ab66cSSepherosa Ziehau * Fix the channel and related attributes. 435*841ab66cSSepherosa Ziehau */ 436*841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, chan); 437*841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 438*841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, chan); 439*841ab66cSSepherosa Ziehau /* 440*841ab66cSSepherosa Ziehau * Do mode-specific rate setup. 441*841ab66cSSepherosa Ziehau */ 442*841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) { 443*841ab66cSSepherosa Ziehau /* 444*841ab66cSSepherosa Ziehau * Use a mixed 11b/11g rate set. 445*841ab66cSSepherosa Ziehau */ 446*841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11G); 447*841ab66cSSepherosa Ziehau } else if (ic->ic_curmode == IEEE80211_MODE_11B) { 448*841ab66cSSepherosa Ziehau /* 449*841ab66cSSepherosa Ziehau * Force pure 11b rate set. 450*841ab66cSSepherosa Ziehau */ 451*841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11B); 452f186073cSJoerg Sonnenberger } 453f186073cSJoerg Sonnenberger 454*841ab66cSSepherosa Ziehau ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 455*841ab66cSSepherosa Ziehau } 456*841ab66cSSepherosa Ziehau 457*841ab66cSSepherosa Ziehau void 458*841ab66cSSepherosa Ziehau ieee80211_reset_bss(struct ieee80211com *ic) 459f186073cSJoerg Sonnenberger { 460*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *obss; 461*841ab66cSSepherosa Ziehau 462*841ab66cSSepherosa Ziehau ieee80211_node_table_reset(&ic->ic_scan); 463*841ab66cSSepherosa Ziehau ieee80211_node_table_reset(&ic->ic_sta); 464*841ab66cSSepherosa Ziehau 465*841ab66cSSepherosa Ziehau ni = ieee80211_alloc_node(&ic->ic_scan, ic->ic_myaddr); 466*841ab66cSSepherosa Ziehau KASSERT(ni != NULL, ("unable to setup inital BSS node")); 467*841ab66cSSepherosa Ziehau obss = ic->ic_bss; 468*841ab66cSSepherosa Ziehau ic->ic_bss = ieee80211_ref_node(ni); 469*841ab66cSSepherosa Ziehau if (obss != NULL) { 470*841ab66cSSepherosa Ziehau copy_bss(ni, obss); 471*841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 472*841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 473*841ab66cSSepherosa Ziehau } 474*841ab66cSSepherosa Ziehau } 475*841ab66cSSepherosa Ziehau 476*841ab66cSSepherosa Ziehau /* XXX tunable */ 477*841ab66cSSepherosa Ziehau #define STA_FAILS_MAX 2 /* assoc failures before ignored */ 478*841ab66cSSepherosa Ziehau 479*841ab66cSSepherosa Ziehau static int 480*841ab66cSSepherosa Ziehau ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) 481*841ab66cSSepherosa Ziehau { 482f186073cSJoerg Sonnenberger uint8_t rate; 483f186073cSJoerg Sonnenberger int fail; 484f186073cSJoerg Sonnenberger 485f186073cSJoerg Sonnenberger fail = 0; 486f186073cSJoerg Sonnenberger if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 487f186073cSJoerg Sonnenberger fail |= 0x01; 488f186073cSJoerg Sonnenberger if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 489f186073cSJoerg Sonnenberger ni->ni_chan != ic->ic_des_chan) 490f186073cSJoerg Sonnenberger fail |= 0x01; 491f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 492f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 493f186073cSJoerg Sonnenberger fail |= 0x02; 494f186073cSJoerg Sonnenberger } else { 495f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 496f186073cSJoerg Sonnenberger fail |= 0x02; 497f186073cSJoerg Sonnenberger } 498*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) { 499f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 500f186073cSJoerg Sonnenberger fail |= 0x04; 501f186073cSJoerg Sonnenberger } else { 502f186073cSJoerg Sonnenberger /* XXX does this mean privacy is supported or required? */ 503f186073cSJoerg Sonnenberger if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 504f186073cSJoerg Sonnenberger fail |= 0x04; 505f186073cSJoerg Sonnenberger } 506*841ab66cSSepherosa Ziehau rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 507f186073cSJoerg Sonnenberger if (rate & IEEE80211_RATE_BASIC) 508f186073cSJoerg Sonnenberger fail |= 0x08; 509f186073cSJoerg Sonnenberger if (ic->ic_des_esslen != 0 && 510f186073cSJoerg Sonnenberger (ni->ni_esslen != ic->ic_des_esslen || 511f186073cSJoerg Sonnenberger memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) 512f186073cSJoerg Sonnenberger fail |= 0x10; 513f186073cSJoerg Sonnenberger if ((ic->ic_flags & IEEE80211_F_DESBSSID) && 514f186073cSJoerg Sonnenberger !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) 515f186073cSJoerg Sonnenberger fail |= 0x20; 516*841ab66cSSepherosa Ziehau if (ni->ni_fails >= STA_FAILS_MAX) 517*841ab66cSSepherosa Ziehau fail |= 0x40; 518f186073cSJoerg Sonnenberger #ifdef IEEE80211_DEBUG 519*841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 520*841ab66cSSepherosa Ziehau printf(" %c %6D", 521*841ab66cSSepherosa Ziehau fail & 0x40 ? '=' : fail & 0x80 ? '^' : fail ? '-' : '+', 522*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 523*841ab66cSSepherosa Ziehau printf(" %6D%c", ni->ni_bssid, ":", 524*841ab66cSSepherosa Ziehau fail & 0x20 ? '!' : ' '); 525f186073cSJoerg Sonnenberger printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), 526f186073cSJoerg Sonnenberger fail & 0x01 ? '!' : ' '); 527f186073cSJoerg Sonnenberger printf(" %+4d", ni->ni_rssi); 528f186073cSJoerg Sonnenberger printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 529f186073cSJoerg Sonnenberger fail & 0x08 ? '!' : ' '); 530f186073cSJoerg Sonnenberger printf(" %4s%c", 531f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 532f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 533f186073cSJoerg Sonnenberger "????", 534f186073cSJoerg Sonnenberger fail & 0x02 ? '!' : ' '); 535f186073cSJoerg Sonnenberger printf(" %3s%c ", 536f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? 537f186073cSJoerg Sonnenberger "wep" : "no", 538f186073cSJoerg Sonnenberger fail & 0x04 ? '!' : ' '); 539f186073cSJoerg Sonnenberger ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 540f186073cSJoerg Sonnenberger printf("%s\n", fail & 0x10 ? "!" : ""); 541f186073cSJoerg Sonnenberger } 542f186073cSJoerg Sonnenberger #endif 543f186073cSJoerg Sonnenberger return fail; 544f186073cSJoerg Sonnenberger } 545f186073cSJoerg Sonnenberger 546*841ab66cSSepherosa Ziehau static __inline uint8_t 547*841ab66cSSepherosa Ziehau maxrate(const struct ieee80211_node *ni) 548*841ab66cSSepherosa Ziehau { 549*841ab66cSSepherosa Ziehau const struct ieee80211_rateset *rs = &ni->ni_rates; 550*841ab66cSSepherosa Ziehau /* NB: assumes rate set is sorted (happens on frame receive) */ 551*841ab66cSSepherosa Ziehau return rs->rs_rates[rs->rs_nrates-1] & IEEE80211_RATE_VAL; 552*841ab66cSSepherosa Ziehau } 553*841ab66cSSepherosa Ziehau 554*841ab66cSSepherosa Ziehau /* 555*841ab66cSSepherosa Ziehau * Compare the capabilities of two nodes and decide which is 556*841ab66cSSepherosa Ziehau * more desirable (return >0 if a is considered better). Note 557*841ab66cSSepherosa Ziehau * that we assume compatibility/usability has already been checked 558*841ab66cSSepherosa Ziehau * so we don't need to (e.g. validate whether privacy is supported). 559*841ab66cSSepherosa Ziehau * Used to select the best scan candidate for association in a BSS. 560*841ab66cSSepherosa Ziehau */ 561*841ab66cSSepherosa Ziehau static int 562*841ab66cSSepherosa Ziehau ieee80211_node_compare(struct ieee80211com *ic, 563*841ab66cSSepherosa Ziehau const struct ieee80211_node *a, 564*841ab66cSSepherosa Ziehau const struct ieee80211_node *b) 565*841ab66cSSepherosa Ziehau { 566*841ab66cSSepherosa Ziehau #define ABS(a) ((a) < 0 ? -(a) : (a)) 567*841ab66cSSepherosa Ziehau uint8_t maxa, maxb; 568*841ab66cSSepherosa Ziehau uint8_t rssia, rssib; 569*841ab66cSSepherosa Ziehau int weight; 570*841ab66cSSepherosa Ziehau 571*841ab66cSSepherosa Ziehau /* privacy support preferred */ 572*841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) && 573*841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 574*841ab66cSSepherosa Ziehau return 1; 575*841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0 && 576*841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)) 577*841ab66cSSepherosa Ziehau return -1; 578*841ab66cSSepherosa Ziehau 579*841ab66cSSepherosa Ziehau /* compare count of previous failures */ 580*841ab66cSSepherosa Ziehau weight = b->ni_fails - a->ni_fails; 581*841ab66cSSepherosa Ziehau if (ABS(weight) > 1) 582*841ab66cSSepherosa Ziehau return weight; 583*841ab66cSSepherosa Ziehau 584*841ab66cSSepherosa Ziehau rssia = ic->ic_node_getrssi(a); 585*841ab66cSSepherosa Ziehau rssib = ic->ic_node_getrssi(b); 586*841ab66cSSepherosa Ziehau if (ABS(rssib - rssia) < 5) { 587*841ab66cSSepherosa Ziehau /* best/max rate preferred if signal level close enough XXX */ 588*841ab66cSSepherosa Ziehau maxa = maxrate(a); 589*841ab66cSSepherosa Ziehau maxb = maxrate(b); 590*841ab66cSSepherosa Ziehau if (maxa != maxb) 591*841ab66cSSepherosa Ziehau return maxa - maxb; 592*841ab66cSSepherosa Ziehau /* XXX use freq for channel preference */ 593*841ab66cSSepherosa Ziehau /* for now just prefer 5Ghz band to all other bands */ 594*841ab66cSSepherosa Ziehau if (IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 595*841ab66cSSepherosa Ziehau !IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 596*841ab66cSSepherosa Ziehau return 1; 597*841ab66cSSepherosa Ziehau if (!IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 598*841ab66cSSepherosa Ziehau IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 599*841ab66cSSepherosa Ziehau return -1; 600*841ab66cSSepherosa Ziehau } 601*841ab66cSSepherosa Ziehau /* all things being equal, use signal level */ 602*841ab66cSSepherosa Ziehau return rssia - rssib; 603*841ab66cSSepherosa Ziehau #undef ABS 604*841ab66cSSepherosa Ziehau } 605*841ab66cSSepherosa Ziehau 606*841ab66cSSepherosa Ziehau /* 607*841ab66cSSepherosa Ziehau * Mark an ongoing scan stopped. 608*841ab66cSSepherosa Ziehau */ 609*841ab66cSSepherosa Ziehau void 610*841ab66cSSepherosa Ziehau ieee80211_cancel_scan(struct ieee80211com *ic) 611*841ab66cSSepherosa Ziehau { 612*841ab66cSSepherosa Ziehau 613*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s: end %s scan\n", 614*841ab66cSSepherosa Ziehau __func__, 615*841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); 616*841ab66cSSepherosa Ziehau 617*841ab66cSSepherosa Ziehau ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN); 618*841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 619*841ab66cSSepherosa Ziehau } 620*841ab66cSSepherosa Ziehau 621f186073cSJoerg Sonnenberger /* 622f186073cSJoerg Sonnenberger * Complete a scan of potential channels. 623f186073cSJoerg Sonnenberger */ 624f186073cSJoerg Sonnenberger void 625*841ab66cSSepherosa Ziehau ieee80211_end_scan(struct ieee80211com *ic) 626f186073cSJoerg Sonnenberger { 627*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 628*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *selbs; 629f186073cSJoerg Sonnenberger 630*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 631*841ab66cSSepherosa Ziehau 632*841ab66cSSepherosa Ziehau ieee80211_cancel_scan(ic); 633*841ab66cSSepherosa Ziehau ieee80211_notify_scan_done(ic); 634f186073cSJoerg Sonnenberger 635f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 636*841ab66cSSepherosa Ziehau uint8_t maxrssi[IEEE80211_CHAN_MAX]; /* XXX off stack? */ 637*841ab66cSSepherosa Ziehau int i, bestchan; 638*841ab66cSSepherosa Ziehau uint8_t rssi; 639*841ab66cSSepherosa Ziehau 640f186073cSJoerg Sonnenberger /* 641f186073cSJoerg Sonnenberger * The passive scan to look for existing AP's completed, 642f186073cSJoerg Sonnenberger * select a channel to camp on. Identify the channels 643f186073cSJoerg Sonnenberger * that already have one or more AP's and try to locate 644*841ab66cSSepherosa Ziehau * an unoccupied one. If that fails, pick a channel that 645*841ab66cSSepherosa Ziehau * looks to be quietest. 646f186073cSJoerg Sonnenberger */ 647*841ab66cSSepherosa Ziehau memset(maxrssi, 0, sizeof(maxrssi)); 648*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 649*841ab66cSSepherosa Ziehau rssi = ic->ic_node_getrssi(ni); 650*841ab66cSSepherosa Ziehau i = ieee80211_chan2ieee(ic, ni->ni_chan); 651*841ab66cSSepherosa Ziehau if (rssi > maxrssi[i]) 652*841ab66cSSepherosa Ziehau maxrssi[i] = rssi; 653f186073cSJoerg Sonnenberger } 654*841ab66cSSepherosa Ziehau /* XXX select channel more intelligently */ 655*841ab66cSSepherosa Ziehau bestchan = -1; 656f186073cSJoerg Sonnenberger for (i = 0; i < IEEE80211_CHAN_MAX; i++) 657*841ab66cSSepherosa Ziehau if (isset(ic->ic_chan_active, i)) { 658*841ab66cSSepherosa Ziehau /* 659*841ab66cSSepherosa Ziehau * If the channel is unoccupied the max rssi 660*841ab66cSSepherosa Ziehau * should be zero; just take it. Otherwise 661*841ab66cSSepherosa Ziehau * track the channel with the lowest rssi and 662*841ab66cSSepherosa Ziehau * use that when all channels appear occupied. 663*841ab66cSSepherosa Ziehau */ 664*841ab66cSSepherosa Ziehau if (maxrssi[i] == 0) { 665*841ab66cSSepherosa Ziehau bestchan = i; 666f186073cSJoerg Sonnenberger break; 667f186073cSJoerg Sonnenberger } 668*841ab66cSSepherosa Ziehau if (bestchan == -1 || 669*841ab66cSSepherosa Ziehau maxrssi[i] < maxrssi[bestchan]) 670*841ab66cSSepherosa Ziehau bestchan = i; 671*841ab66cSSepherosa Ziehau } 672*841ab66cSSepherosa Ziehau if (bestchan != -1) { 673*841ab66cSSepherosa Ziehau ieee80211_create_ibss(ic, &ic->ic_channels[bestchan]); 674f186073cSJoerg Sonnenberger return; 675f186073cSJoerg Sonnenberger } 676*841ab66cSSepherosa Ziehau /* no suitable channel, should not happen */ 677*841ab66cSSepherosa Ziehau } 678*841ab66cSSepherosa Ziehau 679*841ab66cSSepherosa Ziehau /* 680*841ab66cSSepherosa Ziehau * When manually sequencing the state machine; scan just once 681*841ab66cSSepherosa Ziehau * regardless of whether we have a candidate or not. The 682*841ab66cSSepherosa Ziehau * controlling application is expected to setup state and 683*841ab66cSSepherosa Ziehau * initiate an association. 684*841ab66cSSepherosa Ziehau */ 685*841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_MANUAL) 686*841ab66cSSepherosa Ziehau return; 687*841ab66cSSepherosa Ziehau /* 688*841ab66cSSepherosa Ziehau * Automatic sequencing; look for a candidate and 689*841ab66cSSepherosa Ziehau * if found join the network. 690*841ab66cSSepherosa Ziehau */ 691*841ab66cSSepherosa Ziehau /* NB: unlocked read should be ok */ 692*841ab66cSSepherosa Ziehau if (TAILQ_FIRST(&nt->nt_node) == NULL) { 693*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 694*841ab66cSSepherosa Ziehau "%s: no scan candidate\n", __func__); 695f186073cSJoerg Sonnenberger notfound: 696f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS && 697f186073cSJoerg Sonnenberger (ic->ic_flags & IEEE80211_F_IBSSON) && 698f186073cSJoerg Sonnenberger ic->ic_des_esslen != 0) { 699f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_ibss_chan); 700f186073cSJoerg Sonnenberger return; 701f186073cSJoerg Sonnenberger } 702f186073cSJoerg Sonnenberger /* 703*841ab66cSSepherosa Ziehau * Decrement the failure counts so entries will be 704*841ab66cSSepherosa Ziehau * reconsidered the next time around. We really want 705*841ab66cSSepherosa Ziehau * to do this only for sta's where we've previously 706*841ab66cSSepherosa Ziehau * had some success. 707*841ab66cSSepherosa Ziehau */ 708*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 709*841ab66cSSepherosa Ziehau if (ni->ni_fails) 710*841ab66cSSepherosa Ziehau ni->ni_fails--; 711*841ab66cSSepherosa Ziehau /* 712f186073cSJoerg Sonnenberger * Reset the list of channels to scan and start again. 713f186073cSJoerg Sonnenberger */ 714*841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 715*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 716*841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 717f186073cSJoerg Sonnenberger return; 718f186073cSJoerg Sonnenberger } 719f186073cSJoerg Sonnenberger selbs = NULL; 720*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "\t%s\n", 721*841ab66cSSepherosa Ziehau "macaddr bssid chan rssi rate flag wep essid"); 722*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 723*841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) == 0) { 724f186073cSJoerg Sonnenberger if (selbs == NULL) 725f186073cSJoerg Sonnenberger selbs = ni; 726*841ab66cSSepherosa Ziehau else if (ieee80211_node_compare(ic, ni, selbs) > 0) 727f186073cSJoerg Sonnenberger selbs = ni; 728f186073cSJoerg Sonnenberger } 729f186073cSJoerg Sonnenberger } 730*841ab66cSSepherosa Ziehau if (selbs != NULL) /* NB: grab ref while dropping lock */ 731*841ab66cSSepherosa Ziehau ieee80211_ref_node(selbs); 732f186073cSJoerg Sonnenberger if (selbs == NULL) 733f186073cSJoerg Sonnenberger goto notfound; 734*841ab66cSSepherosa Ziehau if (!ieee80211_sta_join(ic, selbs)) { 735*841ab66cSSepherosa Ziehau ieee80211_free_node(selbs); 736*841ab66cSSepherosa Ziehau goto notfound; 737*841ab66cSSepherosa Ziehau } 738*841ab66cSSepherosa Ziehau } 739*841ab66cSSepherosa Ziehau 740*841ab66cSSepherosa Ziehau /* 741*841ab66cSSepherosa Ziehau * Handle 802.11 ad hoc network merge. The 742*841ab66cSSepherosa Ziehau * convention, set by the Wireless Ethernet Compatibility Alliance 743*841ab66cSSepherosa Ziehau * (WECA), is that an 802.11 station will change its BSSID to match 744*841ab66cSSepherosa Ziehau * the "oldest" 802.11 ad hoc network, on the same channel, that 745*841ab66cSSepherosa Ziehau * has the station's desired SSID. The "oldest" 802.11 network 746*841ab66cSSepherosa Ziehau * sends beacons with the greatest TSF timestamp. 747*841ab66cSSepherosa Ziehau * 748*841ab66cSSepherosa Ziehau * The caller is assumed to validate TSF's before attempting a merge. 749*841ab66cSSepherosa Ziehau * 750*841ab66cSSepherosa Ziehau * Return !0 if the BSSID changed, 0 otherwise. 751*841ab66cSSepherosa Ziehau */ 752*841ab66cSSepherosa Ziehau int 753*841ab66cSSepherosa Ziehau ieee80211_ibss_merge(struct ieee80211_node *ni) 754*841ab66cSSepherosa Ziehau { 755*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 756*841ab66cSSepherosa Ziehau 757*841ab66cSSepherosa Ziehau if (ni == ic->ic_bss || 758*841ab66cSSepherosa Ziehau IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { 759*841ab66cSSepherosa Ziehau /* unchanged, nothing to do */ 760*841ab66cSSepherosa Ziehau return 0; 761*841ab66cSSepherosa Ziehau } 762*841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) != 0) { /* capabilities mismatch */ 763*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 764*841ab66cSSepherosa Ziehau "%s: merge failed, capabilities mismatch\n", __func__); 765*841ab66cSSepherosa Ziehau ic->ic_stats.is_ibss_capmismatch++; 766*841ab66cSSepherosa Ziehau return 0; 767*841ab66cSSepherosa Ziehau } 768*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 769*841ab66cSSepherosa Ziehau "%6D: new bssid %s: %s preamble, %s slot time%s\n", __func__, 770*841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 771*841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 772*841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 773*841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 774*841ab66cSSepherosa Ziehau ); 775*841ab66cSSepherosa Ziehau return ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 776*841ab66cSSepherosa Ziehau } 777*841ab66cSSepherosa Ziehau 778*841ab66cSSepherosa Ziehau /* 779*841ab66cSSepherosa Ziehau * Join the specified IBSS/BSS network. The node is assumed to 780*841ab66cSSepherosa Ziehau * be passed in with a held reference. 781*841ab66cSSepherosa Ziehau */ 782*841ab66cSSepherosa Ziehau int 783*841ab66cSSepherosa Ziehau ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) 784*841ab66cSSepherosa Ziehau { 785*841ab66cSSepherosa Ziehau struct ieee80211_node *obss; 786*841ab66cSSepherosa Ziehau 787*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 788*841ab66cSSepherosa Ziehau 789f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 790*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 791f186073cSJoerg Sonnenberger /* 792*841ab66cSSepherosa Ziehau * Delete unusable rates; we've already checked 793*841ab66cSSepherosa Ziehau * that the negotiated rate set is acceptable. 794f186073cSJoerg Sonnenberger */ 795*841ab66cSSepherosa Ziehau ieee80211_fix_rate(selbs, IEEE80211_F_DODEL); 796*841ab66cSSepherosa Ziehau /* 797*841ab66cSSepherosa Ziehau * Fillin the neighbor table; it will already 798*841ab66cSSepherosa Ziehau * exist if we are simply switching mastership. 799*841ab66cSSepherosa Ziehau * XXX ic_sta always setup so this is unnecessary? 800*841ab66cSSepherosa Ziehau */ 801*841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 802*841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 803*841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 804f186073cSJoerg Sonnenberger } 805*841ab66cSSepherosa Ziehau 806*841ab66cSSepherosa Ziehau /* 807*841ab66cSSepherosa Ziehau * Committed to selbs, setup state. 808*841ab66cSSepherosa Ziehau */ 809*841ab66cSSepherosa Ziehau obss = ic->ic_bss; 810*841ab66cSSepherosa Ziehau ic->ic_bss = selbs; /* NB: caller assumed to bump refcnt */ 811*841ab66cSSepherosa Ziehau if (obss != NULL) { 812*841ab66cSSepherosa Ziehau copy_bss(selbs, obss); 813*841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 814*841ab66cSSepherosa Ziehau } 815*841ab66cSSepherosa Ziehau /* 816*841ab66cSSepherosa Ziehau * Set the erp state (mostly the slot time) to deal with 817*841ab66cSSepherosa Ziehau * the auto-select case; this should be redundant if the 818*841ab66cSSepherosa Ziehau * mode is locked. 819*841ab66cSSepherosa Ziehau */ 820*841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan); 821*841ab66cSSepherosa Ziehau ic->ic_curchan = selbs->ni_chan; 822*841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 823*841ab66cSSepherosa Ziehau ieee80211_wme_initparams(ic); 824*841ab66cSSepherosa Ziehau 825*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA) 826*841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 827*841ab66cSSepherosa Ziehau else 828*841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 829*841ab66cSSepherosa Ziehau return 1; 830*841ab66cSSepherosa Ziehau } 831*841ab66cSSepherosa Ziehau 832*841ab66cSSepherosa Ziehau /* 833*841ab66cSSepherosa Ziehau * Leave the specified IBSS/BSS network. The node is assumed to 834*841ab66cSSepherosa Ziehau * be passed in with a held reference. 835*841ab66cSSepherosa Ziehau */ 836*841ab66cSSepherosa Ziehau void 837*841ab66cSSepherosa Ziehau ieee80211_sta_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 838*841ab66cSSepherosa Ziehau { 839*841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 840*841ab66cSSepherosa Ziehau ieee80211_notify_node_leave(ic, ni); 841f186073cSJoerg Sonnenberger } 842f186073cSJoerg Sonnenberger 843f186073cSJoerg Sonnenberger static struct ieee80211_node * 844*841ab66cSSepherosa Ziehau node_alloc(struct ieee80211_node_table *nt) 845f186073cSJoerg Sonnenberger { 846f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 847*841ab66cSSepherosa Ziehau 848*841ab66cSSepherosa Ziehau ni = malloc(sizeof(struct ieee80211_node), M_80211_NODE, 849*841ab66cSSepherosa Ziehau M_NOWAIT | M_ZERO); 850f186073cSJoerg Sonnenberger return ni; 851f186073cSJoerg Sonnenberger } 852f186073cSJoerg Sonnenberger 853*841ab66cSSepherosa Ziehau /* 854*841ab66cSSepherosa Ziehau * Reclaim any resources in a node and reset any critical 855*841ab66cSSepherosa Ziehau * state. Typically nodes are free'd immediately after, 856*841ab66cSSepherosa Ziehau * but in some cases the storage may be reused so we need 857*841ab66cSSepherosa Ziehau * to insure consistent state (should probably fix that). 858*841ab66cSSepherosa Ziehau */ 859f186073cSJoerg Sonnenberger static void 860*841ab66cSSepherosa Ziehau node_cleanup(struct ieee80211_node *ni) 861f186073cSJoerg Sonnenberger { 862*841ab66cSSepherosa Ziehau #define N(a) (sizeof(a)/sizeof(a[0])) 863*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 864*841ab66cSSepherosa Ziehau int i, qlen; 865*841ab66cSSepherosa Ziehau 866*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 867*841ab66cSSepherosa Ziehau 868*841ab66cSSepherosa Ziehau /* NB: preserve ni_table */ 869*841ab66cSSepherosa Ziehau if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 870*841ab66cSSepherosa Ziehau ic->ic_ps_sta--; 871*841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 872*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, 873*841ab66cSSepherosa Ziehau "[%6D] power save mode off, %u sta's in ps mode\n", 874*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_ps_sta); 875*841ab66cSSepherosa Ziehau } 876*841ab66cSSepherosa Ziehau /* 877*841ab66cSSepherosa Ziehau * Clear AREF flag that marks the authorization refcnt bump 878*841ab66cSSepherosa Ziehau * has happened. This is probably not needed as the node 879*841ab66cSSepherosa Ziehau * should always be removed from the table so not found but 880*841ab66cSSepherosa Ziehau * do it just in case. 881*841ab66cSSepherosa Ziehau */ 882*841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AREF; 883*841ab66cSSepherosa Ziehau 884*841ab66cSSepherosa Ziehau /* 885*841ab66cSSepherosa Ziehau * Drain power save queue and, if needed, clear TIM. 886*841ab66cSSepherosa Ziehau */ 887*841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DRAIN(ni, qlen); 888*841ab66cSSepherosa Ziehau if (qlen != 0 && ic->ic_set_tim != NULL) 889*841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 890*841ab66cSSepherosa Ziehau 891*841ab66cSSepherosa Ziehau ni->ni_associd = 0; 892*841ab66cSSepherosa Ziehau if (ni->ni_challenge != NULL) { 893*841ab66cSSepherosa Ziehau free(ni->ni_challenge, M_DEVBUF); 894*841ab66cSSepherosa Ziehau ni->ni_challenge = NULL; 895*841ab66cSSepherosa Ziehau } 896*841ab66cSSepherosa Ziehau /* 897*841ab66cSSepherosa Ziehau * Preserve SSID, WPA, and WME ie's so the bss node is 898*841ab66cSSepherosa Ziehau * reusable during a re-auth/re-assoc state transition. 899*841ab66cSSepherosa Ziehau * If we remove these data they will not be recreated 900*841ab66cSSepherosa Ziehau * because they come from a probe-response or beacon frame 901*841ab66cSSepherosa Ziehau * which cannot be expected prior to the association-response. 902*841ab66cSSepherosa Ziehau * This should not be an issue when operating in other modes 903*841ab66cSSepherosa Ziehau * as stations leaving always go through a full state transition 904*841ab66cSSepherosa Ziehau * which will rebuild this state. 905*841ab66cSSepherosa Ziehau * 906*841ab66cSSepherosa Ziehau * XXX does this leave us open to inheriting old state? 907*841ab66cSSepherosa Ziehau */ 908*841ab66cSSepherosa Ziehau for (i = 0; i < N(ni->ni_rxfrag); i++) 909*841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[i] != NULL) { 910*841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[i]); 911*841ab66cSSepherosa Ziehau ni->ni_rxfrag[i] = NULL; 912*841ab66cSSepherosa Ziehau } 913*841ab66cSSepherosa Ziehau /* 914*841ab66cSSepherosa Ziehau * Must be careful here to remove any key map entry w/o a LOR. 915*841ab66cSSepherosa Ziehau */ 916*841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(ni); 917*841ab66cSSepherosa Ziehau #undef N 918f186073cSJoerg Sonnenberger } 919f186073cSJoerg Sonnenberger 920f186073cSJoerg Sonnenberger static void 921*841ab66cSSepherosa Ziehau node_free(struct ieee80211_node *ni) 922f186073cSJoerg Sonnenberger { 923*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 924*841ab66cSSepherosa Ziehau 925*841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 926*841ab66cSSepherosa Ziehau if (ni->ni_wpa_ie != NULL) 927*841ab66cSSepherosa Ziehau free(ni->ni_wpa_ie, M_DEVBUF); 928*841ab66cSSepherosa Ziehau if (ni->ni_wme_ie != NULL) 929*841ab66cSSepherosa Ziehau free(ni->ni_wme_ie, M_DEVBUF); 930*841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DESTROY(ni); 931*841ab66cSSepherosa Ziehau free(ni, M_80211_NODE); 932f186073cSJoerg Sonnenberger } 933f186073cSJoerg Sonnenberger 934f186073cSJoerg Sonnenberger static uint8_t 935*841ab66cSSepherosa Ziehau node_getrssi(const struct ieee80211_node *ni) 936f186073cSJoerg Sonnenberger { 937f186073cSJoerg Sonnenberger return ni->ni_rssi; 938f186073cSJoerg Sonnenberger } 939f186073cSJoerg Sonnenberger 940f186073cSJoerg Sonnenberger static void 941*841ab66cSSepherosa Ziehau ieee80211_setup_node(struct ieee80211_node_table *nt, 942*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, const uint8_t *macaddr) 943f186073cSJoerg Sonnenberger { 944*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 945f186073cSJoerg Sonnenberger int hash; 946f186073cSJoerg Sonnenberger 947*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 948*841ab66cSSepherosa Ziehau 949*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 950*841ab66cSSepherosa Ziehau "%6D %p<%s> in %s table\n", __func__, ni, 951*841ab66cSSepherosa Ziehau macaddr, ":", nt->nt_name); 952*841ab66cSSepherosa Ziehau 953f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 954f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 955*841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 956*841ab66cSSepherosa Ziehau ni->ni_chan = IEEE80211_CHAN_ANYC; 957*841ab66cSSepherosa Ziehau ni->ni_authmode = IEEE80211_AUTH_OPEN; 958*841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 959*841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 960*841ab66cSSepherosa Ziehau ni->ni_inact_reload = nt->nt_inact_init; 961*841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 962*841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 963*841ab66cSSepherosa Ziehau 964*841ab66cSSepherosa Ziehau TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 965*841ab66cSSepherosa Ziehau LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 966*841ab66cSSepherosa Ziehau ni->ni_table = nt; 967*841ab66cSSepherosa Ziehau ni->ni_ic = ic; 968f186073cSJoerg Sonnenberger } 969f186073cSJoerg Sonnenberger 970f186073cSJoerg Sonnenberger struct ieee80211_node * 971*841ab66cSSepherosa Ziehau ieee80211_alloc_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 972f186073cSJoerg Sonnenberger { 973*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 974*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 975*841ab66cSSepherosa Ziehau 976*841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 977f186073cSJoerg Sonnenberger if (ni != NULL) 978*841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 979f186073cSJoerg Sonnenberger else 980f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 981f186073cSJoerg Sonnenberger return ni; 982f186073cSJoerg Sonnenberger } 983f186073cSJoerg Sonnenberger 984*841ab66cSSepherosa Ziehau /* 985*841ab66cSSepherosa Ziehau * Craft a temporary node suitable for sending a management frame 986*841ab66cSSepherosa Ziehau * to the specified station. We craft only as much state as we 987*841ab66cSSepherosa Ziehau * need to do the work since the node will be immediately reclaimed 988*841ab66cSSepherosa Ziehau * once the send completes. 989*841ab66cSSepherosa Ziehau */ 990f186073cSJoerg Sonnenberger struct ieee80211_node * 991*841ab66cSSepherosa Ziehau ieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr) 992f186073cSJoerg Sonnenberger { 993*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 994*841ab66cSSepherosa Ziehau 995*841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(&ic->ic_sta); 996f186073cSJoerg Sonnenberger if (ni != NULL) { 997*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 998*841ab66cSSepherosa Ziehau "%s %p<%6D>\n", __func__, ni, macaddr, ":"); 999*841ab66cSSepherosa Ziehau 1000*841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1001*841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1002*841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 1003*841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1004*841ab66cSSepherosa Ziehau /* NB: required by ieee80211_fix_rate */ 1005*841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1006*841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, 1007*841ab66cSSepherosa Ziehau IEEE80211_KEYIX_NONE); 1008*841ab66cSSepherosa Ziehau /* XXX optimize away */ 1009*841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 1010*841ab66cSSepherosa Ziehau 1011*841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* NB: pedantic */ 1012*841ab66cSSepherosa Ziehau ni->ni_ic = ic; 1013*841ab66cSSepherosa Ziehau } else { 1014*841ab66cSSepherosa Ziehau /* XXX msg */ 1015*841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1016*841ab66cSSepherosa Ziehau } 1017*841ab66cSSepherosa Ziehau return ni; 1018*841ab66cSSepherosa Ziehau } 1019*841ab66cSSepherosa Ziehau 1020*841ab66cSSepherosa Ziehau struct ieee80211_node * 1021*841ab66cSSepherosa Ziehau ieee80211_dup_bss(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1022*841ab66cSSepherosa Ziehau { 1023*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1024*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1025*841ab66cSSepherosa Ziehau 1026*841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1027*841ab66cSSepherosa Ziehau if (ni != NULL) { 1028*841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 1029f186073cSJoerg Sonnenberger /* 1030f186073cSJoerg Sonnenberger * Inherit from ic_bss. 1031f186073cSJoerg Sonnenberger */ 1032*841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1033*841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1034*841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1035f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1036*841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1037*841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1038f186073cSJoerg Sonnenberger } else 1039f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 1040f186073cSJoerg Sonnenberger return ni; 1041f186073cSJoerg Sonnenberger } 1042f186073cSJoerg Sonnenberger 1043f186073cSJoerg Sonnenberger static struct ieee80211_node * 1044*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1045*841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1046*841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1047*841ab66cSSepherosa Ziehau #else 1048*841ab66cSSepherosa Ziehau _ieee80211_find_node(struct ieee80211_node_table *nt, 1049*841ab66cSSepherosa Ziehau const uint8_t *macaddr) 1050*841ab66cSSepherosa Ziehau #endif 1051f186073cSJoerg Sonnenberger { 1052f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1053f186073cSJoerg Sonnenberger int hash; 1054f186073cSJoerg Sonnenberger 1055f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1056*841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1057f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1058*841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1059*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1060*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1061*841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1062*841ab66cSSepherosa Ziehau func, line, 1063*841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1064*841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1065*841ab66cSSepherosa Ziehau #endif 1066f186073cSJoerg Sonnenberger return ni; 1067f186073cSJoerg Sonnenberger } 1068f186073cSJoerg Sonnenberger } 1069f186073cSJoerg Sonnenberger return NULL; 1070f186073cSJoerg Sonnenberger } 1071*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1072*841ab66cSSepherosa Ziehau #define _ieee80211_find_node(nt, mac) \ 1073*841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(nt, mac, func, line) 1074*841ab66cSSepherosa Ziehau #endif 1075f186073cSJoerg Sonnenberger 1076f186073cSJoerg Sonnenberger struct ieee80211_node * 1077*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1078*841ab66cSSepherosa Ziehau ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1079*841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1080*841ab66cSSepherosa Ziehau #else 1081*841ab66cSSepherosa Ziehau ieee80211_find_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1082*841ab66cSSepherosa Ziehau #endif 1083f186073cSJoerg Sonnenberger { 1084f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1085f186073cSJoerg Sonnenberger 1086*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1087*841ab66cSSepherosa Ziehau 1088*841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1089f186073cSJoerg Sonnenberger return ni; 1090f186073cSJoerg Sonnenberger } 1091f186073cSJoerg Sonnenberger 1092f186073cSJoerg Sonnenberger /* 1093*841ab66cSSepherosa Ziehau * Fake up a node; this handles node discovery in adhoc mode. 1094*841ab66cSSepherosa Ziehau * Note that for the driver's benefit we we treat this like 1095*841ab66cSSepherosa Ziehau * an association so the driver has an opportunity to setup 1096*841ab66cSSepherosa Ziehau * it's private state. 1097*841ab66cSSepherosa Ziehau */ 1098*841ab66cSSepherosa Ziehau struct ieee80211_node * 1099*841ab66cSSepherosa Ziehau ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, 1100*841ab66cSSepherosa Ziehau const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1101*841ab66cSSepherosa Ziehau { 1102*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1103*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1104*841ab66cSSepherosa Ziehau 1105*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1106*841ab66cSSepherosa Ziehau "%s: mac<%6D>\n", __func__, macaddr, ":"); 1107*841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(nt, macaddr); 1108*841ab66cSSepherosa Ziehau if (ni != NULL) { 1109*841ab66cSSepherosa Ziehau /* XXX no rate negotiation; just dup */ 1110*841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_bss->ni_rates; 1111*841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1112*841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1113*841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1114*841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1115*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 1116*841ab66cSSepherosa Ziehau /* 1117*841ab66cSSepherosa Ziehau * Blindly propagate capabilities based on the 1118*841ab66cSSepherosa Ziehau * local configuration. In particular this permits 1119*841ab66cSSepherosa Ziehau * us to use QoS to disable ACK's. 1120*841ab66cSSepherosa Ziehau */ 1121*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_WME) 1122*841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_QOS; 1123*841ab66cSSepherosa Ziehau } 1124*841ab66cSSepherosa Ziehau } 1125*841ab66cSSepherosa Ziehau return ni; 1126*841ab66cSSepherosa Ziehau } 1127*841ab66cSSepherosa Ziehau 1128*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1129*841ab66cSSepherosa Ziehau static void 1130*841ab66cSSepherosa Ziehau dump_probe_beacon(uint8_t subtype, int isnew, 1131*841ab66cSSepherosa Ziehau const uint8_t mac[IEEE80211_ADDR_LEN], 1132*841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1133*841ab66cSSepherosa Ziehau { 1134*841ab66cSSepherosa Ziehau 1135*841ab66cSSepherosa Ziehau printf("[%6D] %s%s on chan %u (bss chan %u) ", 1136*841ab66cSSepherosa Ziehau mac, ":", isnew ? "new " : "", 1137*841ab66cSSepherosa Ziehau ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], 1138*841ab66cSSepherosa Ziehau sp->chan, sp->bchan); 1139*841ab66cSSepherosa Ziehau ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); 1140*841ab66cSSepherosa Ziehau printf("\n"); 1141*841ab66cSSepherosa Ziehau 1142*841ab66cSSepherosa Ziehau if (isnew) { 1143*841ab66cSSepherosa Ziehau printf("[%6D] caps 0x%x bintval %u erp 0x%x", 1144*841ab66cSSepherosa Ziehau mac, ":", sp->capinfo, sp->bintval, sp->erp); 1145*841ab66cSSepherosa Ziehau if (sp->country != NULL) { 1146*841ab66cSSepherosa Ziehau #if defined(__FreeBSD__) || defined(__DragonFly__) 1147*841ab66cSSepherosa Ziehau printf(" country info %*D", 1148*841ab66cSSepherosa Ziehau sp->country[1], sp->country+2, " "); 1149*841ab66cSSepherosa Ziehau #else 1150*841ab66cSSepherosa Ziehau int i; 1151*841ab66cSSepherosa Ziehau printf(" country info"); 1152*841ab66cSSepherosa Ziehau for (i = 0; i < sp->country[1]; i++) 1153*841ab66cSSepherosa Ziehau printf(" %02x", sp->country[i+2]); 1154*841ab66cSSepherosa Ziehau #endif 1155*841ab66cSSepherosa Ziehau } 1156*841ab66cSSepherosa Ziehau printf("\n"); 1157*841ab66cSSepherosa Ziehau } 1158*841ab66cSSepherosa Ziehau } 1159*841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 1160*841ab66cSSepherosa Ziehau 1161*841ab66cSSepherosa Ziehau static void 1162*841ab66cSSepherosa Ziehau saveie(uint8_t **iep, const uint8_t *ie) 1163*841ab66cSSepherosa Ziehau { 1164*841ab66cSSepherosa Ziehau 1165*841ab66cSSepherosa Ziehau if (ie == NULL) 1166*841ab66cSSepherosa Ziehau *iep = NULL; 1167*841ab66cSSepherosa Ziehau else 1168*841ab66cSSepherosa Ziehau ieee80211_saveie(iep, ie); 1169*841ab66cSSepherosa Ziehau } 1170*841ab66cSSepherosa Ziehau 1171*841ab66cSSepherosa Ziehau /* 1172*841ab66cSSepherosa Ziehau * Process a beacon or probe response frame. 1173*841ab66cSSepherosa Ziehau */ 1174*841ab66cSSepherosa Ziehau void 1175*841ab66cSSepherosa Ziehau ieee80211_add_scan(struct ieee80211com *ic, 1176*841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp, 1177*841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1178*841ab66cSSepherosa Ziehau int subtype, int rssi, int rstamp) 1179*841ab66cSSepherosa Ziehau { 1180*841ab66cSSepherosa Ziehau #define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1181*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 1182*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1183*841ab66cSSepherosa Ziehau int newnode = 0; 1184*841ab66cSSepherosa Ziehau 1185*841ab66cSSepherosa Ziehau ni = ieee80211_find_node(nt, wh->i_addr2); 1186*841ab66cSSepherosa Ziehau if (ni == NULL) { 1187*841ab66cSSepherosa Ziehau /* 1188*841ab66cSSepherosa Ziehau * Create a new entry. 1189*841ab66cSSepherosa Ziehau */ 1190*841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1191*841ab66cSSepherosa Ziehau if (ni == NULL) { 1192*841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1193*841ab66cSSepherosa Ziehau return; 1194*841ab66cSSepherosa Ziehau } 1195*841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, wh->i_addr2); 1196*841ab66cSSepherosa Ziehau /* 1197*841ab66cSSepherosa Ziehau * XXX inherit from ic_bss. 1198*841ab66cSSepherosa Ziehau */ 1199*841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1200*841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1201*841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1202*841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_curchan); 1203*841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1204*841ab66cSSepherosa Ziehau newnode = 1; 1205*841ab66cSSepherosa Ziehau } 1206*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1207*841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN)) 1208*841ab66cSSepherosa Ziehau dump_probe_beacon(subtype, newnode, wh->i_addr2, sp); 1209*841ab66cSSepherosa Ziehau #endif 1210*841ab66cSSepherosa Ziehau /* XXX ap beaconing multiple ssid w/ same bssid */ 1211*841ab66cSSepherosa Ziehau if (sp->ssid[1] != 0 && 1212*841ab66cSSepherosa Ziehau (ISPROBE(subtype) || ni->ni_esslen == 0)) { 1213*841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1214*841ab66cSSepherosa Ziehau memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); 1215*841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1216*841ab66cSSepherosa Ziehau } 1217*841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1218*841ab66cSSepherosa Ziehau ni->ni_rssi = rssi; 1219*841ab66cSSepherosa Ziehau ni->ni_rstamp = rstamp; 1220*841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1221*841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1222*841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1223*841ab66cSSepherosa Ziehau ni->ni_chan = &ic->ic_channels[sp->chan]; 1224*841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1225*841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1226*841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1227*841ab66cSSepherosa Ziehau if (sp->tim != NULL) { 1228*841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *ie = 1229*841ab66cSSepherosa Ziehau (struct ieee80211_tim_ie *) sp->tim; 1230*841ab66cSSepherosa Ziehau 1231*841ab66cSSepherosa Ziehau ni->ni_dtim_count = ie->tim_count; 1232*841ab66cSSepherosa Ziehau ni->ni_dtim_period = ie->tim_period; 1233*841ab66cSSepherosa Ziehau } 1234*841ab66cSSepherosa Ziehau /* 1235*841ab66cSSepherosa Ziehau * Record the byte offset from the mac header to 1236*841ab66cSSepherosa Ziehau * the start of the TIM information element for 1237*841ab66cSSepherosa Ziehau * use by hardware and/or to speedup software 1238*841ab66cSSepherosa Ziehau * processing of beacon frames. 1239*841ab66cSSepherosa Ziehau */ 1240*841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1241*841ab66cSSepherosa Ziehau /* 1242*841ab66cSSepherosa Ziehau * Record optional information elements that might be 1243*841ab66cSSepherosa Ziehau * used by applications or drivers. 1244*841ab66cSSepherosa Ziehau */ 1245*841ab66cSSepherosa Ziehau saveie(&ni->ni_wme_ie, sp->wme); 1246*841ab66cSSepherosa Ziehau saveie(&ni->ni_wpa_ie, sp->wpa); 1247*841ab66cSSepherosa Ziehau 1248*841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1249*841ab66cSSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); 1250*841ab66cSSepherosa Ziehau 1251*841ab66cSSepherosa Ziehau if (!newnode) 1252*841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1253*841ab66cSSepherosa Ziehau #undef ISPROBE 1254*841ab66cSSepherosa Ziehau } 1255*841ab66cSSepherosa Ziehau 1256*841ab66cSSepherosa Ziehau void 1257*841ab66cSSepherosa Ziehau ieee80211_init_neighbor(struct ieee80211_node *ni, 1258*841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1259*841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1260*841ab66cSSepherosa Ziehau { 1261*841ab66cSSepherosa Ziehau 1262*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1263*841ab66cSSepherosa Ziehau "%s: %p<%s>\n", __func__, ni, ni->ni_macaddr, ":"); 1264*841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1265*841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1266*841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1267*841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1268*841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1269*841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1270*841ab66cSSepherosa Ziehau ni->ni_chan = ni->ni_ic->ic_curchan; 1271*841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1272*841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1273*841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1274*841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1275*841ab66cSSepherosa Ziehau if (sp->wme != NULL) 1276*841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wme_ie, sp->wme); 1277*841ab66cSSepherosa Ziehau if (sp->wpa != NULL) 1278*841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa); 1279*841ab66cSSepherosa Ziehau 1280*841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1281*841ab66cSSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); 1282*841ab66cSSepherosa Ziehau } 1283*841ab66cSSepherosa Ziehau 1284*841ab66cSSepherosa Ziehau /* 1285*841ab66cSSepherosa Ziehau * Do node discovery in adhoc mode on receipt of a beacon 1286*841ab66cSSepherosa Ziehau * or probe response frame. Note that for the driver's 1287*841ab66cSSepherosa Ziehau * benefit we we treat this like an association so the 1288*841ab66cSSepherosa Ziehau * driver has an opportunity to setup it's private state. 1289*841ab66cSSepherosa Ziehau */ 1290*841ab66cSSepherosa Ziehau struct ieee80211_node * 1291*841ab66cSSepherosa Ziehau ieee80211_add_neighbor(struct ieee80211com *ic, 1292*841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1293*841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1294*841ab66cSSepherosa Ziehau { 1295*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1296*841ab66cSSepherosa Ziehau 1297*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1298*841ab66cSSepherosa Ziehau "%s: mac<%s>\n", __func__, wh->i_addr2, ":"); 1299*841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */ 1300*841ab66cSSepherosa Ziehau if (ni != NULL) { 1301*841ab66cSSepherosa Ziehau ieee80211_init_neighbor(ni, wh, sp); 1302*841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1303*841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1304*841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1305*841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1306*841ab66cSSepherosa Ziehau } 1307*841ab66cSSepherosa Ziehau return ni; 1308*841ab66cSSepherosa Ziehau } 1309*841ab66cSSepherosa Ziehau 1310*841ab66cSSepherosa Ziehau #define IS_CTL(wh) \ 1311*841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 1312*841ab66cSSepherosa Ziehau #define IS_PSPOLL(wh) \ 1313*841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) 1314*841ab66cSSepherosa Ziehau /* 1315*841ab66cSSepherosa Ziehau * Locate the node for sender, track state, and then pass the 1316*841ab66cSSepherosa Ziehau * (referenced) node up to the 802.11 layer for its use. We 1317*841ab66cSSepherosa Ziehau * are required to pass some node so we fall back to ic_bss 1318*841ab66cSSepherosa Ziehau * when this frame is from an unknown sender. The 802.11 layer 1319*841ab66cSSepherosa Ziehau * knows this means the sender wasn't in the node table and 1320*841ab66cSSepherosa Ziehau * acts accordingly. 1321*841ab66cSSepherosa Ziehau */ 1322*841ab66cSSepherosa Ziehau struct ieee80211_node * 1323*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1324*841ab66cSSepherosa Ziehau ieee80211_find_rxnode_debug(struct ieee80211com *ic, 1325*841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, const char *func, int line) 1326*841ab66cSSepherosa Ziehau #else 1327*841ab66cSSepherosa Ziehau ieee80211_find_rxnode(struct ieee80211com *ic, 1328*841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh) 1329*841ab66cSSepherosa Ziehau #endif 1330*841ab66cSSepherosa Ziehau { 1331*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1332*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1333*841ab66cSSepherosa Ziehau 1334*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1335*841ab66cSSepherosa Ziehau 1336*841ab66cSSepherosa Ziehau /* XXX may want scanned nodes in the neighbor table for adhoc */ 1337*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1338*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1339*841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1340*841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1341*841ab66cSSepherosa Ziehau else 1342*841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1343*841ab66cSSepherosa Ziehau /* XXX check ic_bss first in station mode */ 1344*841ab66cSSepherosa Ziehau /* XXX 4-address frames? */ 1345*841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1346*841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1347*841ab66cSSepherosa Ziehau else 1348*841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1349*841ab66cSSepherosa Ziehau if (ni == NULL) 1350*841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1351*841ab66cSSepherosa Ziehau 1352*841ab66cSSepherosa Ziehau return ni; 1353*841ab66cSSepherosa Ziehau } 1354*841ab66cSSepherosa Ziehau 1355*841ab66cSSepherosa Ziehau /* 1356*841ab66cSSepherosa Ziehau * Like ieee80211_find_rxnode but use the supplied h/w 1357*841ab66cSSepherosa Ziehau * key index as a hint to locate the node in the key 1358*841ab66cSSepherosa Ziehau * mapping table. If an entry is present at the key 1359*841ab66cSSepherosa Ziehau * index we return it; otherwise do a normal lookup and 1360*841ab66cSSepherosa Ziehau * update the mapping table if the station has a unicast 1361*841ab66cSSepherosa Ziehau * key assigned to it. 1362*841ab66cSSepherosa Ziehau */ 1363*841ab66cSSepherosa Ziehau struct ieee80211_node * 1364*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1365*841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1366*841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1367*841ab66cSSepherosa Ziehau const char *func, int line) 1368*841ab66cSSepherosa Ziehau #else 1369*841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1370*841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1371*841ab66cSSepherosa Ziehau #endif 1372*841ab66cSSepherosa Ziehau { 1373*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1374*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1375*841ab66cSSepherosa Ziehau 1376*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1377*841ab66cSSepherosa Ziehau 1378*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1379*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1380*841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1381*841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1382*841ab66cSSepherosa Ziehau else 1383*841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1384*841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1385*841ab66cSSepherosa Ziehau ni = nt->nt_keyixmap[keyix]; 1386*841ab66cSSepherosa Ziehau else 1387*841ab66cSSepherosa Ziehau ni = NULL; 1388*841ab66cSSepherosa Ziehau if (ni == NULL) { 1389*841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1390*841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1391*841ab66cSSepherosa Ziehau else 1392*841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1393*841ab66cSSepherosa Ziehau if (ni == NULL) 1394*841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1395*841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 1396*841ab66cSSepherosa Ziehau /* 1397*841ab66cSSepherosa Ziehau * If the station has a unicast key cache slot 1398*841ab66cSSepherosa Ziehau * assigned update the key->node mapping table. 1399*841ab66cSSepherosa Ziehau */ 1400*841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1401*841ab66cSSepherosa Ziehau /* XXX can keyixmap[keyix] != NULL? */ 1402*841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1403*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == NULL) { 1404*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1405*841ab66cSSepherosa Ziehau "%s: add key map entry %p<%6D> refcnt %d\n", 1406*841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1407*841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 1408*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1409*841ab66cSSepherosa Ziehau } 1410*841ab66cSSepherosa Ziehau } 1411*841ab66cSSepherosa Ziehau } else { 1412*841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1413*841ab66cSSepherosa Ziehau } 1414*841ab66cSSepherosa Ziehau 1415*841ab66cSSepherosa Ziehau return ni; 1416*841ab66cSSepherosa Ziehau } 1417*841ab66cSSepherosa Ziehau #undef IS_PSPOLL 1418*841ab66cSSepherosa Ziehau #undef IS_CTL 1419*841ab66cSSepherosa Ziehau 1420*841ab66cSSepherosa Ziehau /* 1421f186073cSJoerg Sonnenberger * Return a reference to the appropriate node for sending 1422f186073cSJoerg Sonnenberger * a data frame. This handles node discovery in adhoc networks. 1423f186073cSJoerg Sonnenberger */ 1424f186073cSJoerg Sonnenberger struct ieee80211_node * 1425*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1426*841ab66cSSepherosa Ziehau ieee80211_find_txnode_debug(struct ieee80211com *ic, const uint8_t *macaddr, 1427*841ab66cSSepherosa Ziehau const char *func, int line) 1428*841ab66cSSepherosa Ziehau #else 1429*841ab66cSSepherosa Ziehau ieee80211_find_txnode(struct ieee80211com *ic, const uint8_t *macaddr) 1430*841ab66cSSepherosa Ziehau #endif 1431f186073cSJoerg Sonnenberger { 1432*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1433f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1434*841ab66cSSepherosa Ziehau 1435*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1436f186073cSJoerg Sonnenberger 1437f186073cSJoerg Sonnenberger /* 1438f186073cSJoerg Sonnenberger * The destination address should be in the node table 1439*841ab66cSSepherosa Ziehau * unless this is a multicast/broadcast frame. We can 1440*841ab66cSSepherosa Ziehau * also optimize station mode operation, all frames go 1441*841ab66cSSepherosa Ziehau * to the bss node. 1442f186073cSJoerg Sonnenberger */ 1443f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) 1444*841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1445*841ab66cSSepherosa Ziehau else 1446*841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1447f186073cSJoerg Sonnenberger 1448*841ab66cSSepherosa Ziehau if (ni == NULL) { 1449*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS || 1450*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO) { 1451f186073cSJoerg Sonnenberger /* 1452*841ab66cSSepherosa Ziehau * In adhoc mode cons up a node for the destination. 1453*841ab66cSSepherosa Ziehau * Note that we need an additional reference for the 1454*841ab66cSSepherosa Ziehau * caller to be consistent with _ieee80211_find_node. 1455f186073cSJoerg Sonnenberger */ 1456*841ab66cSSepherosa Ziehau ni = ieee80211_fakeup_adhoc_node(nt, macaddr); 1457*841ab66cSSepherosa Ziehau if (ni != NULL) 1458*841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1459*841ab66cSSepherosa Ziehau } else { 1460*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, 1461*841ab66cSSepherosa Ziehau "[%6D] no node, discard frame (%s)\n", 1462*841ab66cSSepherosa Ziehau macaddr, ":", __func__); 1463*841ab66cSSepherosa Ziehau ic->ic_stats.is_tx_nonode++; 1464f186073cSJoerg Sonnenberger } 1465f186073cSJoerg Sonnenberger } 1466f186073cSJoerg Sonnenberger return ni; 1467f186073cSJoerg Sonnenberger } 1468f186073cSJoerg Sonnenberger 1469f186073cSJoerg Sonnenberger /* 1470f186073cSJoerg Sonnenberger * Like find but search based on the channel too. 1471f186073cSJoerg Sonnenberger */ 1472f186073cSJoerg Sonnenberger struct ieee80211_node * 1473*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1474*841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel_debug(struct ieee80211_node_table *nt, 1475*841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan, 1476*841ab66cSSepherosa Ziehau const char *func, int line) 1477*841ab66cSSepherosa Ziehau #else 1478*841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel(struct ieee80211_node_table *nt, 1479*841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan) 1480*841ab66cSSepherosa Ziehau #endif 1481f186073cSJoerg Sonnenberger { 1482f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1483f186073cSJoerg Sonnenberger int hash; 1484*841ab66cSSepherosa Ziehau 1485*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1486f186073cSJoerg Sonnenberger 1487f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1488*841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1489f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1490f186073cSJoerg Sonnenberger ni->ni_chan == chan) { 1491*841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1492*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1493*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1494*841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1495*841ab66cSSepherosa Ziehau func, line, 1496*841ab66cSSepherosa Ziehau #else 1497*841ab66cSSepherosa Ziehau "%s %p<%6D> refcnt %d\n", __func__, 1498*841ab66cSSepherosa Ziehau #endif 1499*841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1500*841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1501f186073cSJoerg Sonnenberger break; 1502f186073cSJoerg Sonnenberger } 1503f186073cSJoerg Sonnenberger } 1504f186073cSJoerg Sonnenberger return ni; 1505f186073cSJoerg Sonnenberger } 1506f186073cSJoerg Sonnenberger 1507*841ab66cSSepherosa Ziehau /* 1508*841ab66cSSepherosa Ziehau * Like find but search based on the ssid too. 1509*841ab66cSSepherosa Ziehau */ 1510*841ab66cSSepherosa Ziehau struct ieee80211_node * 1511*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1512*841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid_debug(struct ieee80211_node_table *nt, 1513*841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid, 1514*841ab66cSSepherosa Ziehau const char *func, int line) 1515*841ab66cSSepherosa Ziehau #else 1516*841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid(struct ieee80211_node_table *nt, 1517*841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid) 1518*841ab66cSSepherosa Ziehau #endif 1519f186073cSJoerg Sonnenberger { 1520*841ab66cSSepherosa Ziehau #define MATCH_SSID(ni, ssid, ssidlen) \ 1521*841ab66cSSepherosa Ziehau (ni->ni_esslen == ssidlen && memcmp(ni->ni_essid, ssid, ssidlen) == 0) 1522*841ab66cSSepherosa Ziehau static const uint8_t zeromac[IEEE80211_ADDR_LEN]; 1523*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1524f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1525*841ab66cSSepherosa Ziehau int hash; 1526f186073cSJoerg Sonnenberger 1527*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1528*841ab66cSSepherosa Ziehau 1529*841ab66cSSepherosa Ziehau /* 1530*841ab66cSSepherosa Ziehau * A mac address that is all zero means match only the ssid; 1531*841ab66cSSepherosa Ziehau * otherwise we must match both. 1532*841ab66cSSepherosa Ziehau */ 1533*841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(macaddr, zeromac)) { 1534*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1535*841ab66cSSepherosa Ziehau if (MATCH_SSID(ni, ssid, ssidlen)) 1536*841ab66cSSepherosa Ziehau break; 1537*841ab66cSSepherosa Ziehau } 1538*841ab66cSSepherosa Ziehau } else { 1539*841ab66cSSepherosa Ziehau hash = IEEE80211_NODE_HASH(macaddr); 1540*841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1541*841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1542*841ab66cSSepherosa Ziehau MATCH_SSID(ni, ssid, ssidlen)) 1543*841ab66cSSepherosa Ziehau break; 1544*841ab66cSSepherosa Ziehau } 1545*841ab66cSSepherosa Ziehau } 1546*841ab66cSSepherosa Ziehau if (ni != NULL) { 1547*841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1548*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1549*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1550*841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1551*841ab66cSSepherosa Ziehau func, line, 1552*841ab66cSSepherosa Ziehau #else 1553*841ab66cSSepherosa Ziehau "%s %p<%6D> refcnt %d\n", __func__, 1554*841ab66cSSepherosa Ziehau #endif 1555*841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1556*841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1557*841ab66cSSepherosa Ziehau } 1558*841ab66cSSepherosa Ziehau return ni; 1559*841ab66cSSepherosa Ziehau #undef MATCH_SSID 1560*841ab66cSSepherosa Ziehau } 1561*841ab66cSSepherosa Ziehau 1562*841ab66cSSepherosa Ziehau static void 1563*841ab66cSSepherosa Ziehau _ieee80211_free_node(struct ieee80211_node *ni) 1564*841ab66cSSepherosa Ziehau { 1565*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1566*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1567*841ab66cSSepherosa Ziehau 1568*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1569*841ab66cSSepherosa Ziehau "%s %p<%6D> in %s table\n", __func__, ni, 1570*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1571*841ab66cSSepherosa Ziehau nt != NULL ? nt->nt_name : "<gone>"); 1572*841ab66cSSepherosa Ziehau 1573*841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1574*841ab66cSSepherosa Ziehau if (nt != NULL) { 1575*841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1576*841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1577*841ab66cSSepherosa Ziehau } 1578*841ab66cSSepherosa Ziehau ic->ic_node_free(ni); 1579*841ab66cSSepherosa Ziehau } 1580*841ab66cSSepherosa Ziehau 1581*841ab66cSSepherosa Ziehau void 1582*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1583*841ab66cSSepherosa Ziehau ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1584*841ab66cSSepherosa Ziehau #else 1585*841ab66cSSepherosa Ziehau ieee80211_free_node(struct ieee80211_node *ni) 1586*841ab66cSSepherosa Ziehau #endif 1587*841ab66cSSepherosa Ziehau { 1588*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1589*841ab66cSSepherosa Ziehau 1590*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ni->ni_ic->ic_ifp->if_serializer); 1591*841ab66cSSepherosa Ziehau 1592*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1593*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1594*841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, func, line, ni, 1595*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni) - 1); 1596*841ab66cSSepherosa Ziehau #endif 1597*841ab66cSSepherosa Ziehau if (nt != NULL) { 1598*841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) { 1599*841ab66cSSepherosa Ziehau /* 1600*841ab66cSSepherosa Ziehau * Last reference, reclaim state. 1601*841ab66cSSepherosa Ziehau */ 1602*841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1603*841ab66cSSepherosa Ziehau } else if (ieee80211_node_refcnt(ni) == 1 && 1604*841ab66cSSepherosa Ziehau nt->nt_keyixmap != NULL) { 1605*841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1606*841ab66cSSepherosa Ziehau /* 1607*841ab66cSSepherosa Ziehau * Check for a last reference in the key mapping table. 1608*841ab66cSSepherosa Ziehau */ 1609*841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1610*841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1611*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1612*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1613*841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry", __func__, 1614*841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":"); 1615*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1616*841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* XXX needed? */ 1617*841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1618*841ab66cSSepherosa Ziehau } 1619*841ab66cSSepherosa Ziehau } 1620*841ab66cSSepherosa Ziehau } else { 1621*841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) 1622*841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1623*841ab66cSSepherosa Ziehau } 1624f186073cSJoerg Sonnenberger } 1625f186073cSJoerg Sonnenberger 1626f186073cSJoerg Sonnenberger /* 1627*841ab66cSSepherosa Ziehau * Reclaim a unicast key and clear any key cache state. 1628*841ab66cSSepherosa Ziehau */ 1629*841ab66cSSepherosa Ziehau int 1630*841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(struct ieee80211_node *ni) 1631*841ab66cSSepherosa Ziehau { 1632*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1633*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1634*841ab66cSSepherosa Ziehau struct ieee80211_node *nikey; 1635*841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1636*841ab66cSSepherosa Ziehau int status; 1637*841ab66cSSepherosa Ziehau 1638*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1639*841ab66cSSepherosa Ziehau 1640*841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1641*841ab66cSSepherosa Ziehau status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey); 1642*841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1643*841ab66cSSepherosa Ziehau nikey = nt->nt_keyixmap[keyix]; 1644*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL;; 1645*841ab66cSSepherosa Ziehau } else 1646*841ab66cSSepherosa Ziehau nikey = NULL; 1647*841ab66cSSepherosa Ziehau 1648*841ab66cSSepherosa Ziehau if (nikey != NULL) { 1649*841ab66cSSepherosa Ziehau KASSERT(nikey == ni, 1650*841ab66cSSepherosa Ziehau ("key map out of sync, ni %p nikey %p", ni, nikey)); 1651*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1652*841ab66cSSepherosa Ziehau "%s: delete key map entry %p<%6D> refcnt %d\n", 1653*841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1654*841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)-1); 1655*841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1656*841ab66cSSepherosa Ziehau } 1657*841ab66cSSepherosa Ziehau return status; 1658*841ab66cSSepherosa Ziehau } 1659*841ab66cSSepherosa Ziehau 1660*841ab66cSSepherosa Ziehau /* 1661*841ab66cSSepherosa Ziehau * Reclaim a node. If this is the last reference count then 1662*841ab66cSSepherosa Ziehau * do the normal free work. Otherwise remove it from the node 1663*841ab66cSSepherosa Ziehau * table and mark it gone by clearing the back-reference. 1664*841ab66cSSepherosa Ziehau */ 1665*841ab66cSSepherosa Ziehau static void 1666*841ab66cSSepherosa Ziehau node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1667*841ab66cSSepherosa Ziehau { 1668*841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1669*841ab66cSSepherosa Ziehau 1670*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1671*841ab66cSSepherosa Ziehau 1672*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1673*841ab66cSSepherosa Ziehau "%s: remove %p<%6D> from %s table, refcnt %d\n", 1674*841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1675*841ab66cSSepherosa Ziehau nt->nt_name, ieee80211_node_refcnt(ni)-1); 1676*841ab66cSSepherosa Ziehau /* 1677*841ab66cSSepherosa Ziehau * Clear any entry in the unicast key mapping table. 1678*841ab66cSSepherosa Ziehau * We need to do it here so rx lookups don't find it 1679*841ab66cSSepherosa Ziehau * in the mapping table even if it's not in the hash 1680*841ab66cSSepherosa Ziehau * table. We cannot depend on the mapping table entry 1681*841ab66cSSepherosa Ziehau * being cleared because the node may not be free'd. 1682*841ab66cSSepherosa Ziehau */ 1683*841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1684*841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1685*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1686*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1687*841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry\n", 1688*841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":"); 1689*841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1690*841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* NB: don't need free */ 1691*841ab66cSSepherosa Ziehau } 1692*841ab66cSSepherosa Ziehau if (!ieee80211_node_dectestref(ni)) { 1693*841ab66cSSepherosa Ziehau /* 1694*841ab66cSSepherosa Ziehau * Other references are present, just remove the 1695*841ab66cSSepherosa Ziehau * node from the table so it cannot be found. When 1696*841ab66cSSepherosa Ziehau * the references are dropped storage will be 1697*841ab66cSSepherosa Ziehau * reclaimed. 1698*841ab66cSSepherosa Ziehau */ 1699*841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1700*841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1701*841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* clear reference */ 1702*841ab66cSSepherosa Ziehau } else 1703*841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1704*841ab66cSSepherosa Ziehau } 1705*841ab66cSSepherosa Ziehau 1706*841ab66cSSepherosa Ziehau static void 1707*841ab66cSSepherosa Ziehau ieee80211_free_allnodes(struct ieee80211_node_table *nt) 1708*841ab66cSSepherosa Ziehau { 1709*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1710*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1711*841ab66cSSepherosa Ziehau 1712*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1713*841ab66cSSepherosa Ziehau "%s: free all nodes in %s table\n", __func__, nt->nt_name); 1714*841ab66cSSepherosa Ziehau 1715*841ab66cSSepherosa Ziehau while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) { 1716*841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1717*841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 1718*841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 1719*841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1720*841ab66cSSepherosa Ziehau } 1721*841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1722*841ab66cSSepherosa Ziehau } 1723*841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 1724*841ab66cSSepherosa Ziehau } 1725*841ab66cSSepherosa Ziehau 1726*841ab66cSSepherosa Ziehau /* 1727*841ab66cSSepherosa Ziehau * Timeout entries in the scan cache. 1728*841ab66cSSepherosa Ziehau */ 1729*841ab66cSSepherosa Ziehau static void 1730*841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates(struct ieee80211_node_table *nt) 1731*841ab66cSSepherosa Ziehau { 1732*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1733*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *tni; 1734*841ab66cSSepherosa Ziehau 1735*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1736*841ab66cSSepherosa Ziehau 1737*841ab66cSSepherosa Ziehau ni = ic->ic_bss; 1738*841ab66cSSepherosa Ziehau /* XXX belongs elsewhere */ 1739*841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && ticks > ni->ni_rxfragstamp + hz) { 1740*841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1741*841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1742*841ab66cSSepherosa Ziehau } 1743*841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, tni) { 1744*841ab66cSSepherosa Ziehau if (ni->ni_inact && --ni->ni_inact == 0) { 1745*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1746*841ab66cSSepherosa Ziehau "[%6D] scan candidate purged from cache " 1747*841ab66cSSepherosa Ziehau "(refcnt %u)\n", ni->ni_macaddr, ":", 1748*841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1749*841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1750*841ab66cSSepherosa Ziehau } 1751*841ab66cSSepherosa Ziehau } 1752*841ab66cSSepherosa Ziehau 1753*841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1754*841ab66cSSepherosa Ziehau } 1755*841ab66cSSepherosa Ziehau 1756*841ab66cSSepherosa Ziehau /* 1757*841ab66cSSepherosa Ziehau * Timeout inactive stations and do related housekeeping. 1758*841ab66cSSepherosa Ziehau * Note that we cannot hold the node lock while sending a 1759*841ab66cSSepherosa Ziehau * frame as this would lead to a LOR. Instead we use a 1760*841ab66cSSepherosa Ziehau * generation number to mark nodes that we've scanned and 1761*841ab66cSSepherosa Ziehau * drop the lock and restart a scan if we have to time out 1762*841ab66cSSepherosa Ziehau * a node. Since we are single-threaded by virtue of 1763f186073cSJoerg Sonnenberger * controlling the inactivity timer we can be sure this will 1764f186073cSJoerg Sonnenberger * process each node only once. 1765f186073cSJoerg Sonnenberger */ 1766*841ab66cSSepherosa Ziehau static void 1767*841ab66cSSepherosa Ziehau ieee80211_timeout_stations(struct ieee80211_node_table *nt) 1768f186073cSJoerg Sonnenberger { 1769*841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1770*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1771*841ab66cSSepherosa Ziehau int isadhoc; 1772f186073cSJoerg Sonnenberger 1773*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1774*841ab66cSSepherosa Ziehau 1775*841ab66cSSepherosa Ziehau isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS || 1776*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO); 1777*841ab66cSSepherosa Ziehau 1778*841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) { 1779f186073cSJoerg Sonnenberger /* 1780*841ab66cSSepherosa Ziehau * Ignore entries for which have yet to receive an 1781*841ab66cSSepherosa Ziehau * authentication frame. These are transient and 1782*841ab66cSSepherosa Ziehau * will be reclaimed when the last reference to them 1783*841ab66cSSepherosa Ziehau * goes away (when frame xmits complete). 1784f186073cSJoerg Sonnenberger */ 1785*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1786*841ab66cSSepherosa Ziehau (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1787*841ab66cSSepherosa Ziehau continue; 1788*841ab66cSSepherosa Ziehau /* 1789*841ab66cSSepherosa Ziehau * Free fragment if not needed anymore 1790*841ab66cSSepherosa Ziehau * (last fragment older than 1s). 1791*841ab66cSSepherosa Ziehau * XXX doesn't belong here 1792*841ab66cSSepherosa Ziehau */ 1793*841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && 1794*841ab66cSSepherosa Ziehau ticks > ni->ni_rxfragstamp + hz) { 1795*841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1796*841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1797*841ab66cSSepherosa Ziehau } 1798*841ab66cSSepherosa Ziehau /* 1799*841ab66cSSepherosa Ziehau * Special case ourself; we may be idle for extended periods 1800*841ab66cSSepherosa Ziehau * of time and regardless reclaiming our state is wrong. 1801*841ab66cSSepherosa Ziehau */ 1802*841ab66cSSepherosa Ziehau if (ni == ic->ic_bss) 1803*841ab66cSSepherosa Ziehau continue; 1804*841ab66cSSepherosa Ziehau ni->ni_inact--; 1805*841ab66cSSepherosa Ziehau if (ni->ni_associd != 0 || isadhoc) { 1806*841ab66cSSepherosa Ziehau /* 1807*841ab66cSSepherosa Ziehau * Age frames on the power save queue. The 1808*841ab66cSSepherosa Ziehau * aging interval is 4 times the listen 1809*841ab66cSSepherosa Ziehau * interval specified by the station. This 1810*841ab66cSSepherosa Ziehau * number is factored into the age calculations 1811*841ab66cSSepherosa Ziehau * when the frame is placed on the queue. We 1812*841ab66cSSepherosa Ziehau * store ages as time differences we can check 1813*841ab66cSSepherosa Ziehau * and/or adjust only the head of the list. 1814*841ab66cSSepherosa Ziehau */ 1815*841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) { 1816*841ab66cSSepherosa Ziehau struct mbuf *m; 1817*841ab66cSSepherosa Ziehau int discard = 0; 1818*841ab66cSSepherosa Ziehau 1819*841ab66cSSepherosa Ziehau while (IF_POLL(&ni->ni_savedq, m) != NULL && 1820*841ab66cSSepherosa Ziehau M_AGE_GET(m) < IEEE80211_INACT_WAIT) { 1821*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1822*841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1823*841ab66cSSepherosa Ziehau "[%6D] discard frame, age %u\n", 1824*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1825*841ab66cSSepherosa Ziehau M_AGE_GET(m));/*XXX*/ 1826*841ab66cSSepherosa Ziehau _IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m); 1827*841ab66cSSepherosa Ziehau m_freem(m); 1828*841ab66cSSepherosa Ziehau discard++; 1829*841ab66cSSepherosa Ziehau } 1830*841ab66cSSepherosa Ziehau if (m != NULL) 1831*841ab66cSSepherosa Ziehau M_AGE_SUB(m, IEEE80211_INACT_WAIT); 1832*841ab66cSSepherosa Ziehau 1833*841ab66cSSepherosa Ziehau if (discard != 0) { 1834*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1835*841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1836*841ab66cSSepherosa Ziehau "[%6D] discard %u frames for age\n", 1837*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1838*841ab66cSSepherosa Ziehau discard); 1839*841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_ADD(ni, 1840*841ab66cSSepherosa Ziehau ps_discard, discard); 1841*841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) 1842*841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 1843*841ab66cSSepherosa Ziehau } 1844*841ab66cSSepherosa Ziehau } 1845*841ab66cSSepherosa Ziehau /* 1846*841ab66cSSepherosa Ziehau * Probe the station before time it out. We 1847*841ab66cSSepherosa Ziehau * send a null data frame which may not be 1848*841ab66cSSepherosa Ziehau * universally supported by drivers (need it 1849*841ab66cSSepherosa Ziehau * for ps-poll support so it should be...). 1850*841ab66cSSepherosa Ziehau */ 1851*841ab66cSSepherosa Ziehau if (0 < ni->ni_inact && 1852*841ab66cSSepherosa Ziehau ni->ni_inact <= ic->ic_inact_probe) { 1853*841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1854*841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 1855*841ab66cSSepherosa Ziehau ni, "%s", 1856*841ab66cSSepherosa Ziehau "probe station due to inactivity"); 1857*841ab66cSSepherosa Ziehau /* 1858*841ab66cSSepherosa Ziehau * Grab a reference before unlocking the table 1859*841ab66cSSepherosa Ziehau * so the node cannot be reclaimed before we 1860*841ab66cSSepherosa Ziehau * send the frame. ieee80211_send_nulldata 1861*841ab66cSSepherosa Ziehau * understands we've done this and reclaims the 1862*841ab66cSSepherosa Ziehau * ref for us as needed. 1863*841ab66cSSepherosa Ziehau */ 1864*841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1865*841ab66cSSepherosa Ziehau ieee80211_send_nulldata(ni); 1866*841ab66cSSepherosa Ziehau /* XXX stat? */ 1867*841ab66cSSepherosa Ziehau continue; 1868*841ab66cSSepherosa Ziehau } 1869*841ab66cSSepherosa Ziehau } 1870*841ab66cSSepherosa Ziehau if (ni->ni_inact <= 0) { 1871*841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1872*841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 1873*841ab66cSSepherosa Ziehau "station timed out due to inactivity " 1874*841ab66cSSepherosa Ziehau "(refcnt %u)", ieee80211_node_refcnt(ni)); 1875*841ab66cSSepherosa Ziehau /* 1876*841ab66cSSepherosa Ziehau * Send a deauthenticate frame and drop the station. 1877*841ab66cSSepherosa Ziehau * This is somewhat complicated due to reference counts 1878*841ab66cSSepherosa Ziehau * and locking. At this point a station will typically 1879*841ab66cSSepherosa Ziehau * have a reference count of 1. ieee80211_node_leave 1880*841ab66cSSepherosa Ziehau * will do a "free" of the node which will drop the 1881*841ab66cSSepherosa Ziehau * reference count. But in the meantime a reference 1882*841ab66cSSepherosa Ziehau * wil be held by the deauth frame. The actual reclaim 1883*841ab66cSSepherosa Ziehau * of the node will happen either after the tx is 1884*841ab66cSSepherosa Ziehau * completed or by ieee80211_node_leave. 1885*841ab66cSSepherosa Ziehau */ 1886*841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1887f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1888f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 1889f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_EXPIRE); 1890*841ab66cSSepherosa Ziehau } 1891*841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 1892f186073cSJoerg Sonnenberger ic->ic_stats.is_node_timeout++; 1893*841ab66cSSepherosa Ziehau continue; 1894f186073cSJoerg Sonnenberger } 1895f186073cSJoerg Sonnenberger } 1896*841ab66cSSepherosa Ziehau 1897*841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1898f186073cSJoerg Sonnenberger } 1899f186073cSJoerg Sonnenberger 1900f186073cSJoerg Sonnenberger void 1901*841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg) 1902f186073cSJoerg Sonnenberger { 1903*841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1904f186073cSJoerg Sonnenberger 1905*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1906*841ab66cSSepherosa Ziehau 1907*841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) 1908*841ab66cSSepherosa Ziehau f(arg, ni); 1909*841ab66cSSepherosa Ziehau } 1910*841ab66cSSepherosa Ziehau 1911*841ab66cSSepherosa Ziehau void 1912*841ab66cSSepherosa Ziehau ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1913*841ab66cSSepherosa Ziehau { 1914*841ab66cSSepherosa Ziehau printf("0x%p: mac %6D refcnt %d\n", ni, 1915*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)); 1916*841ab66cSSepherosa Ziehau printf("\tauthmode %u flags 0x%x\n", 1917*841ab66cSSepherosa Ziehau ni->ni_authmode, ni->ni_flags); 1918*841ab66cSSepherosa Ziehau printf("\tassocid 0x%x txpower %u vlan %u\n", 1919*841ab66cSSepherosa Ziehau ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 1920*841ab66cSSepherosa Ziehau printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 1921*841ab66cSSepherosa Ziehau ni->ni_txseqs[0], 1922*841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] >> IEEE80211_SEQ_SEQ_SHIFT, 1923*841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] & IEEE80211_SEQ_FRAG_MASK, 1924*841ab66cSSepherosa Ziehau ni->ni_rxfragstamp); 1925*841ab66cSSepherosa Ziehau printf("\trstamp %u rssi %u intval %u capinfo 0x%x\n", 1926*841ab66cSSepherosa Ziehau ni->ni_rstamp, ni->ni_rssi, ni->ni_intval, ni->ni_capinfo); 1927*841ab66cSSepherosa Ziehau printf("\tbssid %6D essid \"%.*s\" channel %u:0x%x\n", 1928*841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 1929*841ab66cSSepherosa Ziehau ni->ni_esslen, ni->ni_essid, 1930*841ab66cSSepherosa Ziehau ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 1931*841ab66cSSepherosa Ziehau printf("\tfails %u inact %u txrate %u\n", 1932*841ab66cSSepherosa Ziehau ni->ni_fails, ni->ni_inact, ni->ni_txrate); 1933*841ab66cSSepherosa Ziehau } 1934*841ab66cSSepherosa Ziehau 1935*841ab66cSSepherosa Ziehau void 1936*841ab66cSSepherosa Ziehau ieee80211_dump_nodes(struct ieee80211_node_table *nt) 1937*841ab66cSSepherosa Ziehau { 1938*841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(nt, 1939*841ab66cSSepherosa Ziehau (ieee80211_iter_func *) ieee80211_dump_node, nt); 1940*841ab66cSSepherosa Ziehau } 1941*841ab66cSSepherosa Ziehau 1942*841ab66cSSepherosa Ziehau /* 1943*841ab66cSSepherosa Ziehau * Handle a station joining an 11g network. 1944*841ab66cSSepherosa Ziehau */ 1945*841ab66cSSepherosa Ziehau static void 1946*841ab66cSSepherosa Ziehau ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 1947*841ab66cSSepherosa Ziehau { 1948*841ab66cSSepherosa Ziehau 1949*841ab66cSSepherosa Ziehau /* 1950*841ab66cSSepherosa Ziehau * Station isn't capable of short slot time. Bump 1951*841ab66cSSepherosa Ziehau * the count of long slot time stations and disable 1952*841ab66cSSepherosa Ziehau * use of short slot time. Note that the actual switch 1953*841ab66cSSepherosa Ziehau * over to long slot time use may not occur until the 1954*841ab66cSSepherosa Ziehau * next beacon transmission (per sec. 7.3.1.4 of 11g). 1955*841ab66cSSepherosa Ziehau */ 1956*841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 1957*841ab66cSSepherosa Ziehau ic->ic_longslotsta++; 1958*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1959*841ab66cSSepherosa Ziehau "[%6D] station needs long slot time, count %d\n", 1960*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 1961*841ab66cSSepherosa Ziehau /* XXX vap's w/ conflicting needs won't work */ 1962*841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 0); 1963*841ab66cSSepherosa Ziehau } 1964*841ab66cSSepherosa Ziehau /* 1965*841ab66cSSepherosa Ziehau * If the new station is not an ERP station 1966*841ab66cSSepherosa Ziehau * then bump the counter and enable protection 1967*841ab66cSSepherosa Ziehau * if configured. 1968*841ab66cSSepherosa Ziehau */ 1969*841ab66cSSepherosa Ziehau if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) { 1970*841ab66cSSepherosa Ziehau ic->ic_nonerpsta++; 1971*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1972*841ab66cSSepherosa Ziehau "[%6D] station is !ERP, %d non-ERP stations associated\n", 1973*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 1974*841ab66cSSepherosa Ziehau /* 1975*841ab66cSSepherosa Ziehau * If protection is configured, enable it. 1976*841ab66cSSepherosa Ziehau */ 1977*841ab66cSSepherosa Ziehau if (ic->ic_protmode != IEEE80211_PROT_NONE) { 1978*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1979*841ab66cSSepherosa Ziehau "%s: enable use of protection\n", __func__); 1980*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEPROT; 1981*841ab66cSSepherosa Ziehau } 1982*841ab66cSSepherosa Ziehau /* 1983*841ab66cSSepherosa Ziehau * If station does not support short preamble 1984*841ab66cSSepherosa Ziehau * then we must enable use of Barker preamble. 1985*841ab66cSSepherosa Ziehau */ 1986*841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 1987*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1988*841ab66cSSepherosa Ziehau "[%6D] station needs long preamble\n", 1989*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 1990*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEBARKER; 1991*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 1992*841ab66cSSepherosa Ziehau } 1993*841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 1) 1994*841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 1995*841ab66cSSepherosa Ziehau } else 1996*841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_ERP; 1997*841ab66cSSepherosa Ziehau } 1998*841ab66cSSepherosa Ziehau 1999*841ab66cSSepherosa Ziehau void 2000*841ab66cSSepherosa Ziehau ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) 2001*841ab66cSSepherosa Ziehau { 2002*841ab66cSSepherosa Ziehau int newassoc; 2003*841ab66cSSepherosa Ziehau 2004*841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) { 2005*841ab66cSSepherosa Ziehau uint16_t aid; 2006*841ab66cSSepherosa Ziehau 2007*841ab66cSSepherosa Ziehau /* 2008*841ab66cSSepherosa Ziehau * It would be good to search the bitmap 2009*841ab66cSSepherosa Ziehau * more efficiently, but this will do for now. 2010*841ab66cSSepherosa Ziehau */ 2011*841ab66cSSepherosa Ziehau for (aid = 1; aid < ic->ic_max_aid; aid++) { 2012*841ab66cSSepherosa Ziehau if (!IEEE80211_AID_ISSET(aid, 2013*841ab66cSSepherosa Ziehau ic->ic_aid_bitmap)) 2014*841ab66cSSepherosa Ziehau break; 2015*841ab66cSSepherosa Ziehau } 2016*841ab66cSSepherosa Ziehau if (aid >= ic->ic_max_aid) { 2017*841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, 2018*841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_TOOMANY); 2019*841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 2020*841ab66cSSepherosa Ziehau return; 2021*841ab66cSSepherosa Ziehau } 2022*841ab66cSSepherosa Ziehau ni->ni_associd = aid | 0xc000; 2023*841ab66cSSepherosa Ziehau IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); 2024*841ab66cSSepherosa Ziehau ic->ic_sta_assoc++; 2025*841ab66cSSepherosa Ziehau newassoc = 1; 2026*841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2027*841ab66cSSepherosa Ziehau ieee80211_node_join_11g(ic, ni); 2028*841ab66cSSepherosa Ziehau } else 2029*841ab66cSSepherosa Ziehau newassoc = 0; 2030*841ab66cSSepherosa Ziehau 2031*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2032*841ab66cSSepherosa Ziehau "[%6D] station %sassociated at aid %d: %s preamble, %s slot time%s%s\n", 2033*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", newassoc ? "" : "re", 2034*841ab66cSSepherosa Ziehau IEEE80211_NODE_AID(ni), 2035*841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2036*841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2037*841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2038*841ab66cSSepherosa Ziehau ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "" 2039*841ab66cSSepherosa Ziehau ); 2040*841ab66cSSepherosa Ziehau 2041*841ab66cSSepherosa Ziehau /* give driver a chance to setup state like ni_txrate */ 2042*841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 2043*841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, newassoc); 2044*841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_auth; 2045*841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 2046*841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); 2047*841ab66cSSepherosa Ziehau /* tell the authenticator about new station */ 2048*841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_join != NULL) 2049*841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_join(ic, ni); 2050*841ab66cSSepherosa Ziehau ieee80211_notify_node_join(ic, ni, newassoc); 2051*841ab66cSSepherosa Ziehau } 2052*841ab66cSSepherosa Ziehau 2053*841ab66cSSepherosa Ziehau /* 2054*841ab66cSSepherosa Ziehau * Handle a station leaving an 11g network. 2055*841ab66cSSepherosa Ziehau */ 2056*841ab66cSSepherosa Ziehau static void 2057*841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 2058*841ab66cSSepherosa Ziehau { 2059*841ab66cSSepherosa Ziehau 2060*841ab66cSSepherosa Ziehau KASSERT(ic->ic_curmode == IEEE80211_MODE_11G, 2061*841ab66cSSepherosa Ziehau ("not in 11g, bss %u:0x%x, curmode %u", ni->ni_chan->ic_freq, 2062*841ab66cSSepherosa Ziehau ni->ni_chan->ic_flags, ic->ic_curmode)); 2063*841ab66cSSepherosa Ziehau 2064*841ab66cSSepherosa Ziehau /* 2065*841ab66cSSepherosa Ziehau * If a long slot station do the slot time bookkeeping. 2066*841ab66cSSepherosa Ziehau */ 2067*841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2068*841ab66cSSepherosa Ziehau KASSERT(ic->ic_longslotsta > 0, 2069*841ab66cSSepherosa Ziehau ("bogus long slot station count %d", ic->ic_longslotsta)); 2070*841ab66cSSepherosa Ziehau ic->ic_longslotsta--; 2071*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2072*841ab66cSSepherosa Ziehau "[%6D] long slot time station leaves, count now %d\n", 2073*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 2074*841ab66cSSepherosa Ziehau if (ic->ic_longslotsta == 0) { 2075*841ab66cSSepherosa Ziehau /* 2076*841ab66cSSepherosa Ziehau * Re-enable use of short slot time if supported 2077*841ab66cSSepherosa Ziehau * and not operating in IBSS mode (per spec). 2078*841ab66cSSepherosa Ziehau */ 2079*841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2080*841ab66cSSepherosa Ziehau ic->ic_opmode != IEEE80211_M_IBSS) { 2081*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2082*841ab66cSSepherosa Ziehau "%s: re-enable use of short slot time\n", 2083*841ab66cSSepherosa Ziehau __func__); 2084*841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 1); 2085*841ab66cSSepherosa Ziehau } 2086*841ab66cSSepherosa Ziehau } 2087*841ab66cSSepherosa Ziehau } 2088*841ab66cSSepherosa Ziehau /* 2089*841ab66cSSepherosa Ziehau * If a non-ERP station do the protection-related bookkeeping. 2090*841ab66cSSepherosa Ziehau */ 2091*841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2092*841ab66cSSepherosa Ziehau KASSERT(ic->ic_nonerpsta > 0, 2093*841ab66cSSepherosa Ziehau ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2094*841ab66cSSepherosa Ziehau ic->ic_nonerpsta--; 2095*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2096*841ab66cSSepherosa Ziehau "[%6D] non-ERP station leaves, count now %d\n", 2097*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 2098*841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 0) { 2099*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2100*841ab66cSSepherosa Ziehau "%s: disable use of protection\n", __func__); 2101*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT; 2102*841ab66cSSepherosa Ziehau /* XXX verify mode? */ 2103*841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2104*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2105*841ab66cSSepherosa Ziehau "%s: re-enable use of short preamble\n", 2106*841ab66cSSepherosa Ziehau __func__); 2107*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 2108*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEBARKER; 2109*841ab66cSSepherosa Ziehau } 2110*841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2111*841ab66cSSepherosa Ziehau } 2112*841ab66cSSepherosa Ziehau } 2113*841ab66cSSepherosa Ziehau } 2114*841ab66cSSepherosa Ziehau 2115*841ab66cSSepherosa Ziehau /* 2116*841ab66cSSepherosa Ziehau * Handle bookkeeping for station deauthentication/disassociation 2117*841ab66cSSepherosa Ziehau * when operating as an ap. 2118*841ab66cSSepherosa Ziehau */ 2119*841ab66cSSepherosa Ziehau void 2120*841ab66cSSepherosa Ziehau ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 2121*841ab66cSSepherosa Ziehau { 2122*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 2123*841ab66cSSepherosa Ziehau 2124*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2125*841ab66cSSepherosa Ziehau 2126*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2127*841ab66cSSepherosa Ziehau "[%6D] station with aid %d leaves\n", 2128*841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", IEEE80211_NODE_AID(ni)); 2129*841ab66cSSepherosa Ziehau 2130*841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2131*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS || 2132*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO, 2133*841ab66cSSepherosa Ziehau ("unexpected operating mode %u", ic->ic_opmode)); 2134*841ab66cSSepherosa Ziehau /* 2135*841ab66cSSepherosa Ziehau * If node wasn't previously associated all 2136*841ab66cSSepherosa Ziehau * we need to do is reclaim the reference. 2137*841ab66cSSepherosa Ziehau */ 2138*841ab66cSSepherosa Ziehau /* XXX ibss mode bypasses 11g and notification */ 2139*841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) 2140*841ab66cSSepherosa Ziehau goto done; 2141*841ab66cSSepherosa Ziehau /* 2142*841ab66cSSepherosa Ziehau * Tell the authenticator the station is leaving. 2143*841ab66cSSepherosa Ziehau * Note that we must do this before yanking the 2144*841ab66cSSepherosa Ziehau * association id as the authenticator uses the 2145*841ab66cSSepherosa Ziehau * associd to locate it's state block. 2146*841ab66cSSepherosa Ziehau */ 2147*841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 2148*841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 2149*841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 2150*841ab66cSSepherosa Ziehau ni->ni_associd = 0; 2151*841ab66cSSepherosa Ziehau ic->ic_sta_assoc--; 2152*841ab66cSSepherosa Ziehau 2153*841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2154*841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(ic, ni); 2155*841ab66cSSepherosa Ziehau /* 2156*841ab66cSSepherosa Ziehau * Cleanup station state. In particular clear various 2157*841ab66cSSepherosa Ziehau * state that might otherwise be reused if the node 2158*841ab66cSSepherosa Ziehau * is reused before the reference count goes to zero 2159*841ab66cSSepherosa Ziehau * (and memory is reclaimed). 2160*841ab66cSSepherosa Ziehau */ 2161*841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 2162*841ab66cSSepherosa Ziehau done: 2163*841ab66cSSepherosa Ziehau /* 2164*841ab66cSSepherosa Ziehau * Remove the node from any table it's recorded in and 2165*841ab66cSSepherosa Ziehau * drop the caller's reference. Removal from the table 2166*841ab66cSSepherosa Ziehau * is important to insure the node is not reprocessed 2167*841ab66cSSepherosa Ziehau * for inactivity. 2168*841ab66cSSepherosa Ziehau */ 2169*841ab66cSSepherosa Ziehau if (nt != NULL) 2170*841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 2171*841ab66cSSepherosa Ziehau else 2172*841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2173*841ab66cSSepherosa Ziehau } 2174*841ab66cSSepherosa Ziehau 2175*841ab66cSSepherosa Ziehau uint8_t 2176*841ab66cSSepherosa Ziehau ieee80211_getrssi(struct ieee80211com *ic) 2177*841ab66cSSepherosa Ziehau { 2178*841ab66cSSepherosa Ziehau #define NZ(x) ((x) == 0 ? 1 : (x)) 2179*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 2180*841ab66cSSepherosa Ziehau uint32_t rssi_samples, rssi_total; 2181*841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 2182*841ab66cSSepherosa Ziehau 2183*841ab66cSSepherosa Ziehau rssi_total = 0; 2184*841ab66cSSepherosa Ziehau rssi_samples = 0; 2185*841ab66cSSepherosa Ziehau switch (ic->ic_opmode) { 2186*841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2187*841ab66cSSepherosa Ziehau /* XXX locking */ 2188*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2189*841ab66cSSepherosa Ziehau if (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) { 2190*841ab66cSSepherosa Ziehau rssi_samples++; 2191*841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2192*841ab66cSSepherosa Ziehau } 2193*841ab66cSSepherosa Ziehau break; 2194*841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2195*841ab66cSSepherosa Ziehau /* XXX locking */ 2196*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2197*841ab66cSSepherosa Ziehau rssi_samples++; 2198*841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2199*841ab66cSSepherosa Ziehau } 2200*841ab66cSSepherosa Ziehau break; 2201*841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2202*841ab66cSSepherosa Ziehau /* XXX locking */ 2203*841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2204*841ab66cSSepherosa Ziehau if (IEEE80211_AID(ni->ni_associd) != 0) { 2205*841ab66cSSepherosa Ziehau rssi_samples++; 2206*841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2207*841ab66cSSepherosa Ziehau } 2208*841ab66cSSepherosa Ziehau break; 2209*841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* XXX */ 2210*841ab66cSSepherosa Ziehau case IEEE80211_M_STA: /* use stats from associated ap */ 2211*841ab66cSSepherosa Ziehau default: 2212*841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) 2213*841ab66cSSepherosa Ziehau rssi_total = ic->ic_node_getrssi(ic->ic_bss); 2214*841ab66cSSepherosa Ziehau rssi_samples = 1; 2215*841ab66cSSepherosa Ziehau break; 2216*841ab66cSSepherosa Ziehau } 2217*841ab66cSSepherosa Ziehau return rssi_total / NZ(rssi_samples); 2218*841ab66cSSepherosa Ziehau #undef NZ 2219*841ab66cSSepherosa Ziehau } 2220*841ab66cSSepherosa Ziehau 2221*841ab66cSSepherosa Ziehau /* 2222*841ab66cSSepherosa Ziehau * Indicate whether there are frames queued for a station in power-save mode. 2223*841ab66cSSepherosa Ziehau */ 2224*841ab66cSSepherosa Ziehau static void 2225*841ab66cSSepherosa Ziehau ieee80211_set_tim(struct ieee80211_node *ni, int set) 2226*841ab66cSSepherosa Ziehau { 2227*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 2228*841ab66cSSepherosa Ziehau uint16_t aid; 2229*841ab66cSSepherosa Ziehau 2230*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2231*841ab66cSSepherosa Ziehau 2232*841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2233*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS, 2234*841ab66cSSepherosa Ziehau ("operating mode %u", ic->ic_opmode)); 2235*841ab66cSSepherosa Ziehau 2236*841ab66cSSepherosa Ziehau aid = IEEE80211_AID(ni->ni_associd); 2237*841ab66cSSepherosa Ziehau KASSERT(aid < ic->ic_max_aid, 2238*841ab66cSSepherosa Ziehau ("bogus aid %u, max %u", aid, ic->ic_max_aid)); 2239*841ab66cSSepherosa Ziehau 2240*841ab66cSSepherosa Ziehau if (set != (isset(ic->ic_tim_bitmap, aid) != 0)) { 2241*841ab66cSSepherosa Ziehau if (set) { 2242*841ab66cSSepherosa Ziehau setbit(ic->ic_tim_bitmap, aid); 2243*841ab66cSSepherosa Ziehau ic->ic_ps_pending++; 2244*841ab66cSSepherosa Ziehau } else { 2245*841ab66cSSepherosa Ziehau clrbit(ic->ic_tim_bitmap, aid); 2246*841ab66cSSepherosa Ziehau ic->ic_ps_pending--; 2247*841ab66cSSepherosa Ziehau } 2248*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_TIMUPDATE; 2249*841ab66cSSepherosa Ziehau } 2250*841ab66cSSepherosa Ziehau } 2251*841ab66cSSepherosa Ziehau 2252*841ab66cSSepherosa Ziehau /* 2253*841ab66cSSepherosa Ziehau * Node table support. 2254*841ab66cSSepherosa Ziehau */ 2255*841ab66cSSepherosa Ziehau 2256*841ab66cSSepherosa Ziehau static void 2257*841ab66cSSepherosa Ziehau ieee80211_node_table_init(struct ieee80211com *ic, 2258*841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, 2259*841ab66cSSepherosa Ziehau const char *name, int inact, int keyixmax, 2260*841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)) 2261*841ab66cSSepherosa Ziehau { 2262*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 2263*841ab66cSSepherosa Ziehau "%s %s table, inact %u\n", __func__, name, inact); 2264*841ab66cSSepherosa Ziehau 2265*841ab66cSSepherosa Ziehau nt->nt_ic = ic; 2266*841ab66cSSepherosa Ziehau TAILQ_INIT(&nt->nt_node); 2267*841ab66cSSepherosa Ziehau nt->nt_name = name; 2268*841ab66cSSepherosa Ziehau nt->nt_inact_init = inact; 2269*841ab66cSSepherosa Ziehau nt->nt_timeout = timeout; 2270*841ab66cSSepherosa Ziehau nt->nt_keyixmax = keyixmax; 2271*841ab66cSSepherosa Ziehau if (nt->nt_keyixmax > 0) { 2272*841ab66cSSepherosa Ziehau nt->nt_keyixmap = 2273*841ab66cSSepherosa Ziehau malloc(keyixmax * sizeof(struct ieee80211_node *), 2274*841ab66cSSepherosa Ziehau M_80211_NODE, M_WAITOK | M_ZERO); 2275*841ab66cSSepherosa Ziehau } else { 2276*841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2277*841ab66cSSepherosa Ziehau } 2278*841ab66cSSepherosa Ziehau } 2279*841ab66cSSepherosa Ziehau 2280*841ab66cSSepherosa Ziehau void 2281*841ab66cSSepherosa Ziehau ieee80211_node_table_reset(struct ieee80211_node_table *nt) 2282*841ab66cSSepherosa Ziehau { 2283*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2284*841ab66cSSepherosa Ziehau 2285*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2286*841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2287*841ab66cSSepherosa Ziehau 2288*841ab66cSSepherosa Ziehau nt->nt_inact_timer = 0; 2289*841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2290*841ab66cSSepherosa Ziehau } 2291*841ab66cSSepherosa Ziehau 2292*841ab66cSSepherosa Ziehau static void 2293*841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 2294*841ab66cSSepherosa Ziehau { 2295*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2296*841ab66cSSepherosa Ziehau 2297*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2298*841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2299*841ab66cSSepherosa Ziehau 2300*841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2301*841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 2302*841ab66cSSepherosa Ziehau /* XXX verify all entries are NULL */ 2303*841ab66cSSepherosa Ziehau int i; 2304*841ab66cSSepherosa Ziehau for (i = 0; i < nt->nt_keyixmax; i++) 2305*841ab66cSSepherosa Ziehau if (nt->nt_keyixmap[i] != NULL) { 2306*841ab66cSSepherosa Ziehau printf("%s: %s[%u] still active\n", __func__, 2307*841ab66cSSepherosa Ziehau nt->nt_name, i); 2308*841ab66cSSepherosa Ziehau } 2309*841ab66cSSepherosa Ziehau free(nt->nt_keyixmap, M_80211_NODE); 2310*841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2311*841ab66cSSepherosa Ziehau } 2312f186073cSJoerg Sonnenberger } 2313