1f186073cSJoerg Sonnenberger /* 2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 3841ab66cSSepherosa 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 * 325d004897SSepherosa Ziehau * $FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.48.2.12 2006/07/10 00:46:27 sam Exp $ 33*a6ec04bcSSascha Wildner * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.13 2006/12/22 23:57:53 swildner 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 42841ab66cSSepherosa Ziehau #include <sys/socket.h> 43f186073cSJoerg Sonnenberger 44f186073cSJoerg Sonnenberger #include <net/if.h> 45f186073cSJoerg Sonnenberger #include <net/if_arp.h> 46841ab66cSSepherosa 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 53841ab66cSSepherosa Ziehau /* 54841ab66cSSepherosa Ziehau * Association id's are managed with a bit vector. 55841ab66cSSepherosa Ziehau */ 56841ab66cSSepherosa Ziehau #define IEEE80211_AID_SET(b, w) \ 57841ab66cSSepherosa Ziehau ((w)[IEEE80211_AID(b) / 32] |= (1 << (IEEE80211_AID(b) % 32))) 58841ab66cSSepherosa Ziehau #define IEEE80211_AID_CLR(b, w) \ 59841ab66cSSepherosa Ziehau ((w)[IEEE80211_AID(b) / 32] &= ~(1 << (IEEE80211_AID(b) % 32))) 60841ab66cSSepherosa Ziehau #define IEEE80211_AID_ISSET(b, w) \ 61841ab66cSSepherosa Ziehau ((w)[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32))) 62f186073cSJoerg Sonnenberger 635d004897SSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 645d004897SSepherosa Ziehau #define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line 655d004897SSepherosa Ziehau #else 665d004897SSepherosa Ziehau #define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__ 675d004897SSepherosa Ziehau #endif 685d004897SSepherosa Ziehau 69841ab66cSSepherosa Ziehau static struct ieee80211_node *node_alloc(struct ieee80211_node_table *); 70841ab66cSSepherosa Ziehau static void node_cleanup(struct ieee80211_node *); 71841ab66cSSepherosa Ziehau static void node_free(struct ieee80211_node *); 72841ab66cSSepherosa Ziehau static uint8_t node_getrssi(const struct ieee80211_node *); 73f186073cSJoerg Sonnenberger 74841ab66cSSepherosa Ziehau static void ieee80211_setup_node(struct ieee80211_node_table *, 75841ab66cSSepherosa Ziehau struct ieee80211_node *, const uint8_t *); 76841ab66cSSepherosa Ziehau static void _ieee80211_free_node(struct ieee80211_node *); 77841ab66cSSepherosa Ziehau static void ieee80211_free_allnodes(struct ieee80211_node_table *); 78841ab66cSSepherosa Ziehau 79841ab66cSSepherosa Ziehau static void ieee80211_timeout_scan_candidates(struct ieee80211_node_table *); 80841ab66cSSepherosa Ziehau static void ieee80211_timeout_stations(struct ieee80211_node_table *); 81841ab66cSSepherosa Ziehau 82841ab66cSSepherosa Ziehau static void ieee80211_set_tim(struct ieee80211_node *, int set); 83841ab66cSSepherosa Ziehau 84841ab66cSSepherosa Ziehau static void ieee80211_node_table_init(struct ieee80211com *ic, 85841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, const char *name, 86841ab66cSSepherosa Ziehau int inact, int keyixmax, 87841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)); 88841ab66cSSepherosa Ziehau static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 89f186073cSJoerg Sonnenberger 90f186073cSJoerg Sonnenberger MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 91f186073cSJoerg Sonnenberger 92f186073cSJoerg Sonnenberger void 93841ab66cSSepherosa Ziehau ieee80211_node_attach(struct ieee80211com *ic) 94f186073cSJoerg Sonnenberger { 95841ab66cSSepherosa Ziehau ic->ic_node_alloc = node_alloc; 96841ab66cSSepherosa Ziehau ic->ic_node_free = node_free; 97841ab66cSSepherosa Ziehau ic->ic_node_cleanup = node_cleanup; 98841ab66cSSepherosa Ziehau ic->ic_node_getrssi = node_getrssi; 99f186073cSJoerg Sonnenberger 100841ab66cSSepherosa Ziehau /* default station inactivity timer setings */ 101841ab66cSSepherosa Ziehau ic->ic_inact_init = IEEE80211_INACT_INIT; 102841ab66cSSepherosa Ziehau ic->ic_inact_auth = IEEE80211_INACT_AUTH; 103841ab66cSSepherosa Ziehau ic->ic_inact_run = IEEE80211_INACT_RUN; 104841ab66cSSepherosa Ziehau ic->ic_inact_probe = IEEE80211_INACT_PROBE; 105841ab66cSSepherosa Ziehau 106841ab66cSSepherosa Ziehau /* NB: driver should override */ 107841ab66cSSepherosa Ziehau ic->ic_max_aid = IEEE80211_AID_DEF; 108841ab66cSSepherosa Ziehau ic->ic_set_tim = ieee80211_set_tim; 109f186073cSJoerg Sonnenberger } 110f186073cSJoerg Sonnenberger 111f186073cSJoerg Sonnenberger void 112841ab66cSSepherosa Ziehau ieee80211_node_lateattach(struct ieee80211com *ic) 113f186073cSJoerg Sonnenberger { 114841ab66cSSepherosa Ziehau struct ieee80211_rsnparms *rsn; 115f186073cSJoerg Sonnenberger 116841ab66cSSepherosa Ziehau if (ic->ic_max_aid > IEEE80211_AID_MAX) 117841ab66cSSepherosa Ziehau ic->ic_max_aid = IEEE80211_AID_MAX; 118841ab66cSSepherosa Ziehau 119841ab66cSSepherosa Ziehau ic->ic_aid_bitmap = 12077652cadSMatthew Dillon kmalloc(howmany(ic->ic_max_aid, 32) * sizeof(uint32_t), 121841ab66cSSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 122841ab66cSSepherosa Ziehau 123841ab66cSSepherosa Ziehau /* XXX defer until using hostap/ibss mode */ 124841ab66cSSepherosa Ziehau ic->ic_tim_len = howmany(ic->ic_max_aid, 8) * sizeof(uint8_t); 125efda3bd0SMatthew Dillon ic->ic_tim_bitmap = kmalloc(ic->ic_tim_len, M_DEVBUF, 126841ab66cSSepherosa Ziehau M_WAITOK | M_ZERO); 127841ab66cSSepherosa Ziehau 128841ab66cSSepherosa Ziehau ieee80211_node_table_init(ic, &ic->ic_sta, "station", 129841ab66cSSepherosa Ziehau IEEE80211_INACT_INIT, ic->ic_crypto.cs_max_keyix, 130841ab66cSSepherosa Ziehau ieee80211_timeout_stations); 131841ab66cSSepherosa Ziehau ieee80211_node_table_init(ic, &ic->ic_scan, "scan", 132841ab66cSSepherosa Ziehau IEEE80211_INACT_SCAN, 0, 133841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates); 134841ab66cSSepherosa Ziehau 135841ab66cSSepherosa Ziehau ieee80211_reset_bss(ic); 136841ab66cSSepherosa Ziehau /* 137841ab66cSSepherosa Ziehau * Setup "global settings" in the bss node so that 138841ab66cSSepherosa Ziehau * each new station automatically inherits them. 139841ab66cSSepherosa Ziehau */ 140841ab66cSSepherosa Ziehau rsn = &ic->ic_bss->ni_rsn; 141841ab66cSSepherosa Ziehau /* WEP, TKIP, and AES-CCM are always supported */ 142841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_WEP; 143841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_TKIP; 144841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_CCM; 145841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_AES) 146841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_OCB; 147841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_CKIP) 148841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_CKIP; 149841ab66cSSepherosa Ziehau /* 150841ab66cSSepherosa Ziehau * Default unicast cipher to WEP for 802.1x use. If 151841ab66cSSepherosa Ziehau * WPA is enabled the management code will set these 152841ab66cSSepherosa Ziehau * values to reflect. 153841ab66cSSepherosa Ziehau */ 154841ab66cSSepherosa Ziehau rsn->rsn_ucastcipher = IEEE80211_CIPHER_WEP; 155841ab66cSSepherosa Ziehau rsn->rsn_ucastkeylen = 104 / NBBY; 156841ab66cSSepherosa Ziehau /* 157841ab66cSSepherosa Ziehau * WPA says the multicast cipher is the lowest unicast 158841ab66cSSepherosa Ziehau * cipher supported. But we skip WEP which would 159841ab66cSSepherosa Ziehau * otherwise be used based on this criteria. 160841ab66cSSepherosa Ziehau */ 161841ab66cSSepherosa Ziehau rsn->rsn_mcastcipher = IEEE80211_CIPHER_TKIP; 162841ab66cSSepherosa Ziehau rsn->rsn_mcastkeylen = 128 / NBBY; 163841ab66cSSepherosa Ziehau 164841ab66cSSepherosa Ziehau /* 165841ab66cSSepherosa Ziehau * We support both WPA-PSK and 802.1x; the one used 166841ab66cSSepherosa Ziehau * is determined by the authentication mode and the 167841ab66cSSepherosa Ziehau * setting of the PSK state. 168841ab66cSSepherosa Ziehau */ 169841ab66cSSepherosa Ziehau rsn->rsn_keymgmtset = WPA_ASE_8021X_UNSPEC | WPA_ASE_8021X_PSK; 170841ab66cSSepherosa Ziehau rsn->rsn_keymgmt = WPA_ASE_8021X_PSK; 171841ab66cSSepherosa Ziehau 172841ab66cSSepherosa Ziehau ic->ic_auth = ieee80211_authenticator_get(ic->ic_bss->ni_authmode); 173f186073cSJoerg Sonnenberger } 174f186073cSJoerg Sonnenberger 175f186073cSJoerg Sonnenberger void 176841ab66cSSepherosa Ziehau ieee80211_node_detach(struct ieee80211com *ic) 177f186073cSJoerg Sonnenberger { 178841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) { 179841ab66cSSepherosa Ziehau ieee80211_free_node(ic->ic_bss); 180841ab66cSSepherosa Ziehau ic->ic_bss = NULL; 181841ab66cSSepherosa Ziehau } 182841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_scan); 183841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_sta); 184841ab66cSSepherosa Ziehau if (ic->ic_aid_bitmap != NULL) { 185efda3bd0SMatthew Dillon kfree(ic->ic_aid_bitmap, M_DEVBUF); 186841ab66cSSepherosa Ziehau ic->ic_aid_bitmap = NULL; 187841ab66cSSepherosa Ziehau } 188841ab66cSSepherosa Ziehau if (ic->ic_tim_bitmap != NULL) { 189efda3bd0SMatthew Dillon kfree(ic->ic_tim_bitmap, M_DEVBUF); 190841ab66cSSepherosa Ziehau ic->ic_tim_bitmap = NULL; 191841ab66cSSepherosa Ziehau } 192841ab66cSSepherosa Ziehau } 193f186073cSJoerg Sonnenberger 194841ab66cSSepherosa Ziehau /* 195841ab66cSSepherosa Ziehau * Port authorize/unauthorize interfaces for use by an authenticator. 196841ab66cSSepherosa Ziehau */ 197841ab66cSSepherosa Ziehau 198841ab66cSSepherosa Ziehau void 199841ab66cSSepherosa Ziehau ieee80211_node_authorize(struct ieee80211_node *ni) 200841ab66cSSepherosa Ziehau { 201841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 202841ab66cSSepherosa Ziehau 203841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_AUTH; 204841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_run; 205841ab66cSSepherosa Ziehau } 206841ab66cSSepherosa Ziehau 207841ab66cSSepherosa Ziehau void 208841ab66cSSepherosa Ziehau ieee80211_node_unauthorize(struct ieee80211_node *ni) 209841ab66cSSepherosa Ziehau { 210841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AUTH; 211841ab66cSSepherosa Ziehau } 212841ab66cSSepherosa Ziehau 213841ab66cSSepherosa Ziehau /* 214841ab66cSSepherosa Ziehau * Set/change the channel. The rate set is also updated as 215841ab66cSSepherosa Ziehau * to insure a consistent view by drivers. 216841ab66cSSepherosa Ziehau */ 217841ab66cSSepherosa Ziehau static void 218841ab66cSSepherosa Ziehau ieee80211_set_chan(struct ieee80211com *ic, 219841ab66cSSepherosa Ziehau struct ieee80211_node *ni, struct ieee80211_channel *chan) 220841ab66cSSepherosa Ziehau { 221841ab66cSSepherosa Ziehau if (chan == IEEE80211_CHAN_ANYC) /* XXX while scanning */ 222841ab66cSSepherosa Ziehau chan = ic->ic_curchan; 223841ab66cSSepherosa Ziehau ni->ni_chan = chan; 224841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 225f186073cSJoerg Sonnenberger } 226f186073cSJoerg Sonnenberger 227f186073cSJoerg Sonnenberger /* 228f186073cSJoerg Sonnenberger * AP scanning support. 229f186073cSJoerg Sonnenberger */ 230f186073cSJoerg Sonnenberger 231841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 232841ab66cSSepherosa Ziehau static void 233841ab66cSSepherosa Ziehau dump_chanlist(const u_char chans[]) 234841ab66cSSepherosa Ziehau { 235841ab66cSSepherosa Ziehau const char *sep; 236841ab66cSSepherosa Ziehau int i; 237841ab66cSSepherosa Ziehau 238841ab66cSSepherosa Ziehau sep = " "; 239841ab66cSSepherosa Ziehau for (i = 0; i < IEEE80211_CHAN_MAX; i++) 240841ab66cSSepherosa Ziehau if (isset(chans, i)) { 241*a6ec04bcSSascha Wildner kprintf("%s%u", sep, i); 242841ab66cSSepherosa Ziehau sep = ", "; 243841ab66cSSepherosa Ziehau } 244841ab66cSSepherosa Ziehau } 245841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 246841ab66cSSepherosa Ziehau 247f186073cSJoerg Sonnenberger /* 248841ab66cSSepherosa Ziehau * Initialize the channel set to scan based on the 249f186073cSJoerg Sonnenberger * of available channels and the current PHY mode. 250f186073cSJoerg Sonnenberger */ 251f186073cSJoerg Sonnenberger static void 252841ab66cSSepherosa Ziehau ieee80211_reset_scan(struct ieee80211com *ic) 253f186073cSJoerg Sonnenberger { 254f186073cSJoerg Sonnenberger 255841ab66cSSepherosa Ziehau /* XXX ic_des_chan should be handled with ic_chan_active */ 256841ab66cSSepherosa Ziehau if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 257841ab66cSSepherosa Ziehau memset(ic->ic_chan_scan, 0, sizeof(ic->ic_chan_scan)); 258841ab66cSSepherosa Ziehau setbit(ic->ic_chan_scan, 259841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_des_chan)); 260841ab66cSSepherosa Ziehau } else 261f186073cSJoerg Sonnenberger memcpy(ic->ic_chan_scan, ic->ic_chan_active, 262f186073cSJoerg Sonnenberger sizeof(ic->ic_chan_active)); 263841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 264841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 265*a6ec04bcSSascha Wildner kprintf("%s: scan set:", __func__); 266841ab66cSSepherosa Ziehau dump_chanlist(ic->ic_chan_scan); 267*a6ec04bcSSascha Wildner kprintf(" start chan %u\n", 268841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan)); 269841ab66cSSepherosa Ziehau } 270841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 271f186073cSJoerg Sonnenberger } 272f186073cSJoerg Sonnenberger 273f186073cSJoerg Sonnenberger /* 274f186073cSJoerg Sonnenberger * Begin an active scan. 275f186073cSJoerg Sonnenberger */ 276f186073cSJoerg Sonnenberger void 277841ab66cSSepherosa Ziehau ieee80211_begin_scan(struct ieee80211com *ic, int reset) 278f186073cSJoerg Sonnenberger { 279841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 280f186073cSJoerg Sonnenberger 281f186073cSJoerg Sonnenberger /* 282f186073cSJoerg Sonnenberger * In all but hostap mode scanning starts off in 283f186073cSJoerg Sonnenberger * an active mode before switching to passive. 284f186073cSJoerg Sonnenberger */ 285f186073cSJoerg Sonnenberger if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 286f186073cSJoerg Sonnenberger ic->ic_flags |= IEEE80211_F_ASCAN; 287f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_active++; 288f186073cSJoerg Sonnenberger } else 289f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_passive++; 290841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 291841ab66cSSepherosa Ziehau "begin %s scan in %s mode\n", 292841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive", 293841ab66cSSepherosa Ziehau ieee80211_phymode_name[ic->ic_curmode]); 294f186073cSJoerg Sonnenberger /* 295841ab66cSSepherosa Ziehau * Clear scan state and flush any previously seen AP's. 296f186073cSJoerg Sonnenberger */ 297841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 298841ab66cSSepherosa Ziehau if (reset) 299841ab66cSSepherosa Ziehau ieee80211_free_allnodes(&ic->ic_scan); 300841ab66cSSepherosa Ziehau 301841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 302f186073cSJoerg Sonnenberger 303f186073cSJoerg Sonnenberger /* Scan the next channel. */ 304841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 305f186073cSJoerg Sonnenberger } 306f186073cSJoerg Sonnenberger 307f186073cSJoerg Sonnenberger /* 308f186073cSJoerg Sonnenberger * Switch to the next channel marked for scanning. 309f186073cSJoerg Sonnenberger */ 310841ab66cSSepherosa Ziehau int 311841ab66cSSepherosa Ziehau ieee80211_next_scan(struct ieee80211com *ic) 312f186073cSJoerg Sonnenberger { 313f186073cSJoerg Sonnenberger struct ieee80211_channel *chan; 314f186073cSJoerg Sonnenberger 315841ab66cSSepherosa Ziehau /* 316841ab66cSSepherosa Ziehau * Insure any previous mgt frame timeouts don't fire. 317841ab66cSSepherosa Ziehau * This assumes the driver does the right thing in 318841ab66cSSepherosa Ziehau * flushing anything queued in the driver and below. 319841ab66cSSepherosa Ziehau */ 320841ab66cSSepherosa Ziehau ic->ic_mgt_timer = 0; 321841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 322841ab66cSSepherosa Ziehau 323841ab66cSSepherosa Ziehau chan = ic->ic_curchan; 324841ab66cSSepherosa Ziehau do { 325f186073cSJoerg Sonnenberger if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) 326f186073cSJoerg Sonnenberger chan = &ic->ic_channels[0]; 327f186073cSJoerg Sonnenberger if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) { 328f186073cSJoerg Sonnenberger clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); 329841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 330841ab66cSSepherosa Ziehau "%s: chan %d->%d\n", __func__, 331841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 332841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, chan)); 333841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 334841ab66cSSepherosa Ziehau /* 335841ab66cSSepherosa Ziehau * XXX drivers should do this as needed, 336841ab66cSSepherosa Ziehau * XXX for now maintain compatibility 337841ab66cSSepherosa Ziehau */ 338841ab66cSSepherosa Ziehau ic->ic_bss->ni_rates = 339841ab66cSSepherosa Ziehau ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 340f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 341841ab66cSSepherosa Ziehau return 1; 342841ab66cSSepherosa Ziehau } 343841ab66cSSepherosa Ziehau } while (chan != ic->ic_curchan); 344841ab66cSSepherosa Ziehau ieee80211_end_scan(ic); 345841ab66cSSepherosa Ziehau return 0; 346841ab66cSSepherosa Ziehau } 347841ab66cSSepherosa Ziehau 348841ab66cSSepherosa Ziehau /* 349841ab66cSSepherosa Ziehau * Probe the curent channel, if allowed, while scanning. 350841ab66cSSepherosa Ziehau * If the channel is not marked passive-only then send 351841ab66cSSepherosa Ziehau * a probe request immediately. Otherwise mark state and 352841ab66cSSepherosa Ziehau * listen for beacons on the channel; if we receive something 353841ab66cSSepherosa Ziehau * then we'll transmit a probe request. 354841ab66cSSepherosa Ziehau */ 355841ab66cSSepherosa Ziehau void 356841ab66cSSepherosa Ziehau ieee80211_probe_curchan(struct ieee80211com *ic, int force) 357841ab66cSSepherosa Ziehau { 358841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 359841ab66cSSepherosa Ziehau 360841ab66cSSepherosa Ziehau if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 || force) { 361841ab66cSSepherosa Ziehau /* 362841ab66cSSepherosa Ziehau * XXX send both broadcast+directed probe request 363841ab66cSSepherosa Ziehau */ 364841ab66cSSepherosa Ziehau ieee80211_send_probereq(ic->ic_bss, 365841ab66cSSepherosa Ziehau ic->ic_myaddr, ifp->if_broadcastaddr, 366841ab66cSSepherosa Ziehau ifp->if_broadcastaddr, 367841ab66cSSepherosa Ziehau ic->ic_des_essid, ic->ic_des_esslen, 368841ab66cSSepherosa Ziehau ic->ic_opt_ie, ic->ic_opt_ie_len); 369841ab66cSSepherosa Ziehau } else 370841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN; 371841ab66cSSepherosa Ziehau } 372841ab66cSSepherosa Ziehau 373841ab66cSSepherosa Ziehau static __inline void 374841ab66cSSepherosa Ziehau copy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 375841ab66cSSepherosa Ziehau { 376841ab66cSSepherosa Ziehau /* propagate useful state */ 377841ab66cSSepherosa Ziehau nbss->ni_authmode = obss->ni_authmode; 378841ab66cSSepherosa Ziehau nbss->ni_txpower = obss->ni_txpower; 379841ab66cSSepherosa Ziehau nbss->ni_vlan = obss->ni_vlan; 380841ab66cSSepherosa Ziehau nbss->ni_rsn = obss->ni_rsn; 381b9334f94SSepherosa Ziehau ieee80211_ratectl_data_dup(obss, nbss); 382841ab66cSSepherosa Ziehau /* XXX statistics? */ 383f186073cSJoerg Sonnenberger } 384f186073cSJoerg Sonnenberger 385f186073cSJoerg Sonnenberger void 386f186073cSJoerg Sonnenberger ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) 387f186073cSJoerg Sonnenberger { 388841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 389f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 390f186073cSJoerg Sonnenberger 391841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 392841ab66cSSepherosa Ziehau 393841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 394841ab66cSSepherosa Ziehau "%s: creating ibss\n", __func__); 395841ab66cSSepherosa Ziehau 396841ab66cSSepherosa Ziehau /* 397841ab66cSSepherosa Ziehau * Create the station/neighbor table. Note that for adhoc 398841ab66cSSepherosa Ziehau * mode we make the initial inactivity timer longer since 399841ab66cSSepherosa Ziehau * we create nodes only through discovery and they typically 400841ab66cSSepherosa Ziehau * are long-lived associations. 401841ab66cSSepherosa Ziehau */ 402841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 403841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 404841ab66cSSepherosa Ziehau nt->nt_name = "station"; 405841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_init; 406841ab66cSSepherosa Ziehau } else { 407841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 408841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 409841ab66cSSepherosa Ziehau } 410841ab66cSSepherosa Ziehau 411841ab66cSSepherosa Ziehau ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr); 412841ab66cSSepherosa Ziehau if (ni == NULL) { 413841ab66cSSepherosa Ziehau /* XXX recovery? */ 414841ab66cSSepherosa Ziehau return; 415841ab66cSSepherosa Ziehau } 416f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); 417f186073cSJoerg Sonnenberger ni->ni_esslen = ic->ic_des_esslen; 418f186073cSJoerg Sonnenberger memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); 419841ab66cSSepherosa Ziehau copy_bss(ni, ic->ic_bss); 420841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 421841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) 422f186073cSJoerg Sonnenberger ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 423f186073cSJoerg Sonnenberger if (ic->ic_phytype == IEEE80211_T_FH) { 424f186073cSJoerg Sonnenberger ni->ni_fhdwell = 200; /* XXX */ 425f186073cSJoerg Sonnenberger ni->ni_fhindex = 1; 426f186073cSJoerg Sonnenberger } 427841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS) { 428841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SIBSS; 429841ab66cSSepherosa Ziehau ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 430841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 431841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 432841ab66cSSepherosa Ziehau else 433841ab66cSSepherosa Ziehau ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ 434841ab66cSSepherosa Ziehau } else if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 435841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 436841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 437841ab66cSSepherosa Ziehau else 438841ab66cSSepherosa Ziehau memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 439841ab66cSSepherosa Ziehau } 440841ab66cSSepherosa Ziehau /* 441841ab66cSSepherosa Ziehau * Fix the channel and related attributes. 442841ab66cSSepherosa Ziehau */ 443841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, chan); 444841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 445841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, chan); 446841ab66cSSepherosa Ziehau /* 447841ab66cSSepherosa Ziehau * Do mode-specific rate setup. 448841ab66cSSepherosa Ziehau */ 449841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) { 450841ab66cSSepherosa Ziehau /* 451841ab66cSSepherosa Ziehau * Use a mixed 11b/11g rate set. 452841ab66cSSepherosa Ziehau */ 453841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11G); 454841ab66cSSepherosa Ziehau } else if (ic->ic_curmode == IEEE80211_MODE_11B) { 455841ab66cSSepherosa Ziehau /* 456841ab66cSSepherosa Ziehau * Force pure 11b rate set. 457841ab66cSSepherosa Ziehau */ 458841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11B); 459f186073cSJoerg Sonnenberger } 460f186073cSJoerg Sonnenberger 461841ab66cSSepherosa Ziehau ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 462841ab66cSSepherosa Ziehau } 463841ab66cSSepherosa Ziehau 464841ab66cSSepherosa Ziehau void 465841ab66cSSepherosa Ziehau ieee80211_reset_bss(struct ieee80211com *ic) 466f186073cSJoerg Sonnenberger { 467841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *obss; 468841ab66cSSepherosa Ziehau 469841ab66cSSepherosa Ziehau ieee80211_node_table_reset(&ic->ic_scan); 470841ab66cSSepherosa Ziehau ieee80211_node_table_reset(&ic->ic_sta); 471841ab66cSSepherosa Ziehau 472841ab66cSSepherosa Ziehau ni = ieee80211_alloc_node(&ic->ic_scan, ic->ic_myaddr); 473841ab66cSSepherosa Ziehau KASSERT(ni != NULL, ("unable to setup inital BSS node")); 474841ab66cSSepherosa Ziehau obss = ic->ic_bss; 475841ab66cSSepherosa Ziehau ic->ic_bss = ieee80211_ref_node(ni); 476841ab66cSSepherosa Ziehau if (obss != NULL) { 477841ab66cSSepherosa Ziehau copy_bss(ni, obss); 478841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 479841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 480841ab66cSSepherosa Ziehau } 481841ab66cSSepherosa Ziehau } 482841ab66cSSepherosa Ziehau 483841ab66cSSepherosa Ziehau /* XXX tunable */ 484841ab66cSSepherosa Ziehau #define STA_FAILS_MAX 2 /* assoc failures before ignored */ 485841ab66cSSepherosa Ziehau 486841ab66cSSepherosa Ziehau static int 487841ab66cSSepherosa Ziehau ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) 488841ab66cSSepherosa Ziehau { 489f186073cSJoerg Sonnenberger uint8_t rate; 490f186073cSJoerg Sonnenberger int fail; 491f186073cSJoerg Sonnenberger 492f186073cSJoerg Sonnenberger fail = 0; 493f186073cSJoerg Sonnenberger if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 494f186073cSJoerg Sonnenberger fail |= 0x01; 495f186073cSJoerg Sonnenberger if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 496f186073cSJoerg Sonnenberger ni->ni_chan != ic->ic_des_chan) 497f186073cSJoerg Sonnenberger fail |= 0x01; 498f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 499f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 500f186073cSJoerg Sonnenberger fail |= 0x02; 501f186073cSJoerg Sonnenberger } else { 502f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 503f186073cSJoerg Sonnenberger fail |= 0x02; 504f186073cSJoerg Sonnenberger } 505841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) { 506f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 507f186073cSJoerg Sonnenberger fail |= 0x04; 508f186073cSJoerg Sonnenberger } else { 509f186073cSJoerg Sonnenberger /* XXX does this mean privacy is supported or required? */ 510f186073cSJoerg Sonnenberger if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 511f186073cSJoerg Sonnenberger fail |= 0x04; 512f186073cSJoerg Sonnenberger } 513841ab66cSSepherosa Ziehau rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 514f186073cSJoerg Sonnenberger if (rate & IEEE80211_RATE_BASIC) 515f186073cSJoerg Sonnenberger fail |= 0x08; 516f186073cSJoerg Sonnenberger if (ic->ic_des_esslen != 0 && 517f186073cSJoerg Sonnenberger (ni->ni_esslen != ic->ic_des_esslen || 518f186073cSJoerg Sonnenberger memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) 519f186073cSJoerg Sonnenberger fail |= 0x10; 520f186073cSJoerg Sonnenberger if ((ic->ic_flags & IEEE80211_F_DESBSSID) && 521f186073cSJoerg Sonnenberger !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) 522f186073cSJoerg Sonnenberger fail |= 0x20; 523841ab66cSSepherosa Ziehau if (ni->ni_fails >= STA_FAILS_MAX) 524841ab66cSSepherosa Ziehau fail |= 0x40; 525f186073cSJoerg Sonnenberger #ifdef IEEE80211_DEBUG 526841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 527*a6ec04bcSSascha Wildner kprintf(" %c %6D", 528841ab66cSSepherosa Ziehau fail & 0x40 ? '=' : fail & 0x80 ? '^' : fail ? '-' : '+', 529841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 530*a6ec04bcSSascha Wildner kprintf(" %6D%c", ni->ni_bssid, ":", 531841ab66cSSepherosa Ziehau fail & 0x20 ? '!' : ' '); 532*a6ec04bcSSascha Wildner kprintf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), 533f186073cSJoerg Sonnenberger fail & 0x01 ? '!' : ' '); 534*a6ec04bcSSascha Wildner kprintf(" %+4d", ni->ni_rssi); 535*a6ec04bcSSascha Wildner kprintf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 536f186073cSJoerg Sonnenberger fail & 0x08 ? '!' : ' '); 537*a6ec04bcSSascha Wildner kprintf(" %4s%c", 538f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 539f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 540f186073cSJoerg Sonnenberger "????", 541f186073cSJoerg Sonnenberger fail & 0x02 ? '!' : ' '); 542*a6ec04bcSSascha Wildner kprintf(" %3s%c ", 543f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? 544f186073cSJoerg Sonnenberger "wep" : "no", 545f186073cSJoerg Sonnenberger fail & 0x04 ? '!' : ' '); 546f186073cSJoerg Sonnenberger ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 547*a6ec04bcSSascha Wildner kprintf("%s\n", fail & 0x10 ? "!" : ""); 548f186073cSJoerg Sonnenberger } 549f186073cSJoerg Sonnenberger #endif 550f186073cSJoerg Sonnenberger return fail; 551f186073cSJoerg Sonnenberger } 552f186073cSJoerg Sonnenberger 553841ab66cSSepherosa Ziehau static __inline uint8_t 554841ab66cSSepherosa Ziehau maxrate(const struct ieee80211_node *ni) 555841ab66cSSepherosa Ziehau { 556841ab66cSSepherosa Ziehau const struct ieee80211_rateset *rs = &ni->ni_rates; 557841ab66cSSepherosa Ziehau /* NB: assumes rate set is sorted (happens on frame receive) */ 558841ab66cSSepherosa Ziehau return rs->rs_rates[rs->rs_nrates-1] & IEEE80211_RATE_VAL; 559841ab66cSSepherosa Ziehau } 560841ab66cSSepherosa Ziehau 561841ab66cSSepherosa Ziehau /* 562841ab66cSSepherosa Ziehau * Compare the capabilities of two nodes and decide which is 563841ab66cSSepherosa Ziehau * more desirable (return >0 if a is considered better). Note 564841ab66cSSepherosa Ziehau * that we assume compatibility/usability has already been checked 565841ab66cSSepherosa Ziehau * so we don't need to (e.g. validate whether privacy is supported). 566841ab66cSSepherosa Ziehau * Used to select the best scan candidate for association in a BSS. 567841ab66cSSepherosa Ziehau */ 568841ab66cSSepherosa Ziehau static int 569841ab66cSSepherosa Ziehau ieee80211_node_compare(struct ieee80211com *ic, 570841ab66cSSepherosa Ziehau const struct ieee80211_node *a, 571841ab66cSSepherosa Ziehau const struct ieee80211_node *b) 572841ab66cSSepherosa Ziehau { 573841ab66cSSepherosa Ziehau #define ABS(a) ((a) < 0 ? -(a) : (a)) 574841ab66cSSepherosa Ziehau uint8_t maxa, maxb; 575841ab66cSSepherosa Ziehau uint8_t rssia, rssib; 576841ab66cSSepherosa Ziehau int weight; 577841ab66cSSepherosa Ziehau 578841ab66cSSepherosa Ziehau /* privacy support preferred */ 579841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) && 580841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 581841ab66cSSepherosa Ziehau return 1; 582841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0 && 583841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)) 584841ab66cSSepherosa Ziehau return -1; 585841ab66cSSepherosa Ziehau 586841ab66cSSepherosa Ziehau /* compare count of previous failures */ 587841ab66cSSepherosa Ziehau weight = b->ni_fails - a->ni_fails; 588841ab66cSSepherosa Ziehau if (ABS(weight) > 1) 589841ab66cSSepherosa Ziehau return weight; 590841ab66cSSepherosa Ziehau 591841ab66cSSepherosa Ziehau rssia = ic->ic_node_getrssi(a); 592841ab66cSSepherosa Ziehau rssib = ic->ic_node_getrssi(b); 593841ab66cSSepherosa Ziehau if (ABS(rssib - rssia) < 5) { 594841ab66cSSepherosa Ziehau /* best/max rate preferred if signal level close enough XXX */ 595841ab66cSSepherosa Ziehau maxa = maxrate(a); 596841ab66cSSepherosa Ziehau maxb = maxrate(b); 597841ab66cSSepherosa Ziehau if (maxa != maxb) 598841ab66cSSepherosa Ziehau return maxa - maxb; 599841ab66cSSepherosa Ziehau /* XXX use freq for channel preference */ 600841ab66cSSepherosa Ziehau /* for now just prefer 5Ghz band to all other bands */ 601841ab66cSSepherosa Ziehau if (IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 602841ab66cSSepherosa Ziehau !IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 603841ab66cSSepherosa Ziehau return 1; 604841ab66cSSepherosa Ziehau if (!IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 605841ab66cSSepherosa Ziehau IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 606841ab66cSSepherosa Ziehau return -1; 607841ab66cSSepherosa Ziehau } 608841ab66cSSepherosa Ziehau /* all things being equal, use signal level */ 609841ab66cSSepherosa Ziehau return rssia - rssib; 610841ab66cSSepherosa Ziehau #undef ABS 611841ab66cSSepherosa Ziehau } 612841ab66cSSepherosa Ziehau 613841ab66cSSepherosa Ziehau /* 614841ab66cSSepherosa Ziehau * Mark an ongoing scan stopped. 615841ab66cSSepherosa Ziehau */ 616841ab66cSSepherosa Ziehau void 617841ab66cSSepherosa Ziehau ieee80211_cancel_scan(struct ieee80211com *ic) 618841ab66cSSepherosa Ziehau { 619841ab66cSSepherosa Ziehau 620841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s: end %s scan\n", 621841ab66cSSepherosa Ziehau __func__, 622841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); 623841ab66cSSepherosa Ziehau 624841ab66cSSepherosa Ziehau ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN); 625841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 626841ab66cSSepherosa Ziehau } 627841ab66cSSepherosa Ziehau 628f186073cSJoerg Sonnenberger /* 629f186073cSJoerg Sonnenberger * Complete a scan of potential channels. 630f186073cSJoerg Sonnenberger */ 631f186073cSJoerg Sonnenberger void 632841ab66cSSepherosa Ziehau ieee80211_end_scan(struct ieee80211com *ic) 633f186073cSJoerg Sonnenberger { 634841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 635841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *selbs; 636f186073cSJoerg Sonnenberger 637841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 638841ab66cSSepherosa Ziehau 639841ab66cSSepherosa Ziehau ieee80211_cancel_scan(ic); 640841ab66cSSepherosa Ziehau ieee80211_notify_scan_done(ic); 641f186073cSJoerg Sonnenberger 642f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 643841ab66cSSepherosa Ziehau uint8_t maxrssi[IEEE80211_CHAN_MAX]; /* XXX off stack? */ 644841ab66cSSepherosa Ziehau int i, bestchan; 645841ab66cSSepherosa Ziehau uint8_t rssi; 646841ab66cSSepherosa Ziehau 647f186073cSJoerg Sonnenberger /* 648f186073cSJoerg Sonnenberger * The passive scan to look for existing AP's completed, 649f186073cSJoerg Sonnenberger * select a channel to camp on. Identify the channels 650f186073cSJoerg Sonnenberger * that already have one or more AP's and try to locate 651841ab66cSSepherosa Ziehau * an unoccupied one. If that fails, pick a channel that 652841ab66cSSepherosa Ziehau * looks to be quietest. 653f186073cSJoerg Sonnenberger */ 654841ab66cSSepherosa Ziehau memset(maxrssi, 0, sizeof(maxrssi)); 655841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 656841ab66cSSepherosa Ziehau rssi = ic->ic_node_getrssi(ni); 657841ab66cSSepherosa Ziehau i = ieee80211_chan2ieee(ic, ni->ni_chan); 658841ab66cSSepherosa Ziehau if (rssi > maxrssi[i]) 659841ab66cSSepherosa Ziehau maxrssi[i] = rssi; 660f186073cSJoerg Sonnenberger } 661841ab66cSSepherosa Ziehau /* XXX select channel more intelligently */ 662841ab66cSSepherosa Ziehau bestchan = -1; 663f186073cSJoerg Sonnenberger for (i = 0; i < IEEE80211_CHAN_MAX; i++) 664841ab66cSSepherosa Ziehau if (isset(ic->ic_chan_active, i)) { 665841ab66cSSepherosa Ziehau /* 666841ab66cSSepherosa Ziehau * If the channel is unoccupied the max rssi 667841ab66cSSepherosa Ziehau * should be zero; just take it. Otherwise 668841ab66cSSepherosa Ziehau * track the channel with the lowest rssi and 669841ab66cSSepherosa Ziehau * use that when all channels appear occupied. 670841ab66cSSepherosa Ziehau */ 671841ab66cSSepherosa Ziehau if (maxrssi[i] == 0) { 672841ab66cSSepherosa Ziehau bestchan = i; 673f186073cSJoerg Sonnenberger break; 674f186073cSJoerg Sonnenberger } 675841ab66cSSepherosa Ziehau if (bestchan == -1 || 676841ab66cSSepherosa Ziehau maxrssi[i] < maxrssi[bestchan]) 677841ab66cSSepherosa Ziehau bestchan = i; 678841ab66cSSepherosa Ziehau } 679841ab66cSSepherosa Ziehau if (bestchan != -1) { 680841ab66cSSepherosa Ziehau ieee80211_create_ibss(ic, &ic->ic_channels[bestchan]); 681f186073cSJoerg Sonnenberger return; 682f186073cSJoerg Sonnenberger } 683841ab66cSSepherosa Ziehau /* no suitable channel, should not happen */ 684841ab66cSSepherosa Ziehau } 685841ab66cSSepherosa Ziehau 686841ab66cSSepherosa Ziehau /* 687841ab66cSSepherosa Ziehau * When manually sequencing the state machine; scan just once 688841ab66cSSepherosa Ziehau * regardless of whether we have a candidate or not. The 689841ab66cSSepherosa Ziehau * controlling application is expected to setup state and 690841ab66cSSepherosa Ziehau * initiate an association. 691841ab66cSSepherosa Ziehau */ 692841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_MANUAL) 693841ab66cSSepherosa Ziehau return; 694841ab66cSSepherosa Ziehau /* 695841ab66cSSepherosa Ziehau * Automatic sequencing; look for a candidate and 696841ab66cSSepherosa Ziehau * if found join the network. 697841ab66cSSepherosa Ziehau */ 698841ab66cSSepherosa Ziehau /* NB: unlocked read should be ok */ 699841ab66cSSepherosa Ziehau if (TAILQ_FIRST(&nt->nt_node) == NULL) { 700841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 701841ab66cSSepherosa Ziehau "%s: no scan candidate\n", __func__); 702f186073cSJoerg Sonnenberger notfound: 703f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS && 704f186073cSJoerg Sonnenberger (ic->ic_flags & IEEE80211_F_IBSSON) && 705f186073cSJoerg Sonnenberger ic->ic_des_esslen != 0) { 706f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_ibss_chan); 707f186073cSJoerg Sonnenberger return; 708f186073cSJoerg Sonnenberger } 709f186073cSJoerg Sonnenberger /* 710841ab66cSSepherosa Ziehau * Decrement the failure counts so entries will be 711841ab66cSSepherosa Ziehau * reconsidered the next time around. We really want 712841ab66cSSepherosa Ziehau * to do this only for sta's where we've previously 713841ab66cSSepherosa Ziehau * had some success. 714841ab66cSSepherosa Ziehau */ 715841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 716841ab66cSSepherosa Ziehau if (ni->ni_fails) 717841ab66cSSepherosa Ziehau ni->ni_fails--; 718841ab66cSSepherosa Ziehau /* 719f186073cSJoerg Sonnenberger * Reset the list of channels to scan and start again. 720f186073cSJoerg Sonnenberger */ 721841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 722841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 723841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 724f186073cSJoerg Sonnenberger return; 725f186073cSJoerg Sonnenberger } 726f186073cSJoerg Sonnenberger selbs = NULL; 727841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "\t%s\n", 728841ab66cSSepherosa Ziehau "macaddr bssid chan rssi rate flag wep essid"); 729841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 730841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) == 0) { 731f186073cSJoerg Sonnenberger if (selbs == NULL) 732f186073cSJoerg Sonnenberger selbs = ni; 733841ab66cSSepherosa Ziehau else if (ieee80211_node_compare(ic, ni, selbs) > 0) 734f186073cSJoerg Sonnenberger selbs = ni; 735f186073cSJoerg Sonnenberger } 736f186073cSJoerg Sonnenberger } 737841ab66cSSepherosa Ziehau if (selbs != NULL) /* NB: grab ref while dropping lock */ 738841ab66cSSepherosa Ziehau ieee80211_ref_node(selbs); 739f186073cSJoerg Sonnenberger if (selbs == NULL) 740f186073cSJoerg Sonnenberger goto notfound; 741841ab66cSSepherosa Ziehau if (!ieee80211_sta_join(ic, selbs)) { 742841ab66cSSepherosa Ziehau ieee80211_free_node(selbs); 743841ab66cSSepherosa Ziehau goto notfound; 744841ab66cSSepherosa Ziehau } 745841ab66cSSepherosa Ziehau } 746841ab66cSSepherosa Ziehau 747841ab66cSSepherosa Ziehau /* 748841ab66cSSepherosa Ziehau * Handle 802.11 ad hoc network merge. The 749841ab66cSSepherosa Ziehau * convention, set by the Wireless Ethernet Compatibility Alliance 750841ab66cSSepherosa Ziehau * (WECA), is that an 802.11 station will change its BSSID to match 751841ab66cSSepherosa Ziehau * the "oldest" 802.11 ad hoc network, on the same channel, that 752841ab66cSSepherosa Ziehau * has the station's desired SSID. The "oldest" 802.11 network 753841ab66cSSepherosa Ziehau * sends beacons with the greatest TSF timestamp. 754841ab66cSSepherosa Ziehau * 755841ab66cSSepherosa Ziehau * The caller is assumed to validate TSF's before attempting a merge. 756841ab66cSSepherosa Ziehau * 757841ab66cSSepherosa Ziehau * Return !0 if the BSSID changed, 0 otherwise. 758841ab66cSSepherosa Ziehau */ 759841ab66cSSepherosa Ziehau int 760841ab66cSSepherosa Ziehau ieee80211_ibss_merge(struct ieee80211_node *ni) 761841ab66cSSepherosa Ziehau { 762841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 763841ab66cSSepherosa Ziehau 764841ab66cSSepherosa Ziehau if (ni == ic->ic_bss || 765841ab66cSSepherosa Ziehau IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { 766841ab66cSSepherosa Ziehau /* unchanged, nothing to do */ 767841ab66cSSepherosa Ziehau return 0; 768841ab66cSSepherosa Ziehau } 769841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) != 0) { /* capabilities mismatch */ 770841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 771841ab66cSSepherosa Ziehau "%s: merge failed, capabilities mismatch\n", __func__); 772841ab66cSSepherosa Ziehau ic->ic_stats.is_ibss_capmismatch++; 773841ab66cSSepherosa Ziehau return 0; 774841ab66cSSepherosa Ziehau } 775841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 776841ab66cSSepherosa Ziehau "%6D: new bssid %s: %s preamble, %s slot time%s\n", __func__, 777841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 778841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 779841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 780841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 781841ab66cSSepherosa Ziehau ); 782841ab66cSSepherosa Ziehau return ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 783841ab66cSSepherosa Ziehau } 784841ab66cSSepherosa Ziehau 785841ab66cSSepherosa Ziehau /* 786841ab66cSSepherosa Ziehau * Join the specified IBSS/BSS network. The node is assumed to 787841ab66cSSepherosa Ziehau * be passed in with a held reference. 788841ab66cSSepherosa Ziehau */ 789841ab66cSSepherosa Ziehau int 790841ab66cSSepherosa Ziehau ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) 791841ab66cSSepherosa Ziehau { 792841ab66cSSepherosa Ziehau struct ieee80211_node *obss; 793841ab66cSSepherosa Ziehau 794841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 795841ab66cSSepherosa Ziehau 796f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 797841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 798f186073cSJoerg Sonnenberger /* 799841ab66cSSepherosa Ziehau * Delete unusable rates; we've already checked 800841ab66cSSepherosa Ziehau * that the negotiated rate set is acceptable. 801f186073cSJoerg Sonnenberger */ 802841ab66cSSepherosa Ziehau ieee80211_fix_rate(selbs, IEEE80211_F_DODEL); 803841ab66cSSepherosa Ziehau /* 804841ab66cSSepherosa Ziehau * Fillin the neighbor table; it will already 805841ab66cSSepherosa Ziehau * exist if we are simply switching mastership. 806841ab66cSSepherosa Ziehau * XXX ic_sta always setup so this is unnecessary? 807841ab66cSSepherosa Ziehau */ 808841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 809841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 810841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 811f186073cSJoerg Sonnenberger } 812841ab66cSSepherosa Ziehau 813841ab66cSSepherosa Ziehau /* 814841ab66cSSepherosa Ziehau * Committed to selbs, setup state. 815841ab66cSSepherosa Ziehau */ 816841ab66cSSepherosa Ziehau obss = ic->ic_bss; 817841ab66cSSepherosa Ziehau ic->ic_bss = selbs; /* NB: caller assumed to bump refcnt */ 818841ab66cSSepherosa Ziehau if (obss != NULL) { 819841ab66cSSepherosa Ziehau copy_bss(selbs, obss); 820841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 821841ab66cSSepherosa Ziehau } 822841ab66cSSepherosa Ziehau /* 823841ab66cSSepherosa Ziehau * Set the erp state (mostly the slot time) to deal with 824841ab66cSSepherosa Ziehau * the auto-select case; this should be redundant if the 825841ab66cSSepherosa Ziehau * mode is locked. 826841ab66cSSepherosa Ziehau */ 827841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan); 828841ab66cSSepherosa Ziehau ic->ic_curchan = selbs->ni_chan; 829841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 830841ab66cSSepherosa Ziehau ieee80211_wme_initparams(ic); 831841ab66cSSepherosa Ziehau 832841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA) 833841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 834841ab66cSSepherosa Ziehau else 835841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 836841ab66cSSepherosa Ziehau return 1; 837841ab66cSSepherosa Ziehau } 838841ab66cSSepherosa Ziehau 839841ab66cSSepherosa Ziehau /* 840841ab66cSSepherosa Ziehau * Leave the specified IBSS/BSS network. The node is assumed to 841841ab66cSSepherosa Ziehau * be passed in with a held reference. 842841ab66cSSepherosa Ziehau */ 843841ab66cSSepherosa Ziehau void 844841ab66cSSepherosa Ziehau ieee80211_sta_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 845841ab66cSSepherosa Ziehau { 846841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 847841ab66cSSepherosa Ziehau ieee80211_notify_node_leave(ic, ni); 848f186073cSJoerg Sonnenberger } 849f186073cSJoerg Sonnenberger 850f186073cSJoerg Sonnenberger static struct ieee80211_node * 851841ab66cSSepherosa Ziehau node_alloc(struct ieee80211_node_table *nt) 852f186073cSJoerg Sonnenberger { 853f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 854841ab66cSSepherosa Ziehau 855efda3bd0SMatthew Dillon ni = kmalloc(sizeof(struct ieee80211_node), M_80211_NODE, 856841ab66cSSepherosa Ziehau M_NOWAIT | M_ZERO); 857f186073cSJoerg Sonnenberger return ni; 858f186073cSJoerg Sonnenberger } 859f186073cSJoerg Sonnenberger 860841ab66cSSepherosa Ziehau /* 861841ab66cSSepherosa Ziehau * Reclaim any resources in a node and reset any critical 862841ab66cSSepherosa Ziehau * state. Typically nodes are free'd immediately after, 863841ab66cSSepherosa Ziehau * but in some cases the storage may be reused so we need 864841ab66cSSepherosa Ziehau * to insure consistent state (should probably fix that). 865841ab66cSSepherosa Ziehau */ 866f186073cSJoerg Sonnenberger static void 867841ab66cSSepherosa Ziehau node_cleanup(struct ieee80211_node *ni) 868f186073cSJoerg Sonnenberger { 869841ab66cSSepherosa Ziehau #define N(a) (sizeof(a)/sizeof(a[0])) 870841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 871841ab66cSSepherosa Ziehau int i, qlen; 872841ab66cSSepherosa Ziehau 873841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 874841ab66cSSepherosa Ziehau 875841ab66cSSepherosa Ziehau /* NB: preserve ni_table */ 876841ab66cSSepherosa Ziehau if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 877841ab66cSSepherosa Ziehau ic->ic_ps_sta--; 878841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 879841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, 880841ab66cSSepherosa Ziehau "[%6D] power save mode off, %u sta's in ps mode\n", 881841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_ps_sta); 882841ab66cSSepherosa Ziehau } 883841ab66cSSepherosa Ziehau /* 884841ab66cSSepherosa Ziehau * Clear AREF flag that marks the authorization refcnt bump 885841ab66cSSepherosa Ziehau * has happened. This is probably not needed as the node 886841ab66cSSepherosa Ziehau * should always be removed from the table so not found but 887841ab66cSSepherosa Ziehau * do it just in case. 888841ab66cSSepherosa Ziehau */ 889841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AREF; 890841ab66cSSepherosa Ziehau 891841ab66cSSepherosa Ziehau /* 892841ab66cSSepherosa Ziehau * Drain power save queue and, if needed, clear TIM. 893841ab66cSSepherosa Ziehau */ 894841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DRAIN(ni, qlen); 895841ab66cSSepherosa Ziehau if (qlen != 0 && ic->ic_set_tim != NULL) 896841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 897841ab66cSSepherosa Ziehau 898841ab66cSSepherosa Ziehau ni->ni_associd = 0; 899841ab66cSSepherosa Ziehau if (ni->ni_challenge != NULL) { 900efda3bd0SMatthew Dillon kfree(ni->ni_challenge, M_DEVBUF); 901841ab66cSSepherosa Ziehau ni->ni_challenge = NULL; 902841ab66cSSepherosa Ziehau } 903841ab66cSSepherosa Ziehau /* 904841ab66cSSepherosa Ziehau * Preserve SSID, WPA, and WME ie's so the bss node is 905841ab66cSSepherosa Ziehau * reusable during a re-auth/re-assoc state transition. 906841ab66cSSepherosa Ziehau * If we remove these data they will not be recreated 907841ab66cSSepherosa Ziehau * because they come from a probe-response or beacon frame 908841ab66cSSepherosa Ziehau * which cannot be expected prior to the association-response. 909841ab66cSSepherosa Ziehau * This should not be an issue when operating in other modes 910841ab66cSSepherosa Ziehau * as stations leaving always go through a full state transition 911841ab66cSSepherosa Ziehau * which will rebuild this state. 912841ab66cSSepherosa Ziehau * 913841ab66cSSepherosa Ziehau * XXX does this leave us open to inheriting old state? 914841ab66cSSepherosa Ziehau */ 915841ab66cSSepherosa Ziehau for (i = 0; i < N(ni->ni_rxfrag); i++) 916841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[i] != NULL) { 917841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[i]); 918841ab66cSSepherosa Ziehau ni->ni_rxfrag[i] = NULL; 919841ab66cSSepherosa Ziehau } 920841ab66cSSepherosa Ziehau /* 921841ab66cSSepherosa Ziehau * Must be careful here to remove any key map entry w/o a LOR. 922841ab66cSSepherosa Ziehau */ 923841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(ni); 924841ab66cSSepherosa Ziehau #undef N 925f186073cSJoerg Sonnenberger } 926f186073cSJoerg Sonnenberger 927f186073cSJoerg Sonnenberger static void 928841ab66cSSepherosa Ziehau node_free(struct ieee80211_node *ni) 929f186073cSJoerg Sonnenberger { 930841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 931841ab66cSSepherosa Ziehau 932841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 933841ab66cSSepherosa Ziehau if (ni->ni_wpa_ie != NULL) 934efda3bd0SMatthew Dillon kfree(ni->ni_wpa_ie, M_DEVBUF); 935841ab66cSSepherosa Ziehau if (ni->ni_wme_ie != NULL) 936efda3bd0SMatthew Dillon kfree(ni->ni_wme_ie, M_DEVBUF); 937841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DESTROY(ni); 938efda3bd0SMatthew Dillon kfree(ni, M_80211_NODE); 939f186073cSJoerg Sonnenberger } 940f186073cSJoerg Sonnenberger 941f186073cSJoerg Sonnenberger static uint8_t 942841ab66cSSepherosa Ziehau node_getrssi(const struct ieee80211_node *ni) 943f186073cSJoerg Sonnenberger { 944f186073cSJoerg Sonnenberger return ni->ni_rssi; 945f186073cSJoerg Sonnenberger } 946f186073cSJoerg Sonnenberger 947f186073cSJoerg Sonnenberger static void 948841ab66cSSepherosa Ziehau ieee80211_setup_node(struct ieee80211_node_table *nt, 949841ab66cSSepherosa Ziehau struct ieee80211_node *ni, const uint8_t *macaddr) 950f186073cSJoerg Sonnenberger { 951841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 952f186073cSJoerg Sonnenberger int hash; 953f186073cSJoerg Sonnenberger 954841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 955841ab66cSSepherosa Ziehau 956841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 95789625b06SSepherosa Ziehau "%s %p<%6D> in %s table\n", __func__, ni, 958841ab66cSSepherosa Ziehau macaddr, ":", nt->nt_name); 959841ab66cSSepherosa Ziehau 960f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 961f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 962841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 963841ab66cSSepherosa Ziehau ni->ni_chan = IEEE80211_CHAN_ANYC; 964841ab66cSSepherosa Ziehau ni->ni_authmode = IEEE80211_AUTH_OPEN; 965841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 966841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 967841ab66cSSepherosa Ziehau ni->ni_inact_reload = nt->nt_inact_init; 968841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 969841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 970841ab66cSSepherosa Ziehau 971841ab66cSSepherosa Ziehau TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 972841ab66cSSepherosa Ziehau LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 973841ab66cSSepherosa Ziehau ni->ni_table = nt; 974841ab66cSSepherosa Ziehau ni->ni_ic = ic; 975b9334f94SSepherosa Ziehau 976b9334f94SSepherosa Ziehau ieee80211_ratectl_data_alloc(ni); 977f186073cSJoerg Sonnenberger } 978f186073cSJoerg Sonnenberger 979f186073cSJoerg Sonnenberger struct ieee80211_node * 980841ab66cSSepherosa Ziehau ieee80211_alloc_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 981f186073cSJoerg Sonnenberger { 982841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 983841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 984841ab66cSSepherosa Ziehau 985841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 986f186073cSJoerg Sonnenberger if (ni != NULL) 987841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 988f186073cSJoerg Sonnenberger else 989f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 990f186073cSJoerg Sonnenberger return ni; 991f186073cSJoerg Sonnenberger } 992f186073cSJoerg Sonnenberger 993841ab66cSSepherosa Ziehau /* 994841ab66cSSepherosa Ziehau * Craft a temporary node suitable for sending a management frame 995841ab66cSSepherosa Ziehau * to the specified station. We craft only as much state as we 996841ab66cSSepherosa Ziehau * need to do the work since the node will be immediately reclaimed 997841ab66cSSepherosa Ziehau * once the send completes. 998841ab66cSSepherosa Ziehau */ 999f186073cSJoerg Sonnenberger struct ieee80211_node * 1000841ab66cSSepherosa Ziehau ieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr) 1001f186073cSJoerg Sonnenberger { 1002841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1003841ab66cSSepherosa Ziehau 1004841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(&ic->ic_sta); 1005f186073cSJoerg Sonnenberger if (ni != NULL) { 1006841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1007841ab66cSSepherosa Ziehau "%s %p<%6D>\n", __func__, ni, macaddr, ":"); 1008841ab66cSSepherosa Ziehau 1009841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1010841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1011841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 1012841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1013841ab66cSSepherosa Ziehau /* NB: required by ieee80211_fix_rate */ 1014841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1015841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, 1016841ab66cSSepherosa Ziehau IEEE80211_KEYIX_NONE); 1017841ab66cSSepherosa Ziehau /* XXX optimize away */ 1018841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 1019841ab66cSSepherosa Ziehau 1020841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* NB: pedantic */ 1021841ab66cSSepherosa Ziehau ni->ni_ic = ic; 1022b9334f94SSepherosa Ziehau 1023b9334f94SSepherosa Ziehau ieee80211_ratectl_data_alloc(ni); 1024841ab66cSSepherosa Ziehau } else { 1025841ab66cSSepherosa Ziehau /* XXX msg */ 1026841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1027841ab66cSSepherosa Ziehau } 1028841ab66cSSepherosa Ziehau return ni; 1029841ab66cSSepherosa Ziehau } 1030841ab66cSSepherosa Ziehau 1031841ab66cSSepherosa Ziehau struct ieee80211_node * 1032841ab66cSSepherosa Ziehau ieee80211_dup_bss(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1033841ab66cSSepherosa Ziehau { 1034841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1035841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1036841ab66cSSepherosa Ziehau 1037841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1038841ab66cSSepherosa Ziehau if (ni != NULL) { 1039841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 1040f186073cSJoerg Sonnenberger /* 1041f186073cSJoerg Sonnenberger * Inherit from ic_bss. 1042f186073cSJoerg Sonnenberger */ 1043841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1044841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1045841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1046f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1047841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1048841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1049f186073cSJoerg Sonnenberger } else 1050f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 1051f186073cSJoerg Sonnenberger return ni; 1052f186073cSJoerg Sonnenberger } 1053f186073cSJoerg Sonnenberger 1054f186073cSJoerg Sonnenberger static struct ieee80211_node * 1055841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1056841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1057841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1058841ab66cSSepherosa Ziehau #else 1059841ab66cSSepherosa Ziehau _ieee80211_find_node(struct ieee80211_node_table *nt, 1060841ab66cSSepherosa Ziehau const uint8_t *macaddr) 1061841ab66cSSepherosa Ziehau #endif 1062f186073cSJoerg Sonnenberger { 1063f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1064f186073cSJoerg Sonnenberger int hash; 1065f186073cSJoerg Sonnenberger 1066f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1067841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1068f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1069841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1070841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1071841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1072841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1073841ab66cSSepherosa Ziehau func, line, 1074841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1075841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1076841ab66cSSepherosa Ziehau #endif 1077f186073cSJoerg Sonnenberger return ni; 1078f186073cSJoerg Sonnenberger } 1079f186073cSJoerg Sonnenberger } 1080f186073cSJoerg Sonnenberger return NULL; 1081f186073cSJoerg Sonnenberger } 1082841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1083841ab66cSSepherosa Ziehau #define _ieee80211_find_node(nt, mac) \ 1084841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(nt, mac, func, line) 1085841ab66cSSepherosa Ziehau #endif 1086f186073cSJoerg Sonnenberger 1087f186073cSJoerg Sonnenberger struct ieee80211_node * 1088841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1089841ab66cSSepherosa Ziehau ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1090841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1091841ab66cSSepherosa Ziehau #else 1092841ab66cSSepherosa Ziehau ieee80211_find_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1093841ab66cSSepherosa Ziehau #endif 1094f186073cSJoerg Sonnenberger { 1095f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1096f186073cSJoerg Sonnenberger 1097841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1098841ab66cSSepherosa Ziehau 1099841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1100f186073cSJoerg Sonnenberger return ni; 1101f186073cSJoerg Sonnenberger } 1102f186073cSJoerg Sonnenberger 1103f186073cSJoerg Sonnenberger /* 1104841ab66cSSepherosa Ziehau * Fake up a node; this handles node discovery in adhoc mode. 1105841ab66cSSepherosa Ziehau * Note that for the driver's benefit we we treat this like 1106841ab66cSSepherosa Ziehau * an association so the driver has an opportunity to setup 1107841ab66cSSepherosa Ziehau * it's private state. 1108841ab66cSSepherosa Ziehau */ 1109841ab66cSSepherosa Ziehau struct ieee80211_node * 1110841ab66cSSepherosa Ziehau ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, 1111841ab66cSSepherosa Ziehau const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1112841ab66cSSepherosa Ziehau { 1113841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1114841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1115841ab66cSSepherosa Ziehau 1116841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1117841ab66cSSepherosa Ziehau "%s: mac<%6D>\n", __func__, macaddr, ":"); 1118841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(nt, macaddr); 1119841ab66cSSepherosa Ziehau if (ni != NULL) { 1120841ab66cSSepherosa Ziehau /* XXX no rate negotiation; just dup */ 1121841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_bss->ni_rates; 1122b9334f94SSepherosa Ziehau 1123b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, 1); 1124b9334f94SSepherosa Ziehau 1125841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1126841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1127b9334f94SSepherosa Ziehau 1128841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1129841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1130841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 1131841ab66cSSepherosa Ziehau /* 1132841ab66cSSepherosa Ziehau * Blindly propagate capabilities based on the 1133841ab66cSSepherosa Ziehau * local configuration. In particular this permits 1134841ab66cSSepherosa Ziehau * us to use QoS to disable ACK's. 1135841ab66cSSepherosa Ziehau */ 1136841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_WME) 1137841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_QOS; 1138841ab66cSSepherosa Ziehau } 1139841ab66cSSepherosa Ziehau } 1140841ab66cSSepherosa Ziehau return ni; 1141841ab66cSSepherosa Ziehau } 1142841ab66cSSepherosa Ziehau 1143841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1144841ab66cSSepherosa Ziehau static void 1145841ab66cSSepherosa Ziehau dump_probe_beacon(uint8_t subtype, int isnew, 1146841ab66cSSepherosa Ziehau const uint8_t mac[IEEE80211_ADDR_LEN], 1147841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1148841ab66cSSepherosa Ziehau { 1149841ab66cSSepherosa Ziehau 1150*a6ec04bcSSascha Wildner kprintf("[%6D] %s%s on chan %u (bss chan %u) ", 1151841ab66cSSepherosa Ziehau mac, ":", isnew ? "new " : "", 1152841ab66cSSepherosa Ziehau ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], 1153841ab66cSSepherosa Ziehau sp->chan, sp->bchan); 1154841ab66cSSepherosa Ziehau ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); 1155*a6ec04bcSSascha Wildner kprintf("\n"); 1156841ab66cSSepherosa Ziehau 1157841ab66cSSepherosa Ziehau if (isnew) { 1158*a6ec04bcSSascha Wildner kprintf("[%6D] caps 0x%x bintval %u erp 0x%x", 1159841ab66cSSepherosa Ziehau mac, ":", sp->capinfo, sp->bintval, sp->erp); 1160841ab66cSSepherosa Ziehau if (sp->country != NULL) { 1161841ab66cSSepherosa Ziehau #if defined(__FreeBSD__) || defined(__DragonFly__) 1162*a6ec04bcSSascha Wildner kprintf(" country info %*D", 1163841ab66cSSepherosa Ziehau sp->country[1], sp->country+2, " "); 1164841ab66cSSepherosa Ziehau #else 1165841ab66cSSepherosa Ziehau int i; 1166*a6ec04bcSSascha Wildner kprintf(" country info"); 1167841ab66cSSepherosa Ziehau for (i = 0; i < sp->country[1]; i++) 1168*a6ec04bcSSascha Wildner kprintf(" %02x", sp->country[i+2]); 1169841ab66cSSepherosa Ziehau #endif 1170841ab66cSSepherosa Ziehau } 1171*a6ec04bcSSascha Wildner kprintf("\n"); 1172841ab66cSSepherosa Ziehau } 1173841ab66cSSepherosa Ziehau } 1174841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 1175841ab66cSSepherosa Ziehau 1176841ab66cSSepherosa Ziehau static void 1177841ab66cSSepherosa Ziehau saveie(uint8_t **iep, const uint8_t *ie) 1178841ab66cSSepherosa Ziehau { 1179841ab66cSSepherosa Ziehau 1180841ab66cSSepherosa Ziehau if (ie == NULL) 1181841ab66cSSepherosa Ziehau *iep = NULL; 1182841ab66cSSepherosa Ziehau else 1183841ab66cSSepherosa Ziehau ieee80211_saveie(iep, ie); 1184841ab66cSSepherosa Ziehau } 1185841ab66cSSepherosa Ziehau 1186841ab66cSSepherosa Ziehau /* 1187841ab66cSSepherosa Ziehau * Process a beacon or probe response frame. 1188841ab66cSSepherosa Ziehau */ 1189841ab66cSSepherosa Ziehau void 1190841ab66cSSepherosa Ziehau ieee80211_add_scan(struct ieee80211com *ic, 1191841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp, 1192841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1193841ab66cSSepherosa Ziehau int subtype, int rssi, int rstamp) 1194841ab66cSSepherosa Ziehau { 1195841ab66cSSepherosa Ziehau #define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1196841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 1197841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1198841ab66cSSepherosa Ziehau int newnode = 0; 1199841ab66cSSepherosa Ziehau 1200841ab66cSSepherosa Ziehau ni = ieee80211_find_node(nt, wh->i_addr2); 1201841ab66cSSepherosa Ziehau if (ni == NULL) { 1202841ab66cSSepherosa Ziehau /* 1203841ab66cSSepherosa Ziehau * Create a new entry. 1204841ab66cSSepherosa Ziehau */ 1205841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1206841ab66cSSepherosa Ziehau if (ni == NULL) { 1207841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1208841ab66cSSepherosa Ziehau return; 1209841ab66cSSepherosa Ziehau } 1210841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, wh->i_addr2); 1211841ab66cSSepherosa Ziehau /* 1212841ab66cSSepherosa Ziehau * XXX inherit from ic_bss. 1213841ab66cSSepherosa Ziehau */ 1214841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1215841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1216841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1217841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_curchan); 1218841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1219841ab66cSSepherosa Ziehau newnode = 1; 1220841ab66cSSepherosa Ziehau } 1221841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1222841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN)) 1223841ab66cSSepherosa Ziehau dump_probe_beacon(subtype, newnode, wh->i_addr2, sp); 1224841ab66cSSepherosa Ziehau #endif 1225841ab66cSSepherosa Ziehau /* XXX ap beaconing multiple ssid w/ same bssid */ 1226841ab66cSSepherosa Ziehau if (sp->ssid[1] != 0 && 1227841ab66cSSepherosa Ziehau (ISPROBE(subtype) || ni->ni_esslen == 0)) { 1228841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1229841ab66cSSepherosa Ziehau memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); 1230841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1231841ab66cSSepherosa Ziehau } 1232841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1233841ab66cSSepherosa Ziehau ni->ni_rssi = rssi; 1234841ab66cSSepherosa Ziehau ni->ni_rstamp = rstamp; 1235841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1236841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1237841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1238841ab66cSSepherosa Ziehau ni->ni_chan = &ic->ic_channels[sp->chan]; 1239841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1240841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1241841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1242841ab66cSSepherosa Ziehau if (sp->tim != NULL) { 1243841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *ie = 1244841ab66cSSepherosa Ziehau (struct ieee80211_tim_ie *) sp->tim; 1245841ab66cSSepherosa Ziehau 1246841ab66cSSepherosa Ziehau ni->ni_dtim_count = ie->tim_count; 1247841ab66cSSepherosa Ziehau ni->ni_dtim_period = ie->tim_period; 1248841ab66cSSepherosa Ziehau } 1249841ab66cSSepherosa Ziehau /* 1250841ab66cSSepherosa Ziehau * Record the byte offset from the mac header to 1251841ab66cSSepherosa Ziehau * the start of the TIM information element for 1252841ab66cSSepherosa Ziehau * use by hardware and/or to speedup software 1253841ab66cSSepherosa Ziehau * processing of beacon frames. 1254841ab66cSSepherosa Ziehau */ 1255841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1256841ab66cSSepherosa Ziehau /* 1257841ab66cSSepherosa Ziehau * Record optional information elements that might be 1258841ab66cSSepherosa Ziehau * used by applications or drivers. 1259841ab66cSSepherosa Ziehau */ 1260841ab66cSSepherosa Ziehau saveie(&ni->ni_wme_ie, sp->wme); 1261841ab66cSSepherosa Ziehau saveie(&ni->ni_wpa_ie, sp->wpa); 1262841ab66cSSepherosa Ziehau 1263841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1264841ab66cSSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); 1265841ab66cSSepherosa Ziehau 1266841ab66cSSepherosa Ziehau if (!newnode) 1267841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1268841ab66cSSepherosa Ziehau #undef ISPROBE 1269841ab66cSSepherosa Ziehau } 1270841ab66cSSepherosa Ziehau 1271841ab66cSSepherosa Ziehau void 1272841ab66cSSepherosa Ziehau ieee80211_init_neighbor(struct ieee80211_node *ni, 1273841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1274841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1275841ab66cSSepherosa Ziehau { 1276841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 127789625b06SSepherosa Ziehau "%s: %p<%6D>\n", __func__, ni, ni->ni_macaddr, ":"); 1278841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1279841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1280841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1281841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1282841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1283841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1284841ab66cSSepherosa Ziehau ni->ni_chan = ni->ni_ic->ic_curchan; 1285841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1286841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1287841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1288841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1289841ab66cSSepherosa Ziehau if (sp->wme != NULL) 1290841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wme_ie, sp->wme); 1291841ab66cSSepherosa Ziehau if (sp->wpa != NULL) 1292841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa); 1293841ab66cSSepherosa Ziehau 1294841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1295841ab66cSSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); 1296476d885dSSepherosa Ziehau IEEE80211_PRINT_NODERATES(ni->ni_ic, ni, IEEE80211_MSG_NODE); 1297841ab66cSSepherosa Ziehau } 1298841ab66cSSepherosa Ziehau 1299841ab66cSSepherosa Ziehau /* 1300841ab66cSSepherosa Ziehau * Do node discovery in adhoc mode on receipt of a beacon 1301841ab66cSSepherosa Ziehau * or probe response frame. Note that for the driver's 1302841ab66cSSepherosa Ziehau * benefit we we treat this like an association so the 1303841ab66cSSepherosa Ziehau * driver has an opportunity to setup it's private state. 1304841ab66cSSepherosa Ziehau */ 1305841ab66cSSepherosa Ziehau struct ieee80211_node * 1306841ab66cSSepherosa Ziehau ieee80211_add_neighbor(struct ieee80211com *ic, 1307841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1308841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1309841ab66cSSepherosa Ziehau { 1310841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1311841ab66cSSepherosa Ziehau 1312841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1313841ab66cSSepherosa Ziehau "%s: mac<%s>\n", __func__, wh->i_addr2, ":"); 1314841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */ 1315841ab66cSSepherosa Ziehau if (ni != NULL) { 1316841ab66cSSepherosa Ziehau ieee80211_init_neighbor(ni, wh, sp); 1317b9334f94SSepherosa Ziehau 1318b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, 1); 1319b9334f94SSepherosa Ziehau 1320841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1321841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1322b9334f94SSepherosa Ziehau 1323841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1324841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1325841ab66cSSepherosa Ziehau } 1326841ab66cSSepherosa Ziehau return ni; 1327841ab66cSSepherosa Ziehau } 1328841ab66cSSepherosa Ziehau 1329841ab66cSSepherosa Ziehau #define IS_CTL(wh) \ 1330841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 1331841ab66cSSepherosa Ziehau #define IS_PSPOLL(wh) \ 1332841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) 1333841ab66cSSepherosa Ziehau /* 1334841ab66cSSepherosa Ziehau * Locate the node for sender, track state, and then pass the 1335841ab66cSSepherosa Ziehau * (referenced) node up to the 802.11 layer for its use. We 1336841ab66cSSepherosa Ziehau * are required to pass some node so we fall back to ic_bss 1337841ab66cSSepherosa Ziehau * when this frame is from an unknown sender. The 802.11 layer 1338841ab66cSSepherosa Ziehau * knows this means the sender wasn't in the node table and 1339841ab66cSSepherosa Ziehau * acts accordingly. 1340841ab66cSSepherosa Ziehau */ 1341841ab66cSSepherosa Ziehau struct ieee80211_node * 1342841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1343841ab66cSSepherosa Ziehau ieee80211_find_rxnode_debug(struct ieee80211com *ic, 1344841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, const char *func, int line) 1345841ab66cSSepherosa Ziehau #else 1346841ab66cSSepherosa Ziehau ieee80211_find_rxnode(struct ieee80211com *ic, 1347841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh) 1348841ab66cSSepherosa Ziehau #endif 1349841ab66cSSepherosa Ziehau { 1350841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1351841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1352841ab66cSSepherosa Ziehau 1353841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1354841ab66cSSepherosa Ziehau 1355841ab66cSSepherosa Ziehau /* XXX may want scanned nodes in the neighbor table for adhoc */ 1356841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1357841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1358841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1359841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1360841ab66cSSepherosa Ziehau else 1361841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1362841ab66cSSepherosa Ziehau /* XXX check ic_bss first in station mode */ 1363841ab66cSSepherosa Ziehau /* XXX 4-address frames? */ 1364841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1365841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1366841ab66cSSepherosa Ziehau else 1367841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1368841ab66cSSepherosa Ziehau if (ni == NULL) 1369841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1370841ab66cSSepherosa Ziehau 1371841ab66cSSepherosa Ziehau return ni; 1372841ab66cSSepherosa Ziehau } 1373841ab66cSSepherosa Ziehau 1374841ab66cSSepherosa Ziehau /* 1375841ab66cSSepherosa Ziehau * Like ieee80211_find_rxnode but use the supplied h/w 1376841ab66cSSepherosa Ziehau * key index as a hint to locate the node in the key 1377841ab66cSSepherosa Ziehau * mapping table. If an entry is present at the key 1378841ab66cSSepherosa Ziehau * index we return it; otherwise do a normal lookup and 1379841ab66cSSepherosa Ziehau * update the mapping table if the station has a unicast 1380841ab66cSSepherosa Ziehau * key assigned to it. 1381841ab66cSSepherosa Ziehau */ 1382841ab66cSSepherosa Ziehau struct ieee80211_node * 1383841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1384841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1385841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1386841ab66cSSepherosa Ziehau const char *func, int line) 1387841ab66cSSepherosa Ziehau #else 1388841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1389841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1390841ab66cSSepherosa Ziehau #endif 1391841ab66cSSepherosa Ziehau { 1392841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1393841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1394841ab66cSSepherosa Ziehau 1395841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1396841ab66cSSepherosa Ziehau 1397841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1398841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1399841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1400841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1401841ab66cSSepherosa Ziehau else 1402841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1403841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1404841ab66cSSepherosa Ziehau ni = nt->nt_keyixmap[keyix]; 1405841ab66cSSepherosa Ziehau else 1406841ab66cSSepherosa Ziehau ni = NULL; 1407841ab66cSSepherosa Ziehau if (ni == NULL) { 1408841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1409841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1410841ab66cSSepherosa Ziehau else 1411841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1412841ab66cSSepherosa Ziehau if (ni == NULL) 1413841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1414841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 1415841ab66cSSepherosa Ziehau /* 1416841ab66cSSepherosa Ziehau * If the station has a unicast key cache slot 1417841ab66cSSepherosa Ziehau * assigned update the key->node mapping table. 1418841ab66cSSepherosa Ziehau */ 1419841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1420841ab66cSSepherosa Ziehau /* XXX can keyixmap[keyix] != NULL? */ 1421841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1422841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == NULL) { 1423841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1424841ab66cSSepherosa Ziehau "%s: add key map entry %p<%6D> refcnt %d\n", 1425841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1426841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 1427841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1428841ab66cSSepherosa Ziehau } 1429841ab66cSSepherosa Ziehau } 1430841ab66cSSepherosa Ziehau } else { 1431841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1432841ab66cSSepherosa Ziehau } 1433841ab66cSSepherosa Ziehau 1434841ab66cSSepherosa Ziehau return ni; 1435841ab66cSSepherosa Ziehau } 1436841ab66cSSepherosa Ziehau #undef IS_PSPOLL 1437841ab66cSSepherosa Ziehau #undef IS_CTL 1438841ab66cSSepherosa Ziehau 1439841ab66cSSepherosa Ziehau /* 1440f186073cSJoerg Sonnenberger * Return a reference to the appropriate node for sending 1441f186073cSJoerg Sonnenberger * a data frame. This handles node discovery in adhoc networks. 1442f186073cSJoerg Sonnenberger */ 1443f186073cSJoerg Sonnenberger struct ieee80211_node * 1444841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1445841ab66cSSepherosa Ziehau ieee80211_find_txnode_debug(struct ieee80211com *ic, const uint8_t *macaddr, 1446841ab66cSSepherosa Ziehau const char *func, int line) 1447841ab66cSSepherosa Ziehau #else 1448841ab66cSSepherosa Ziehau ieee80211_find_txnode(struct ieee80211com *ic, const uint8_t *macaddr) 1449841ab66cSSepherosa Ziehau #endif 1450f186073cSJoerg Sonnenberger { 1451841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1452f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1453841ab66cSSepherosa Ziehau 1454841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1455f186073cSJoerg Sonnenberger 1456f186073cSJoerg Sonnenberger /* 1457f186073cSJoerg Sonnenberger * The destination address should be in the node table 1458841ab66cSSepherosa Ziehau * unless this is a multicast/broadcast frame. We can 1459841ab66cSSepherosa Ziehau * also optimize station mode operation, all frames go 1460841ab66cSSepherosa Ziehau * to the bss node. 1461f186073cSJoerg Sonnenberger */ 1462a6226bb4SSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1463a6226bb4SSepherosa Ziehau IEEE80211_IS_MULTICAST(macaddr)) { 1464841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1465a6226bb4SSepherosa Ziehau } else { 1466841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1467a6226bb4SSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1468a6226bb4SSepherosa Ziehau (ni != NULL && ni->ni_associd == 0)) { 1469a6226bb4SSepherosa Ziehau /* 1470a6226bb4SSepherosa Ziehau * Station is not associated; don't permit the 1471a6226bb4SSepherosa Ziehau * data frame to be sent by returning NULL. This 1472a6226bb4SSepherosa Ziehau * is kinda a kludge but the least intrusive way 1473a6226bb4SSepherosa Ziehau * to add this check into all drivers. 1474a6226bb4SSepherosa Ziehau */ 1475a6226bb4SSepherosa Ziehau ieee80211_unref_node(&ni); /* NB: null's ni */ 1476a6226bb4SSepherosa Ziehau } 1477a6226bb4SSepherosa Ziehau } 1478f186073cSJoerg Sonnenberger 1479841ab66cSSepherosa Ziehau if (ni == NULL) { 1480841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS || 1481841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO) { 1482f186073cSJoerg Sonnenberger /* 1483841ab66cSSepherosa Ziehau * In adhoc mode cons up a node for the destination. 1484841ab66cSSepherosa Ziehau * Note that we need an additional reference for the 1485841ab66cSSepherosa Ziehau * caller to be consistent with _ieee80211_find_node. 1486f186073cSJoerg Sonnenberger */ 1487841ab66cSSepherosa Ziehau ni = ieee80211_fakeup_adhoc_node(nt, macaddr); 1488841ab66cSSepherosa Ziehau if (ni != NULL) 1489841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1490841ab66cSSepherosa Ziehau } else { 1491841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, 1492841ab66cSSepherosa Ziehau "[%6D] no node, discard frame (%s)\n", 1493841ab66cSSepherosa Ziehau macaddr, ":", __func__); 1494841ab66cSSepherosa Ziehau ic->ic_stats.is_tx_nonode++; 1495f186073cSJoerg Sonnenberger } 1496f186073cSJoerg Sonnenberger } 1497f186073cSJoerg Sonnenberger return ni; 1498f186073cSJoerg Sonnenberger } 1499f186073cSJoerg Sonnenberger 1500f186073cSJoerg Sonnenberger /* 1501f186073cSJoerg Sonnenberger * Like find but search based on the channel too. 1502f186073cSJoerg Sonnenberger */ 1503f186073cSJoerg Sonnenberger struct ieee80211_node * 1504841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1505841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel_debug(struct ieee80211_node_table *nt, 1506841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan, 1507841ab66cSSepherosa Ziehau const char *func, int line) 1508841ab66cSSepherosa Ziehau #else 1509841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel(struct ieee80211_node_table *nt, 1510841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan) 1511841ab66cSSepherosa Ziehau #endif 1512f186073cSJoerg Sonnenberger { 1513f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1514f186073cSJoerg Sonnenberger int hash; 1515841ab66cSSepherosa Ziehau 1516841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1517f186073cSJoerg Sonnenberger 1518f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1519841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1520f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1521f186073cSJoerg Sonnenberger ni->ni_chan == chan) { 1522841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1523841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 15245d004897SSepherosa Ziehau REFCNT_LOC, ni, ni->ni_macaddr, ":", 1525841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1526f186073cSJoerg Sonnenberger break; 1527f186073cSJoerg Sonnenberger } 1528f186073cSJoerg Sonnenberger } 1529f186073cSJoerg Sonnenberger return ni; 1530f186073cSJoerg Sonnenberger } 1531f186073cSJoerg Sonnenberger 1532841ab66cSSepherosa Ziehau /* 1533841ab66cSSepherosa Ziehau * Like find but search based on the ssid too. 1534841ab66cSSepherosa Ziehau */ 1535841ab66cSSepherosa Ziehau struct ieee80211_node * 1536841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1537841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid_debug(struct ieee80211_node_table *nt, 1538841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid, 1539841ab66cSSepherosa Ziehau const char *func, int line) 1540841ab66cSSepherosa Ziehau #else 1541841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid(struct ieee80211_node_table *nt, 1542841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid) 1543841ab66cSSepherosa Ziehau #endif 1544f186073cSJoerg Sonnenberger { 1545841ab66cSSepherosa Ziehau #define MATCH_SSID(ni, ssid, ssidlen) \ 1546841ab66cSSepherosa Ziehau (ni->ni_esslen == ssidlen && memcmp(ni->ni_essid, ssid, ssidlen) == 0) 1547841ab66cSSepherosa Ziehau static const uint8_t zeromac[IEEE80211_ADDR_LEN]; 1548841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1549f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1550841ab66cSSepherosa Ziehau int hash; 1551f186073cSJoerg Sonnenberger 1552841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1553841ab66cSSepherosa Ziehau 1554841ab66cSSepherosa Ziehau /* 1555841ab66cSSepherosa Ziehau * A mac address that is all zero means match only the ssid; 1556841ab66cSSepherosa Ziehau * otherwise we must match both. 1557841ab66cSSepherosa Ziehau */ 1558841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(macaddr, zeromac)) { 1559841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1560841ab66cSSepherosa Ziehau if (MATCH_SSID(ni, ssid, ssidlen)) 1561841ab66cSSepherosa Ziehau break; 1562841ab66cSSepherosa Ziehau } 1563841ab66cSSepherosa Ziehau } else { 1564841ab66cSSepherosa Ziehau hash = IEEE80211_NODE_HASH(macaddr); 1565841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1566841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1567841ab66cSSepherosa Ziehau MATCH_SSID(ni, ssid, ssidlen)) 1568841ab66cSSepherosa Ziehau break; 1569841ab66cSSepherosa Ziehau } 1570841ab66cSSepherosa Ziehau } 1571841ab66cSSepherosa Ziehau if (ni != NULL) { 1572841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1573841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 15745d004897SSepherosa Ziehau REFCNT_LOC, ni, ni->ni_macaddr, ":", 1575841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1576841ab66cSSepherosa Ziehau } 1577841ab66cSSepherosa Ziehau return ni; 1578841ab66cSSepherosa Ziehau #undef MATCH_SSID 1579841ab66cSSepherosa Ziehau } 1580841ab66cSSepherosa Ziehau 1581841ab66cSSepherosa Ziehau static void 1582841ab66cSSepherosa Ziehau _ieee80211_free_node(struct ieee80211_node *ni) 1583841ab66cSSepherosa Ziehau { 1584841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1585841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1586841ab66cSSepherosa Ziehau 1587841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1588841ab66cSSepherosa Ziehau "%s %p<%6D> in %s table\n", __func__, ni, 1589841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1590841ab66cSSepherosa Ziehau nt != NULL ? nt->nt_name : "<gone>"); 1591841ab66cSSepherosa Ziehau 1592b9334f94SSepherosa Ziehau ieee80211_ratectl_data_free(ni); 1593b9334f94SSepherosa Ziehau 1594841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1595841ab66cSSepherosa Ziehau if (nt != NULL) { 1596841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1597841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1598841ab66cSSepherosa Ziehau } 1599841ab66cSSepherosa Ziehau ic->ic_node_free(ni); 1600841ab66cSSepherosa Ziehau } 1601841ab66cSSepherosa Ziehau 1602841ab66cSSepherosa Ziehau void 1603841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1604841ab66cSSepherosa Ziehau ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1605841ab66cSSepherosa Ziehau #else 1606841ab66cSSepherosa Ziehau ieee80211_free_node(struct ieee80211_node *ni) 1607841ab66cSSepherosa Ziehau #endif 1608841ab66cSSepherosa Ziehau { 1609841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1610841ab66cSSepherosa Ziehau 1611841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ni->ni_ic->ic_ifp->if_serializer); 1612841ab66cSSepherosa Ziehau 1613841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1614841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1615841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, func, line, ni, 1616841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni) - 1); 1617841ab66cSSepherosa Ziehau #endif 1618841ab66cSSepherosa Ziehau if (nt != NULL) { 1619841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) { 1620841ab66cSSepherosa Ziehau /* 1621841ab66cSSepherosa Ziehau * Last reference, reclaim state. 1622841ab66cSSepherosa Ziehau */ 1623841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1624841ab66cSSepherosa Ziehau } else if (ieee80211_node_refcnt(ni) == 1 && 1625841ab66cSSepherosa Ziehau nt->nt_keyixmap != NULL) { 1626841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1627841ab66cSSepherosa Ziehau /* 1628841ab66cSSepherosa Ziehau * Check for a last reference in the key mapping table. 1629841ab66cSSepherosa Ziehau */ 1630841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1631841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1632841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1633841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1634841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry", __func__, 1635841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":"); 1636841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1637841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* XXX needed? */ 1638841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1639841ab66cSSepherosa Ziehau } 1640841ab66cSSepherosa Ziehau } 1641841ab66cSSepherosa Ziehau } else { 1642841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) 1643841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1644841ab66cSSepherosa Ziehau } 1645f186073cSJoerg Sonnenberger } 1646f186073cSJoerg Sonnenberger 1647f186073cSJoerg Sonnenberger /* 1648841ab66cSSepherosa Ziehau * Reclaim a unicast key and clear any key cache state. 1649841ab66cSSepherosa Ziehau */ 1650841ab66cSSepherosa Ziehau int 1651841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(struct ieee80211_node *ni) 1652841ab66cSSepherosa Ziehau { 1653841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1654841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1655841ab66cSSepherosa Ziehau struct ieee80211_node *nikey; 1656841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1657841ab66cSSepherosa Ziehau int status; 1658841ab66cSSepherosa Ziehau 1659841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1660841ab66cSSepherosa Ziehau 1661841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1662841ab66cSSepherosa Ziehau status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey); 1663841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1664841ab66cSSepherosa Ziehau nikey = nt->nt_keyixmap[keyix]; 1665fc6d0222SSascha Wildner nt->nt_keyixmap[keyix] = NULL; 1666841ab66cSSepherosa Ziehau } else 1667841ab66cSSepherosa Ziehau nikey = NULL; 1668841ab66cSSepherosa Ziehau 1669841ab66cSSepherosa Ziehau if (nikey != NULL) { 1670841ab66cSSepherosa Ziehau KASSERT(nikey == ni, 1671841ab66cSSepherosa Ziehau ("key map out of sync, ni %p nikey %p", ni, nikey)); 1672841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1673841ab66cSSepherosa Ziehau "%s: delete key map entry %p<%6D> refcnt %d\n", 1674841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1675841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)-1); 1676841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1677841ab66cSSepherosa Ziehau } 1678841ab66cSSepherosa Ziehau return status; 1679841ab66cSSepherosa Ziehau } 1680841ab66cSSepherosa Ziehau 1681841ab66cSSepherosa Ziehau /* 1682841ab66cSSepherosa Ziehau * Reclaim a node. If this is the last reference count then 1683841ab66cSSepherosa Ziehau * do the normal free work. Otherwise remove it from the node 1684841ab66cSSepherosa Ziehau * table and mark it gone by clearing the back-reference. 1685841ab66cSSepherosa Ziehau */ 1686841ab66cSSepherosa Ziehau static void 1687841ab66cSSepherosa Ziehau node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1688841ab66cSSepherosa Ziehau { 1689841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1690841ab66cSSepherosa Ziehau 1691841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1692841ab66cSSepherosa Ziehau 1693841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1694841ab66cSSepherosa Ziehau "%s: remove %p<%6D> from %s table, refcnt %d\n", 1695841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1696841ab66cSSepherosa Ziehau nt->nt_name, ieee80211_node_refcnt(ni)-1); 1697b9334f94SSepherosa Ziehau 1698b9334f94SSepherosa Ziehau ieee80211_ratectl_data_free(ni); 1699b9334f94SSepherosa Ziehau 1700841ab66cSSepherosa Ziehau /* 1701841ab66cSSepherosa Ziehau * Clear any entry in the unicast key mapping table. 1702841ab66cSSepherosa Ziehau * We need to do it here so rx lookups don't find it 1703841ab66cSSepherosa Ziehau * in the mapping table even if it's not in the hash 1704841ab66cSSepherosa Ziehau * table. We cannot depend on the mapping table entry 1705841ab66cSSepherosa Ziehau * being cleared because the node may not be free'd. 1706841ab66cSSepherosa Ziehau */ 1707841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1708841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1709841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1710841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1711841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry\n", 1712841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":"); 1713841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1714841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* NB: don't need free */ 1715841ab66cSSepherosa Ziehau } 1716841ab66cSSepherosa Ziehau if (!ieee80211_node_dectestref(ni)) { 1717841ab66cSSepherosa Ziehau /* 1718841ab66cSSepherosa Ziehau * Other references are present, just remove the 1719841ab66cSSepherosa Ziehau * node from the table so it cannot be found. When 1720841ab66cSSepherosa Ziehau * the references are dropped storage will be 1721841ab66cSSepherosa Ziehau * reclaimed. 1722841ab66cSSepherosa Ziehau */ 1723841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1724841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1725841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* clear reference */ 1726841ab66cSSepherosa Ziehau } else 1727841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1728841ab66cSSepherosa Ziehau } 1729841ab66cSSepherosa Ziehau 1730841ab66cSSepherosa Ziehau static void 1731841ab66cSSepherosa Ziehau ieee80211_free_allnodes(struct ieee80211_node_table *nt) 1732841ab66cSSepherosa Ziehau { 1733841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1734841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1735841ab66cSSepherosa Ziehau 1736841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1737841ab66cSSepherosa Ziehau "%s: free all nodes in %s table\n", __func__, nt->nt_name); 1738841ab66cSSepherosa Ziehau 1739841ab66cSSepherosa Ziehau while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) { 1740841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1741841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 1742841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 1743841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1744841ab66cSSepherosa Ziehau } 1745841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1746841ab66cSSepherosa Ziehau } 1747841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 1748841ab66cSSepherosa Ziehau } 1749841ab66cSSepherosa Ziehau 1750841ab66cSSepherosa Ziehau /* 1751841ab66cSSepherosa Ziehau * Timeout entries in the scan cache. 1752841ab66cSSepherosa Ziehau */ 1753841ab66cSSepherosa Ziehau static void 1754841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates(struct ieee80211_node_table *nt) 1755841ab66cSSepherosa Ziehau { 1756841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1757841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *tni; 1758841ab66cSSepherosa Ziehau 1759841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1760841ab66cSSepherosa Ziehau 1761841ab66cSSepherosa Ziehau ni = ic->ic_bss; 1762841ab66cSSepherosa Ziehau /* XXX belongs elsewhere */ 1763841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && ticks > ni->ni_rxfragstamp + hz) { 1764841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1765841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1766841ab66cSSepherosa Ziehau } 1767841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, tni) { 1768841ab66cSSepherosa Ziehau if (ni->ni_inact && --ni->ni_inact == 0) { 1769841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1770841ab66cSSepherosa Ziehau "[%6D] scan candidate purged from cache " 1771841ab66cSSepherosa Ziehau "(refcnt %u)\n", ni->ni_macaddr, ":", 1772841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1773841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1774841ab66cSSepherosa Ziehau } 1775841ab66cSSepherosa Ziehau } 1776841ab66cSSepherosa Ziehau 1777841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1778841ab66cSSepherosa Ziehau } 1779841ab66cSSepherosa Ziehau 1780841ab66cSSepherosa Ziehau /* 1781841ab66cSSepherosa Ziehau * Timeout inactive stations and do related housekeeping. 1782841ab66cSSepherosa Ziehau * Note that we cannot hold the node lock while sending a 1783841ab66cSSepherosa Ziehau * frame as this would lead to a LOR. Instead we use a 1784841ab66cSSepherosa Ziehau * generation number to mark nodes that we've scanned and 1785841ab66cSSepherosa Ziehau * drop the lock and restart a scan if we have to time out 1786841ab66cSSepherosa Ziehau * a node. Since we are single-threaded by virtue of 1787f186073cSJoerg Sonnenberger * controlling the inactivity timer we can be sure this will 1788f186073cSJoerg Sonnenberger * process each node only once. 1789f186073cSJoerg Sonnenberger */ 1790841ab66cSSepherosa Ziehau static void 1791841ab66cSSepherosa Ziehau ieee80211_timeout_stations(struct ieee80211_node_table *nt) 1792f186073cSJoerg Sonnenberger { 1793841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1794841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1795841ab66cSSepherosa Ziehau int isadhoc; 1796f186073cSJoerg Sonnenberger 1797841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1798841ab66cSSepherosa Ziehau 1799841ab66cSSepherosa Ziehau isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS || 1800841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO); 1801841ab66cSSepherosa Ziehau 1802841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) { 1803f186073cSJoerg Sonnenberger /* 1804841ab66cSSepherosa Ziehau * Ignore entries for which have yet to receive an 1805841ab66cSSepherosa Ziehau * authentication frame. These are transient and 1806841ab66cSSepherosa Ziehau * will be reclaimed when the last reference to them 1807841ab66cSSepherosa Ziehau * goes away (when frame xmits complete). 1808f186073cSJoerg Sonnenberger */ 1809841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1810841ab66cSSepherosa Ziehau (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1811841ab66cSSepherosa Ziehau continue; 1812841ab66cSSepherosa Ziehau /* 1813841ab66cSSepherosa Ziehau * Free fragment if not needed anymore 1814841ab66cSSepherosa Ziehau * (last fragment older than 1s). 1815841ab66cSSepherosa Ziehau * XXX doesn't belong here 1816841ab66cSSepherosa Ziehau */ 1817841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && 1818841ab66cSSepherosa Ziehau ticks > ni->ni_rxfragstamp + hz) { 1819841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1820841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1821841ab66cSSepherosa Ziehau } 1822841ab66cSSepherosa Ziehau /* 1823841ab66cSSepherosa Ziehau * Special case ourself; we may be idle for extended periods 1824841ab66cSSepherosa Ziehau * of time and regardless reclaiming our state is wrong. 1825841ab66cSSepherosa Ziehau */ 1826841ab66cSSepherosa Ziehau if (ni == ic->ic_bss) 1827841ab66cSSepherosa Ziehau continue; 1828841ab66cSSepherosa Ziehau ni->ni_inact--; 1829841ab66cSSepherosa Ziehau if (ni->ni_associd != 0 || isadhoc) { 1830841ab66cSSepherosa Ziehau /* 1831841ab66cSSepherosa Ziehau * Age frames on the power save queue. The 1832841ab66cSSepherosa Ziehau * aging interval is 4 times the listen 1833841ab66cSSepherosa Ziehau * interval specified by the station. This 1834841ab66cSSepherosa Ziehau * number is factored into the age calculations 1835841ab66cSSepherosa Ziehau * when the frame is placed on the queue. We 1836841ab66cSSepherosa Ziehau * store ages as time differences we can check 1837841ab66cSSepherosa Ziehau * and/or adjust only the head of the list. 1838841ab66cSSepherosa Ziehau */ 1839841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) { 1840841ab66cSSepherosa Ziehau struct mbuf *m; 1841841ab66cSSepherosa Ziehau int discard = 0; 1842841ab66cSSepherosa Ziehau 1843841ab66cSSepherosa Ziehau while (IF_POLL(&ni->ni_savedq, m) != NULL && 1844841ab66cSSepherosa Ziehau M_AGE_GET(m) < IEEE80211_INACT_WAIT) { 1845841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1846841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1847841ab66cSSepherosa Ziehau "[%6D] discard frame, age %u\n", 1848841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1849841ab66cSSepherosa Ziehau M_AGE_GET(m));/*XXX*/ 1850841ab66cSSepherosa Ziehau _IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m); 1851841ab66cSSepherosa Ziehau m_freem(m); 1852841ab66cSSepherosa Ziehau discard++; 1853841ab66cSSepherosa Ziehau } 1854841ab66cSSepherosa Ziehau if (m != NULL) 1855841ab66cSSepherosa Ziehau M_AGE_SUB(m, IEEE80211_INACT_WAIT); 1856841ab66cSSepherosa Ziehau 1857841ab66cSSepherosa Ziehau if (discard != 0) { 1858841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1859841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1860841ab66cSSepherosa Ziehau "[%6D] discard %u frames for age\n", 1861841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1862841ab66cSSepherosa Ziehau discard); 1863841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_ADD(ni, 1864841ab66cSSepherosa Ziehau ps_discard, discard); 1865841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) 1866841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 1867841ab66cSSepherosa Ziehau } 1868841ab66cSSepherosa Ziehau } 1869841ab66cSSepherosa Ziehau /* 1870841ab66cSSepherosa Ziehau * Probe the station before time it out. We 1871841ab66cSSepherosa Ziehau * send a null data frame which may not be 1872841ab66cSSepherosa Ziehau * universally supported by drivers (need it 1873841ab66cSSepherosa Ziehau * for ps-poll support so it should be...). 1874841ab66cSSepherosa Ziehau */ 1875841ab66cSSepherosa Ziehau if (0 < ni->ni_inact && 1876841ab66cSSepherosa Ziehau ni->ni_inact <= ic->ic_inact_probe) { 1877841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1878841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 1879841ab66cSSepherosa Ziehau ni, "%s", 1880841ab66cSSepherosa Ziehau "probe station due to inactivity"); 1881841ab66cSSepherosa Ziehau /* 1882841ab66cSSepherosa Ziehau * Grab a reference before unlocking the table 1883841ab66cSSepherosa Ziehau * so the node cannot be reclaimed before we 1884841ab66cSSepherosa Ziehau * send the frame. ieee80211_send_nulldata 1885841ab66cSSepherosa Ziehau * understands we've done this and reclaims the 1886841ab66cSSepherosa Ziehau * ref for us as needed. 1887841ab66cSSepherosa Ziehau */ 1888841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1889841ab66cSSepherosa Ziehau ieee80211_send_nulldata(ni); 1890841ab66cSSepherosa Ziehau /* XXX stat? */ 1891841ab66cSSepherosa Ziehau continue; 1892841ab66cSSepherosa Ziehau } 1893841ab66cSSepherosa Ziehau } 1894841ab66cSSepherosa Ziehau if (ni->ni_inact <= 0) { 1895841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1896841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 1897841ab66cSSepherosa Ziehau "station timed out due to inactivity " 1898841ab66cSSepherosa Ziehau "(refcnt %u)", ieee80211_node_refcnt(ni)); 1899841ab66cSSepherosa Ziehau /* 1900841ab66cSSepherosa Ziehau * Send a deauthenticate frame and drop the station. 1901841ab66cSSepherosa Ziehau * This is somewhat complicated due to reference counts 1902841ab66cSSepherosa Ziehau * and locking. At this point a station will typically 1903841ab66cSSepherosa Ziehau * have a reference count of 1. ieee80211_node_leave 1904841ab66cSSepherosa Ziehau * will do a "free" of the node which will drop the 1905841ab66cSSepherosa Ziehau * reference count. But in the meantime a reference 1906841ab66cSSepherosa Ziehau * wil be held by the deauth frame. The actual reclaim 1907841ab66cSSepherosa Ziehau * of the node will happen either after the tx is 1908841ab66cSSepherosa Ziehau * completed or by ieee80211_node_leave. 1909841ab66cSSepherosa Ziehau */ 1910841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1911f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1912f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 1913f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_EXPIRE); 1914841ab66cSSepherosa Ziehau } 1915841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 1916f186073cSJoerg Sonnenberger ic->ic_stats.is_node_timeout++; 1917841ab66cSSepherosa Ziehau continue; 1918f186073cSJoerg Sonnenberger } 1919f186073cSJoerg Sonnenberger } 1920841ab66cSSepherosa Ziehau 1921841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1922f186073cSJoerg Sonnenberger } 1923f186073cSJoerg Sonnenberger 1924f186073cSJoerg Sonnenberger void 1925841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg) 1926f186073cSJoerg Sonnenberger { 1927841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1928f186073cSJoerg Sonnenberger 1929841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1930841ab66cSSepherosa Ziehau 1931841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) 1932841ab66cSSepherosa Ziehau f(arg, ni); 1933841ab66cSSepherosa Ziehau } 1934841ab66cSSepherosa Ziehau 1935841ab66cSSepherosa Ziehau void 1936841ab66cSSepherosa Ziehau ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1937841ab66cSSepherosa Ziehau { 1938*a6ec04bcSSascha Wildner kprintf("0x%p: mac %6D refcnt %d\n", ni, 1939841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)); 1940*a6ec04bcSSascha Wildner kprintf("\tauthmode %u flags 0x%x\n", 1941841ab66cSSepherosa Ziehau ni->ni_authmode, ni->ni_flags); 1942*a6ec04bcSSascha Wildner kprintf("\tassocid 0x%x txpower %u vlan %u\n", 1943841ab66cSSepherosa Ziehau ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 1944*a6ec04bcSSascha Wildner kprintf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 1945841ab66cSSepherosa Ziehau ni->ni_txseqs[0], 1946841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] >> IEEE80211_SEQ_SEQ_SHIFT, 1947841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] & IEEE80211_SEQ_FRAG_MASK, 1948841ab66cSSepherosa Ziehau ni->ni_rxfragstamp); 1949*a6ec04bcSSascha Wildner kprintf("\trstamp %u rssi %u intval %u capinfo 0x%x\n", 1950841ab66cSSepherosa Ziehau ni->ni_rstamp, ni->ni_rssi, ni->ni_intval, ni->ni_capinfo); 1951*a6ec04bcSSascha Wildner kprintf("\tbssid %6D essid \"%.*s\" channel %u:0x%x\n", 1952841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 1953841ab66cSSepherosa Ziehau ni->ni_esslen, ni->ni_essid, 1954841ab66cSSepherosa Ziehau ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 1955*a6ec04bcSSascha Wildner kprintf("\tfails %u inact %u txrate %u\n", 1956841ab66cSSepherosa Ziehau ni->ni_fails, ni->ni_inact, ni->ni_txrate); 1957841ab66cSSepherosa Ziehau } 1958841ab66cSSepherosa Ziehau 1959841ab66cSSepherosa Ziehau void 1960841ab66cSSepherosa Ziehau ieee80211_dump_nodes(struct ieee80211_node_table *nt) 1961841ab66cSSepherosa Ziehau { 1962841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(nt, 1963841ab66cSSepherosa Ziehau (ieee80211_iter_func *) ieee80211_dump_node, nt); 1964841ab66cSSepherosa Ziehau } 1965841ab66cSSepherosa Ziehau 1966841ab66cSSepherosa Ziehau /* 1967841ab66cSSepherosa Ziehau * Handle a station joining an 11g network. 1968841ab66cSSepherosa Ziehau */ 1969841ab66cSSepherosa Ziehau static void 1970841ab66cSSepherosa Ziehau ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 1971841ab66cSSepherosa Ziehau { 1972841ab66cSSepherosa Ziehau 1973841ab66cSSepherosa Ziehau /* 1974841ab66cSSepherosa Ziehau * Station isn't capable of short slot time. Bump 1975841ab66cSSepherosa Ziehau * the count of long slot time stations and disable 1976841ab66cSSepherosa Ziehau * use of short slot time. Note that the actual switch 1977841ab66cSSepherosa Ziehau * over to long slot time use may not occur until the 1978841ab66cSSepherosa Ziehau * next beacon transmission (per sec. 7.3.1.4 of 11g). 1979841ab66cSSepherosa Ziehau */ 1980841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 1981841ab66cSSepherosa Ziehau ic->ic_longslotsta++; 1982841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1983841ab66cSSepherosa Ziehau "[%6D] station needs long slot time, count %d\n", 1984841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 1985841ab66cSSepherosa Ziehau /* XXX vap's w/ conflicting needs won't work */ 1986841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 0); 1987841ab66cSSepherosa Ziehau } 1988841ab66cSSepherosa Ziehau /* 1989841ab66cSSepherosa Ziehau * If the new station is not an ERP station 1990841ab66cSSepherosa Ziehau * then bump the counter and enable protection 1991841ab66cSSepherosa Ziehau * if configured. 1992841ab66cSSepherosa Ziehau */ 1993841ab66cSSepherosa Ziehau if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) { 1994841ab66cSSepherosa Ziehau ic->ic_nonerpsta++; 1995841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1996841ab66cSSepherosa Ziehau "[%6D] station is !ERP, %d non-ERP stations associated\n", 1997841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 1998841ab66cSSepherosa Ziehau /* 1999841ab66cSSepherosa Ziehau * If protection is configured, enable it. 2000841ab66cSSepherosa Ziehau */ 2001841ab66cSSepherosa Ziehau if (ic->ic_protmode != IEEE80211_PROT_NONE) { 2002841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2003841ab66cSSepherosa Ziehau "%s: enable use of protection\n", __func__); 2004841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEPROT; 2005841ab66cSSepherosa Ziehau } 2006841ab66cSSepherosa Ziehau /* 2007841ab66cSSepherosa Ziehau * If station does not support short preamble 2008841ab66cSSepherosa Ziehau * then we must enable use of Barker preamble. 2009841ab66cSSepherosa Ziehau */ 2010841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 2011841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2012841ab66cSSepherosa Ziehau "[%6D] station needs long preamble\n", 2013841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 2014ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, 0); 2015841ab66cSSepherosa Ziehau } 2016841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 1) 2017841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2018841ab66cSSepherosa Ziehau } else 2019841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_ERP; 2020841ab66cSSepherosa Ziehau } 2021841ab66cSSepherosa Ziehau 2022841ab66cSSepherosa Ziehau void 2023841ab66cSSepherosa Ziehau ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) 2024841ab66cSSepherosa Ziehau { 2025841ab66cSSepherosa Ziehau int newassoc; 2026841ab66cSSepherosa Ziehau 2027841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) { 2028841ab66cSSepherosa Ziehau uint16_t aid; 2029841ab66cSSepherosa Ziehau 2030841ab66cSSepherosa Ziehau /* 2031841ab66cSSepherosa Ziehau * It would be good to search the bitmap 2032841ab66cSSepherosa Ziehau * more efficiently, but this will do for now. 2033841ab66cSSepherosa Ziehau */ 2034841ab66cSSepherosa Ziehau for (aid = 1; aid < ic->ic_max_aid; aid++) { 2035841ab66cSSepherosa Ziehau if (!IEEE80211_AID_ISSET(aid, 2036841ab66cSSepherosa Ziehau ic->ic_aid_bitmap)) 2037841ab66cSSepherosa Ziehau break; 2038841ab66cSSepherosa Ziehau } 2039841ab66cSSepherosa Ziehau if (aid >= ic->ic_max_aid) { 2040841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, 2041841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_TOOMANY); 2042841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 2043841ab66cSSepherosa Ziehau return; 2044841ab66cSSepherosa Ziehau } 2045841ab66cSSepherosa Ziehau ni->ni_associd = aid | 0xc000; 2046841ab66cSSepherosa Ziehau IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); 2047841ab66cSSepherosa Ziehau ic->ic_sta_assoc++; 2048841ab66cSSepherosa Ziehau newassoc = 1; 2049841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2050841ab66cSSepherosa Ziehau ieee80211_node_join_11g(ic, ni); 2051841ab66cSSepherosa Ziehau } else 2052841ab66cSSepherosa Ziehau newassoc = 0; 2053841ab66cSSepherosa Ziehau 2054841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2055841ab66cSSepherosa Ziehau "[%6D] station %sassociated at aid %d: %s preamble, %s slot time%s%s\n", 2056841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", newassoc ? "" : "re", 2057841ab66cSSepherosa Ziehau IEEE80211_NODE_AID(ni), 2058841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2059841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2060841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2061841ab66cSSepherosa Ziehau ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "" 2062841ab66cSSepherosa Ziehau ); 2063841ab66cSSepherosa Ziehau 2064476d885dSSepherosa Ziehau IEEE80211_PRINT_NODERATES(ic, ni, 2065476d885dSSepherosa Ziehau IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG); 206621152d39SSepherosa Ziehau 2067b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, newassoc); 2068b9334f94SSepherosa Ziehau 2069841ab66cSSepherosa Ziehau /* give driver a chance to setup state like ni_txrate */ 2070841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 2071841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, newassoc); 2072b9334f94SSepherosa Ziehau 2073841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_auth; 2074841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 2075841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); 2076841ab66cSSepherosa Ziehau /* tell the authenticator about new station */ 2077841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_join != NULL) 2078841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_join(ic, ni); 2079841ab66cSSepherosa Ziehau ieee80211_notify_node_join(ic, ni, newassoc); 2080841ab66cSSepherosa Ziehau } 2081841ab66cSSepherosa Ziehau 2082841ab66cSSepherosa Ziehau /* 2083841ab66cSSepherosa Ziehau * Handle a station leaving an 11g network. 2084841ab66cSSepherosa Ziehau */ 2085841ab66cSSepherosa Ziehau static void 2086841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 2087841ab66cSSepherosa Ziehau { 2088841ab66cSSepherosa Ziehau 2089841ab66cSSepherosa Ziehau KASSERT(ic->ic_curmode == IEEE80211_MODE_11G, 2090841ab66cSSepherosa Ziehau ("not in 11g, bss %u:0x%x, curmode %u", ni->ni_chan->ic_freq, 2091841ab66cSSepherosa Ziehau ni->ni_chan->ic_flags, ic->ic_curmode)); 2092841ab66cSSepherosa Ziehau 2093841ab66cSSepherosa Ziehau /* 2094841ab66cSSepherosa Ziehau * If a long slot station do the slot time bookkeeping. 2095841ab66cSSepherosa Ziehau */ 2096841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2097841ab66cSSepherosa Ziehau KASSERT(ic->ic_longslotsta > 0, 2098841ab66cSSepherosa Ziehau ("bogus long slot station count %d", ic->ic_longslotsta)); 2099841ab66cSSepherosa Ziehau ic->ic_longslotsta--; 2100841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2101841ab66cSSepherosa Ziehau "[%6D] long slot time station leaves, count now %d\n", 2102841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 2103841ab66cSSepherosa Ziehau if (ic->ic_longslotsta == 0) { 2104841ab66cSSepherosa Ziehau /* 2105841ab66cSSepherosa Ziehau * Re-enable use of short slot time if supported 2106841ab66cSSepherosa Ziehau * and not operating in IBSS mode (per spec). 2107841ab66cSSepherosa Ziehau */ 2108841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2109841ab66cSSepherosa Ziehau ic->ic_opmode != IEEE80211_M_IBSS) { 2110841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2111841ab66cSSepherosa Ziehau "%s: re-enable use of short slot time\n", 2112841ab66cSSepherosa Ziehau __func__); 2113841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 1); 2114841ab66cSSepherosa Ziehau } 2115841ab66cSSepherosa Ziehau } 2116841ab66cSSepherosa Ziehau } 2117841ab66cSSepherosa Ziehau /* 2118841ab66cSSepherosa Ziehau * If a non-ERP station do the protection-related bookkeeping. 2119841ab66cSSepherosa Ziehau */ 2120841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2121841ab66cSSepherosa Ziehau KASSERT(ic->ic_nonerpsta > 0, 2122841ab66cSSepherosa Ziehau ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2123841ab66cSSepherosa Ziehau ic->ic_nonerpsta--; 2124841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2125841ab66cSSepherosa Ziehau "[%6D] non-ERP station leaves, count now %d\n", 2126841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 2127841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 0) { 2128841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2129841ab66cSSepherosa Ziehau "%s: disable use of protection\n", __func__); 2130841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT; 2131841ab66cSSepherosa Ziehau /* XXX verify mode? */ 2132841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2133841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2134841ab66cSSepherosa Ziehau "%s: re-enable use of short preamble\n", 2135841ab66cSSepherosa Ziehau __func__); 2136ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, 1); 2137841ab66cSSepherosa Ziehau } 2138841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2139841ab66cSSepherosa Ziehau } 2140841ab66cSSepherosa Ziehau } 2141841ab66cSSepherosa Ziehau } 2142841ab66cSSepherosa Ziehau 2143841ab66cSSepherosa Ziehau /* 2144841ab66cSSepherosa Ziehau * Handle bookkeeping for station deauthentication/disassociation 2145841ab66cSSepherosa Ziehau * when operating as an ap. 2146841ab66cSSepherosa Ziehau */ 2147841ab66cSSepherosa Ziehau void 2148841ab66cSSepherosa Ziehau ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 2149841ab66cSSepherosa Ziehau { 2150841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 2151841ab66cSSepherosa Ziehau 2152841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2153841ab66cSSepherosa Ziehau 2154841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2155841ab66cSSepherosa Ziehau "[%6D] station with aid %d leaves\n", 2156841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", IEEE80211_NODE_AID(ni)); 2157841ab66cSSepherosa Ziehau 2158841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2159841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS || 2160841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO, 2161841ab66cSSepherosa Ziehau ("unexpected operating mode %u", ic->ic_opmode)); 2162841ab66cSSepherosa Ziehau /* 2163841ab66cSSepherosa Ziehau * If node wasn't previously associated all 2164841ab66cSSepherosa Ziehau * we need to do is reclaim the reference. 2165841ab66cSSepherosa Ziehau */ 2166841ab66cSSepherosa Ziehau /* XXX ibss mode bypasses 11g and notification */ 2167841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) 2168841ab66cSSepherosa Ziehau goto done; 2169841ab66cSSepherosa Ziehau /* 2170841ab66cSSepherosa Ziehau * Tell the authenticator the station is leaving. 2171841ab66cSSepherosa Ziehau * Note that we must do this before yanking the 2172841ab66cSSepherosa Ziehau * association id as the authenticator uses the 2173841ab66cSSepherosa Ziehau * associd to locate it's state block. 2174841ab66cSSepherosa Ziehau */ 2175841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 2176841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 2177841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 2178841ab66cSSepherosa Ziehau ni->ni_associd = 0; 2179841ab66cSSepherosa Ziehau ic->ic_sta_assoc--; 2180841ab66cSSepherosa Ziehau 2181841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2182841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(ic, ni); 2183841ab66cSSepherosa Ziehau /* 2184841ab66cSSepherosa Ziehau * Cleanup station state. In particular clear various 2185841ab66cSSepherosa Ziehau * state that might otherwise be reused if the node 2186841ab66cSSepherosa Ziehau * is reused before the reference count goes to zero 2187841ab66cSSepherosa Ziehau * (and memory is reclaimed). 2188841ab66cSSepherosa Ziehau */ 2189841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 2190841ab66cSSepherosa Ziehau done: 2191841ab66cSSepherosa Ziehau /* 2192841ab66cSSepherosa Ziehau * Remove the node from any table it's recorded in and 2193841ab66cSSepherosa Ziehau * drop the caller's reference. Removal from the table 2194841ab66cSSepherosa Ziehau * is important to insure the node is not reprocessed 2195841ab66cSSepherosa Ziehau * for inactivity. 2196841ab66cSSepherosa Ziehau */ 2197841ab66cSSepherosa Ziehau if (nt != NULL) 2198841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 2199841ab66cSSepherosa Ziehau else 2200841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2201841ab66cSSepherosa Ziehau } 2202841ab66cSSepherosa Ziehau 2203841ab66cSSepherosa Ziehau uint8_t 2204841ab66cSSepherosa Ziehau ieee80211_getrssi(struct ieee80211com *ic) 2205841ab66cSSepherosa Ziehau { 2206841ab66cSSepherosa Ziehau #define NZ(x) ((x) == 0 ? 1 : (x)) 2207841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 2208841ab66cSSepherosa Ziehau uint32_t rssi_samples, rssi_total; 2209841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 2210841ab66cSSepherosa Ziehau 2211841ab66cSSepherosa Ziehau rssi_total = 0; 2212841ab66cSSepherosa Ziehau rssi_samples = 0; 2213841ab66cSSepherosa Ziehau switch (ic->ic_opmode) { 2214841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2215841ab66cSSepherosa Ziehau /* XXX locking */ 2216841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2217841ab66cSSepherosa Ziehau if (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) { 2218841ab66cSSepherosa Ziehau rssi_samples++; 2219841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2220841ab66cSSepherosa Ziehau } 2221841ab66cSSepherosa Ziehau break; 2222841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2223841ab66cSSepherosa Ziehau /* XXX locking */ 2224841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2225841ab66cSSepherosa Ziehau rssi_samples++; 2226841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2227841ab66cSSepherosa Ziehau } 2228841ab66cSSepherosa Ziehau break; 2229841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2230841ab66cSSepherosa Ziehau /* XXX locking */ 2231841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2232841ab66cSSepherosa Ziehau if (IEEE80211_AID(ni->ni_associd) != 0) { 2233841ab66cSSepherosa Ziehau rssi_samples++; 2234841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2235841ab66cSSepherosa Ziehau } 2236841ab66cSSepherosa Ziehau break; 2237841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* XXX */ 2238841ab66cSSepherosa Ziehau case IEEE80211_M_STA: /* use stats from associated ap */ 2239841ab66cSSepherosa Ziehau default: 2240841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) 2241841ab66cSSepherosa Ziehau rssi_total = ic->ic_node_getrssi(ic->ic_bss); 2242841ab66cSSepherosa Ziehau rssi_samples = 1; 2243841ab66cSSepherosa Ziehau break; 2244841ab66cSSepherosa Ziehau } 2245841ab66cSSepherosa Ziehau return rssi_total / NZ(rssi_samples); 2246841ab66cSSepherosa Ziehau #undef NZ 2247841ab66cSSepherosa Ziehau } 2248841ab66cSSepherosa Ziehau 2249841ab66cSSepherosa Ziehau /* 2250841ab66cSSepherosa Ziehau * Indicate whether there are frames queued for a station in power-save mode. 2251841ab66cSSepherosa Ziehau */ 2252841ab66cSSepherosa Ziehau static void 2253841ab66cSSepherosa Ziehau ieee80211_set_tim(struct ieee80211_node *ni, int set) 2254841ab66cSSepherosa Ziehau { 2255841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 2256841ab66cSSepherosa Ziehau uint16_t aid; 2257841ab66cSSepherosa Ziehau 2258841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2259841ab66cSSepherosa Ziehau 2260841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2261841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS, 2262841ab66cSSepherosa Ziehau ("operating mode %u", ic->ic_opmode)); 2263841ab66cSSepherosa Ziehau 2264841ab66cSSepherosa Ziehau aid = IEEE80211_AID(ni->ni_associd); 2265841ab66cSSepherosa Ziehau KASSERT(aid < ic->ic_max_aid, 2266841ab66cSSepherosa Ziehau ("bogus aid %u, max %u", aid, ic->ic_max_aid)); 2267841ab66cSSepherosa Ziehau 2268841ab66cSSepherosa Ziehau if (set != (isset(ic->ic_tim_bitmap, aid) != 0)) { 2269841ab66cSSepherosa Ziehau if (set) { 2270841ab66cSSepherosa Ziehau setbit(ic->ic_tim_bitmap, aid); 2271841ab66cSSepherosa Ziehau ic->ic_ps_pending++; 2272841ab66cSSepherosa Ziehau } else { 2273841ab66cSSepherosa Ziehau clrbit(ic->ic_tim_bitmap, aid); 2274841ab66cSSepherosa Ziehau ic->ic_ps_pending--; 2275841ab66cSSepherosa Ziehau } 2276841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_TIMUPDATE; 2277841ab66cSSepherosa Ziehau } 2278841ab66cSSepherosa Ziehau } 2279841ab66cSSepherosa Ziehau 2280841ab66cSSepherosa Ziehau /* 2281841ab66cSSepherosa Ziehau * Node table support. 2282841ab66cSSepherosa Ziehau */ 2283841ab66cSSepherosa Ziehau 2284841ab66cSSepherosa Ziehau static void 2285841ab66cSSepherosa Ziehau ieee80211_node_table_init(struct ieee80211com *ic, 2286841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, 2287841ab66cSSepherosa Ziehau const char *name, int inact, int keyixmax, 2288841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)) 2289841ab66cSSepherosa Ziehau { 2290841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 2291841ab66cSSepherosa Ziehau "%s %s table, inact %u\n", __func__, name, inact); 2292841ab66cSSepherosa Ziehau 2293841ab66cSSepherosa Ziehau nt->nt_ic = ic; 2294841ab66cSSepherosa Ziehau TAILQ_INIT(&nt->nt_node); 2295841ab66cSSepherosa Ziehau nt->nt_name = name; 2296841ab66cSSepherosa Ziehau nt->nt_inact_init = inact; 2297841ab66cSSepherosa Ziehau nt->nt_timeout = timeout; 2298841ab66cSSepherosa Ziehau nt->nt_keyixmax = keyixmax; 2299841ab66cSSepherosa Ziehau if (nt->nt_keyixmax > 0) { 2300841ab66cSSepherosa Ziehau nt->nt_keyixmap = 230177652cadSMatthew Dillon kmalloc(keyixmax * sizeof(struct ieee80211_node *), 2302841ab66cSSepherosa Ziehau M_80211_NODE, M_WAITOK | M_ZERO); 2303841ab66cSSepherosa Ziehau } else { 2304841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2305841ab66cSSepherosa Ziehau } 2306841ab66cSSepherosa Ziehau } 2307841ab66cSSepherosa Ziehau 2308841ab66cSSepherosa Ziehau void 2309841ab66cSSepherosa Ziehau ieee80211_node_table_reset(struct ieee80211_node_table *nt) 2310841ab66cSSepherosa Ziehau { 2311841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2312841ab66cSSepherosa Ziehau 2313841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2314841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2315841ab66cSSepherosa Ziehau 2316841ab66cSSepherosa Ziehau nt->nt_inact_timer = 0; 2317841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2318841ab66cSSepherosa Ziehau } 2319841ab66cSSepherosa Ziehau 2320841ab66cSSepherosa Ziehau static void 2321841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 2322841ab66cSSepherosa Ziehau { 2323841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2324841ab66cSSepherosa Ziehau 2325841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2326841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2327841ab66cSSepherosa Ziehau 2328841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2329841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 2330841ab66cSSepherosa Ziehau /* XXX verify all entries are NULL */ 2331841ab66cSSepherosa Ziehau int i; 2332841ab66cSSepherosa Ziehau for (i = 0; i < nt->nt_keyixmax; i++) 2333841ab66cSSepherosa Ziehau if (nt->nt_keyixmap[i] != NULL) { 2334*a6ec04bcSSascha Wildner kprintf("%s: %s[%u] still active\n", __func__, 2335841ab66cSSepherosa Ziehau nt->nt_name, i); 2336841ab66cSSepherosa Ziehau } 2337efda3bd0SMatthew Dillon kfree(nt->nt_keyixmap, M_80211_NODE); 2338841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2339841ab66cSSepherosa Ziehau } 2340f186073cSJoerg Sonnenberger } 2341ab0665aaSSepherosa Ziehau 2342ab0665aaSSepherosa Ziehau /* 2343ab0665aaSSepherosa Ziehau * Update short preamble state 2344ab0665aaSSepherosa Ziehau */ 2345ab0665aaSSepherosa Ziehau void 2346ab0665aaSSepherosa Ziehau ieee80211_update_shpreamble(struct ieee80211com *ic, 2347ab0665aaSSepherosa Ziehau const struct ieee80211_node *ni) 2348ab0665aaSSepherosa Ziehau { 2349ab0665aaSSepherosa Ziehau int shpreamble = 0; 2350ab0665aaSSepherosa Ziehau 2351ab0665aaSSepherosa Ziehau switch (ic->ic_curmode) { 2352ab0665aaSSepherosa Ziehau case IEEE80211_MODE_11A: 2353ab0665aaSSepherosa Ziehau shpreamble = 1; 2354ab0665aaSSepherosa Ziehau break; 2355ab0665aaSSepherosa Ziehau case IEEE80211_MODE_11G: 2356ab0665aaSSepherosa Ziehau if (ni->ni_erp & IEEE80211_ERP_LONG_PREAMBLE) { 2357ab0665aaSSepherosa Ziehau /* 2358ab0665aaSSepherosa Ziehau * According to IEEE Std 802.11g-2003 subclause 2359ab0665aaSSepherosa Ziehau * 7.3.2.13, page 10: 2360ab0665aaSSepherosa Ziehau * Short preamble should not be used, if barker 2361ab0665aaSSepherosa Ziehau * preamble mode bit is 1 in ERP informarion, 2362ab0665aaSSepherosa Ziehau * _regardless_ of the short preamble bit in 2363ab0665aaSSepherosa Ziehau * capability information. 2364ab0665aaSSepherosa Ziehau */ 2365ab0665aaSSepherosa Ziehau break; 2366ab0665aaSSepherosa Ziehau } 2367ab0665aaSSepherosa Ziehau /* FALL THROUGH */ 2368ab0665aaSSepherosa Ziehau default: 2369ab0665aaSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) && 2370ab0665aaSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) 2371ab0665aaSSepherosa Ziehau shpreamble = 1; 2372ab0665aaSSepherosa Ziehau break; 2373ab0665aaSSepherosa Ziehau } 2374ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, shpreamble); 2375ab0665aaSSepherosa Ziehau } 2376