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*215bf50cSSepherosa Ziehau * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.16 2007/03/06 14:51:22 sephe Exp $ 34f186073cSJoerg Sonnenberger */ 35f186073cSJoerg Sonnenberger 36f186073cSJoerg Sonnenberger #include <sys/param.h> 37f186073cSJoerg Sonnenberger #include <sys/systm.h> 38f186073cSJoerg Sonnenberger #include <sys/mbuf.h> 39f186073cSJoerg Sonnenberger #include <sys/malloc.h> 40f186073cSJoerg Sonnenberger #include <sys/kernel.h> 41f186073cSJoerg Sonnenberger 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)) { 241a6ec04bcSSascha 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)) { 265a6ec04bcSSascha Wildner kprintf("%s: scan set:", __func__); 266841ab66cSSepherosa Ziehau dump_chanlist(ic->ic_chan_scan); 267a6ec04bcSSascha 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 */ 430*215bf50cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) { 431841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 432*215bf50cSSepherosa Ziehau } else { 433*215bf50cSSepherosa Ziehau get_random_bytes(ni->ni_bssid, IEEE80211_ADDR_LEN); 434*215bf50cSSepherosa Ziehau /* Clear group bit, add local bit */ 435*215bf50cSSepherosa Ziehau ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02; 436*215bf50cSSepherosa Ziehau } 437841ab66cSSepherosa Ziehau } else if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 438841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 439841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 440841ab66cSSepherosa Ziehau else 441841ab66cSSepherosa Ziehau memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 442841ab66cSSepherosa Ziehau } 443841ab66cSSepherosa Ziehau /* 444841ab66cSSepherosa Ziehau * Fix the channel and related attributes. 445841ab66cSSepherosa Ziehau */ 446841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, chan); 447841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 448841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, chan); 449841ab66cSSepherosa Ziehau /* 450841ab66cSSepherosa Ziehau * Do mode-specific rate setup. 451841ab66cSSepherosa Ziehau */ 4529639b71dSSepherosa Ziehau ieee80211_set_basicrates(&ni->ni_rates, ic->ic_curmode, 4539639b71dSSepherosa Ziehau ic->ic_flags & IEEE80211_F_PUREG); 454f186073cSJoerg Sonnenberger 455841ab66cSSepherosa Ziehau ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 456841ab66cSSepherosa Ziehau } 457841ab66cSSepherosa Ziehau 458841ab66cSSepherosa Ziehau void 459841ab66cSSepherosa Ziehau ieee80211_reset_bss(struct ieee80211com *ic) 460f186073cSJoerg Sonnenberger { 461841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *obss; 462841ab66cSSepherosa Ziehau 463841ab66cSSepherosa Ziehau ieee80211_node_table_reset(&ic->ic_scan); 464841ab66cSSepherosa Ziehau ieee80211_node_table_reset(&ic->ic_sta); 465841ab66cSSepherosa Ziehau 466841ab66cSSepherosa Ziehau ni = ieee80211_alloc_node(&ic->ic_scan, ic->ic_myaddr); 467841ab66cSSepherosa Ziehau KASSERT(ni != NULL, ("unable to setup inital BSS node")); 468841ab66cSSepherosa Ziehau obss = ic->ic_bss; 469841ab66cSSepherosa Ziehau ic->ic_bss = ieee80211_ref_node(ni); 470841ab66cSSepherosa Ziehau if (obss != NULL) { 471841ab66cSSepherosa Ziehau copy_bss(ni, obss); 472841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 473841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 474841ab66cSSepherosa Ziehau } 475208a1285SSepherosa Ziehau ic->ic_nbasicrates = 0; 476841ab66cSSepherosa Ziehau } 477841ab66cSSepherosa Ziehau 478841ab66cSSepherosa Ziehau /* XXX tunable */ 479841ab66cSSepherosa Ziehau #define STA_FAILS_MAX 2 /* assoc failures before ignored */ 480841ab66cSSepherosa Ziehau 481841ab66cSSepherosa Ziehau static int 482841ab66cSSepherosa Ziehau ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) 483841ab66cSSepherosa Ziehau { 484f186073cSJoerg Sonnenberger uint8_t rate; 485f186073cSJoerg Sonnenberger int fail; 486f186073cSJoerg Sonnenberger 487208a1285SSepherosa Ziehau IEEE80211_PRINT_NODERATES(ic, ni, 0); 488208a1285SSepherosa Ziehau 489f186073cSJoerg Sonnenberger fail = 0; 490f186073cSJoerg Sonnenberger if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 491f186073cSJoerg Sonnenberger fail |= 0x01; 492f186073cSJoerg Sonnenberger if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 493f186073cSJoerg Sonnenberger ni->ni_chan != ic->ic_des_chan) 494f186073cSJoerg Sonnenberger fail |= 0x01; 495f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 496f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 497f186073cSJoerg Sonnenberger fail |= 0x02; 498f186073cSJoerg Sonnenberger } else { 499f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 500f186073cSJoerg Sonnenberger fail |= 0x02; 501f186073cSJoerg Sonnenberger } 502841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) { 503f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 504f186073cSJoerg Sonnenberger fail |= 0x04; 505f186073cSJoerg Sonnenberger } else { 506f186073cSJoerg Sonnenberger /* XXX does this mean privacy is supported or required? */ 507f186073cSJoerg Sonnenberger if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 508f186073cSJoerg Sonnenberger fail |= 0x04; 509f186073cSJoerg Sonnenberger } 510208a1285SSepherosa Ziehau rate = ieee80211_fix_rate(ni, 511208a1285SSepherosa Ziehau IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE, 1); 512f186073cSJoerg Sonnenberger if (rate & IEEE80211_RATE_BASIC) 513f186073cSJoerg Sonnenberger fail |= 0x08; 514f186073cSJoerg Sonnenberger if (ic->ic_des_esslen != 0 && 515f186073cSJoerg Sonnenberger (ni->ni_esslen != ic->ic_des_esslen || 516f186073cSJoerg Sonnenberger memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) 517f186073cSJoerg Sonnenberger fail |= 0x10; 518f186073cSJoerg Sonnenberger if ((ic->ic_flags & IEEE80211_F_DESBSSID) && 519f186073cSJoerg Sonnenberger !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) 520f186073cSJoerg Sonnenberger fail |= 0x20; 521841ab66cSSepherosa Ziehau if (ni->ni_fails >= STA_FAILS_MAX) 522841ab66cSSepherosa Ziehau fail |= 0x40; 523f186073cSJoerg Sonnenberger #ifdef IEEE80211_DEBUG 524841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 525a6ec04bcSSascha Wildner kprintf(" %c %6D", 526841ab66cSSepherosa Ziehau fail & 0x40 ? '=' : fail & 0x80 ? '^' : fail ? '-' : '+', 527841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 528a6ec04bcSSascha Wildner kprintf(" %6D%c", ni->ni_bssid, ":", 529841ab66cSSepherosa Ziehau fail & 0x20 ? '!' : ' '); 530a6ec04bcSSascha Wildner kprintf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), 531f186073cSJoerg Sonnenberger fail & 0x01 ? '!' : ' '); 532a6ec04bcSSascha Wildner kprintf(" %+4d", ni->ni_rssi); 533a6ec04bcSSascha Wildner kprintf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 534f186073cSJoerg Sonnenberger fail & 0x08 ? '!' : ' '); 535a6ec04bcSSascha Wildner kprintf(" %4s%c", 536f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 537f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 538f186073cSJoerg Sonnenberger "????", 539f186073cSJoerg Sonnenberger fail & 0x02 ? '!' : ' '); 540a6ec04bcSSascha Wildner kprintf(" %3s%c ", 541f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? 542f186073cSJoerg Sonnenberger "wep" : "no", 543f186073cSJoerg Sonnenberger fail & 0x04 ? '!' : ' '); 544f186073cSJoerg Sonnenberger ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 545a6ec04bcSSascha Wildner kprintf("%s\n", fail & 0x10 ? "!" : ""); 546f186073cSJoerg Sonnenberger } 547f186073cSJoerg Sonnenberger #endif 548f186073cSJoerg Sonnenberger return fail; 549f186073cSJoerg Sonnenberger } 550f186073cSJoerg Sonnenberger 551841ab66cSSepherosa Ziehau static __inline uint8_t 552841ab66cSSepherosa Ziehau maxrate(const struct ieee80211_node *ni) 553841ab66cSSepherosa Ziehau { 554841ab66cSSepherosa Ziehau const struct ieee80211_rateset *rs = &ni->ni_rates; 555841ab66cSSepherosa Ziehau /* NB: assumes rate set is sorted (happens on frame receive) */ 556841ab66cSSepherosa Ziehau return rs->rs_rates[rs->rs_nrates-1] & IEEE80211_RATE_VAL; 557841ab66cSSepherosa Ziehau } 558841ab66cSSepherosa Ziehau 559841ab66cSSepherosa Ziehau /* 560841ab66cSSepherosa Ziehau * Compare the capabilities of two nodes and decide which is 561841ab66cSSepherosa Ziehau * more desirable (return >0 if a is considered better). Note 562841ab66cSSepherosa Ziehau * that we assume compatibility/usability has already been checked 563841ab66cSSepherosa Ziehau * so we don't need to (e.g. validate whether privacy is supported). 564841ab66cSSepherosa Ziehau * Used to select the best scan candidate for association in a BSS. 565841ab66cSSepherosa Ziehau */ 566841ab66cSSepherosa Ziehau static int 567841ab66cSSepherosa Ziehau ieee80211_node_compare(struct ieee80211com *ic, 568841ab66cSSepherosa Ziehau const struct ieee80211_node *a, 569841ab66cSSepherosa Ziehau const struct ieee80211_node *b) 570841ab66cSSepherosa Ziehau { 571841ab66cSSepherosa Ziehau #define ABS(a) ((a) < 0 ? -(a) : (a)) 572841ab66cSSepherosa Ziehau uint8_t maxa, maxb; 573841ab66cSSepherosa Ziehau uint8_t rssia, rssib; 574841ab66cSSepherosa Ziehau int weight; 575841ab66cSSepherosa Ziehau 576841ab66cSSepherosa Ziehau /* privacy support preferred */ 577841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) && 578841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 579841ab66cSSepherosa Ziehau return 1; 580841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0 && 581841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)) 582841ab66cSSepherosa Ziehau return -1; 583841ab66cSSepherosa Ziehau 584841ab66cSSepherosa Ziehau /* compare count of previous failures */ 585841ab66cSSepherosa Ziehau weight = b->ni_fails - a->ni_fails; 586841ab66cSSepherosa Ziehau if (ABS(weight) > 1) 587841ab66cSSepherosa Ziehau return weight; 588841ab66cSSepherosa Ziehau 589841ab66cSSepherosa Ziehau rssia = ic->ic_node_getrssi(a); 590841ab66cSSepherosa Ziehau rssib = ic->ic_node_getrssi(b); 591841ab66cSSepherosa Ziehau if (ABS(rssib - rssia) < 5) { 592841ab66cSSepherosa Ziehau /* best/max rate preferred if signal level close enough XXX */ 593841ab66cSSepherosa Ziehau maxa = maxrate(a); 594841ab66cSSepherosa Ziehau maxb = maxrate(b); 595841ab66cSSepherosa Ziehau if (maxa != maxb) 596841ab66cSSepherosa Ziehau return maxa - maxb; 597841ab66cSSepherosa Ziehau /* XXX use freq for channel preference */ 598841ab66cSSepherosa Ziehau /* for now just prefer 5Ghz band to all other bands */ 599841ab66cSSepherosa Ziehau if (IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 600841ab66cSSepherosa Ziehau !IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 601841ab66cSSepherosa Ziehau return 1; 602841ab66cSSepherosa Ziehau if (!IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 603841ab66cSSepherosa Ziehau IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 604841ab66cSSepherosa Ziehau return -1; 605841ab66cSSepherosa Ziehau } 606841ab66cSSepherosa Ziehau /* all things being equal, use signal level */ 607841ab66cSSepherosa Ziehau return rssia - rssib; 608841ab66cSSepherosa Ziehau #undef ABS 609841ab66cSSepherosa Ziehau } 610841ab66cSSepherosa Ziehau 611841ab66cSSepherosa Ziehau /* 612841ab66cSSepherosa Ziehau * Mark an ongoing scan stopped. 613841ab66cSSepherosa Ziehau */ 614841ab66cSSepherosa Ziehau void 615841ab66cSSepherosa Ziehau ieee80211_cancel_scan(struct ieee80211com *ic) 616841ab66cSSepherosa Ziehau { 617841ab66cSSepherosa Ziehau 618841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s: end %s scan\n", 619841ab66cSSepherosa Ziehau __func__, 620841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); 621841ab66cSSepherosa Ziehau 622841ab66cSSepherosa Ziehau ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN); 623841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 624841ab66cSSepherosa Ziehau } 625841ab66cSSepherosa Ziehau 626f186073cSJoerg Sonnenberger /* 627f186073cSJoerg Sonnenberger * Complete a scan of potential channels. 628f186073cSJoerg Sonnenberger */ 629f186073cSJoerg Sonnenberger void 630841ab66cSSepherosa Ziehau ieee80211_end_scan(struct ieee80211com *ic) 631f186073cSJoerg Sonnenberger { 632841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 633841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *selbs; 634f186073cSJoerg Sonnenberger 635841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 636841ab66cSSepherosa Ziehau 637841ab66cSSepherosa Ziehau ieee80211_cancel_scan(ic); 638841ab66cSSepherosa Ziehau ieee80211_notify_scan_done(ic); 639f186073cSJoerg Sonnenberger 640f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 641841ab66cSSepherosa Ziehau uint8_t maxrssi[IEEE80211_CHAN_MAX]; /* XXX off stack? */ 642841ab66cSSepherosa Ziehau int i, bestchan; 643841ab66cSSepherosa Ziehau uint8_t rssi; 644841ab66cSSepherosa Ziehau 645f186073cSJoerg Sonnenberger /* 646f186073cSJoerg Sonnenberger * The passive scan to look for existing AP's completed, 647f186073cSJoerg Sonnenberger * select a channel to camp on. Identify the channels 648f186073cSJoerg Sonnenberger * that already have one or more AP's and try to locate 649841ab66cSSepherosa Ziehau * an unoccupied one. If that fails, pick a channel that 650841ab66cSSepherosa Ziehau * looks to be quietest. 651f186073cSJoerg Sonnenberger */ 652841ab66cSSepherosa Ziehau memset(maxrssi, 0, sizeof(maxrssi)); 653841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 654841ab66cSSepherosa Ziehau rssi = ic->ic_node_getrssi(ni); 655841ab66cSSepherosa Ziehau i = ieee80211_chan2ieee(ic, ni->ni_chan); 656841ab66cSSepherosa Ziehau if (rssi > maxrssi[i]) 657841ab66cSSepherosa Ziehau maxrssi[i] = rssi; 658f186073cSJoerg Sonnenberger } 659841ab66cSSepherosa Ziehau /* XXX select channel more intelligently */ 660841ab66cSSepherosa Ziehau bestchan = -1; 661f186073cSJoerg Sonnenberger for (i = 0; i < IEEE80211_CHAN_MAX; i++) 662841ab66cSSepherosa Ziehau if (isset(ic->ic_chan_active, i)) { 663841ab66cSSepherosa Ziehau /* 664841ab66cSSepherosa Ziehau * If the channel is unoccupied the max rssi 665841ab66cSSepherosa Ziehau * should be zero; just take it. Otherwise 666841ab66cSSepherosa Ziehau * track the channel with the lowest rssi and 667841ab66cSSepherosa Ziehau * use that when all channels appear occupied. 668841ab66cSSepherosa Ziehau */ 669841ab66cSSepherosa Ziehau if (maxrssi[i] == 0) { 670841ab66cSSepherosa Ziehau bestchan = i; 671f186073cSJoerg Sonnenberger break; 672f186073cSJoerg Sonnenberger } 673841ab66cSSepherosa Ziehau if (bestchan == -1 || 674841ab66cSSepherosa Ziehau maxrssi[i] < maxrssi[bestchan]) 675841ab66cSSepherosa Ziehau bestchan = i; 676841ab66cSSepherosa Ziehau } 677841ab66cSSepherosa Ziehau if (bestchan != -1) { 678841ab66cSSepherosa Ziehau ieee80211_create_ibss(ic, &ic->ic_channels[bestchan]); 679f186073cSJoerg Sonnenberger return; 680f186073cSJoerg Sonnenberger } 681841ab66cSSepherosa Ziehau /* no suitable channel, should not happen */ 682841ab66cSSepherosa Ziehau } 683841ab66cSSepherosa Ziehau 684841ab66cSSepherosa Ziehau /* 685841ab66cSSepherosa Ziehau * When manually sequencing the state machine; scan just once 686841ab66cSSepherosa Ziehau * regardless of whether we have a candidate or not. The 687841ab66cSSepherosa Ziehau * controlling application is expected to setup state and 688841ab66cSSepherosa Ziehau * initiate an association. 689841ab66cSSepherosa Ziehau */ 690841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_MANUAL) 691841ab66cSSepherosa Ziehau return; 692841ab66cSSepherosa Ziehau /* 693841ab66cSSepherosa Ziehau * Automatic sequencing; look for a candidate and 694841ab66cSSepherosa Ziehau * if found join the network. 695841ab66cSSepherosa Ziehau */ 696841ab66cSSepherosa Ziehau /* NB: unlocked read should be ok */ 697841ab66cSSepherosa Ziehau if (TAILQ_FIRST(&nt->nt_node) == NULL) { 698841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 699841ab66cSSepherosa Ziehau "%s: no scan candidate\n", __func__); 700f186073cSJoerg Sonnenberger notfound: 701f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS && 702f186073cSJoerg Sonnenberger (ic->ic_flags & IEEE80211_F_IBSSON) && 703f186073cSJoerg Sonnenberger ic->ic_des_esslen != 0) { 704f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_ibss_chan); 705f186073cSJoerg Sonnenberger return; 706f186073cSJoerg Sonnenberger } 707f186073cSJoerg Sonnenberger /* 708841ab66cSSepherosa Ziehau * Decrement the failure counts so entries will be 709841ab66cSSepherosa Ziehau * reconsidered the next time around. We really want 710841ab66cSSepherosa Ziehau * to do this only for sta's where we've previously 711841ab66cSSepherosa Ziehau * had some success. 712841ab66cSSepherosa Ziehau */ 713841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 714841ab66cSSepherosa Ziehau if (ni->ni_fails) 715841ab66cSSepherosa Ziehau ni->ni_fails--; 716841ab66cSSepherosa Ziehau /* 717f186073cSJoerg Sonnenberger * Reset the list of channels to scan and start again. 718f186073cSJoerg Sonnenberger */ 719841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 720841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 721841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 722f186073cSJoerg Sonnenberger return; 723f186073cSJoerg Sonnenberger } 724f186073cSJoerg Sonnenberger selbs = NULL; 725841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "\t%s\n", 726841ab66cSSepherosa Ziehau "macaddr bssid chan rssi rate flag wep essid"); 727841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 728841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) == 0) { 729f186073cSJoerg Sonnenberger if (selbs == NULL) 730f186073cSJoerg Sonnenberger selbs = ni; 731841ab66cSSepherosa Ziehau else if (ieee80211_node_compare(ic, ni, selbs) > 0) 732f186073cSJoerg Sonnenberger selbs = ni; 733f186073cSJoerg Sonnenberger } 734f186073cSJoerg Sonnenberger } 735841ab66cSSepherosa Ziehau if (selbs != NULL) /* NB: grab ref while dropping lock */ 736841ab66cSSepherosa Ziehau ieee80211_ref_node(selbs); 737f186073cSJoerg Sonnenberger if (selbs == NULL) 738f186073cSJoerg Sonnenberger goto notfound; 739841ab66cSSepherosa Ziehau if (!ieee80211_sta_join(ic, selbs)) { 740841ab66cSSepherosa Ziehau ieee80211_free_node(selbs); 741841ab66cSSepherosa Ziehau goto notfound; 742841ab66cSSepherosa Ziehau } 743841ab66cSSepherosa Ziehau } 744841ab66cSSepherosa Ziehau 745841ab66cSSepherosa Ziehau /* 746841ab66cSSepherosa Ziehau * Handle 802.11 ad hoc network merge. The 747841ab66cSSepherosa Ziehau * convention, set by the Wireless Ethernet Compatibility Alliance 748841ab66cSSepherosa Ziehau * (WECA), is that an 802.11 station will change its BSSID to match 749841ab66cSSepherosa Ziehau * the "oldest" 802.11 ad hoc network, on the same channel, that 750841ab66cSSepherosa Ziehau * has the station's desired SSID. The "oldest" 802.11 network 751841ab66cSSepherosa Ziehau * sends beacons with the greatest TSF timestamp. 752841ab66cSSepherosa Ziehau * 753841ab66cSSepherosa Ziehau * The caller is assumed to validate TSF's before attempting a merge. 754841ab66cSSepherosa Ziehau * 755841ab66cSSepherosa Ziehau * Return !0 if the BSSID changed, 0 otherwise. 756841ab66cSSepherosa Ziehau */ 757841ab66cSSepherosa Ziehau int 758841ab66cSSepherosa Ziehau ieee80211_ibss_merge(struct ieee80211_node *ni) 759841ab66cSSepherosa Ziehau { 760841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 761841ab66cSSepherosa Ziehau 762841ab66cSSepherosa Ziehau if (ni == ic->ic_bss || 763841ab66cSSepherosa Ziehau IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { 764841ab66cSSepherosa Ziehau /* unchanged, nothing to do */ 765841ab66cSSepherosa Ziehau return 0; 766841ab66cSSepherosa Ziehau } 767841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) != 0) { /* capabilities mismatch */ 768841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 769841ab66cSSepherosa Ziehau "%s: merge failed, capabilities mismatch\n", __func__); 770841ab66cSSepherosa Ziehau ic->ic_stats.is_ibss_capmismatch++; 771841ab66cSSepherosa Ziehau return 0; 772841ab66cSSepherosa Ziehau } 773841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 774841ab66cSSepherosa Ziehau "%6D: new bssid %s: %s preamble, %s slot time%s\n", __func__, 775841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 776841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 777841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 778841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 779841ab66cSSepherosa Ziehau ); 780841ab66cSSepherosa Ziehau return ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 781841ab66cSSepherosa Ziehau } 782841ab66cSSepherosa Ziehau 783841ab66cSSepherosa Ziehau /* 784841ab66cSSepherosa Ziehau * Join the specified IBSS/BSS network. The node is assumed to 785841ab66cSSepherosa Ziehau * be passed in with a held reference. 786841ab66cSSepherosa Ziehau */ 787841ab66cSSepherosa Ziehau int 788841ab66cSSepherosa Ziehau ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) 789841ab66cSSepherosa Ziehau { 790841ab66cSSepherosa Ziehau struct ieee80211_node *obss; 791841ab66cSSepherosa Ziehau 792841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 793841ab66cSSepherosa Ziehau 794208a1285SSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS || 795208a1285SSepherosa Ziehau ic->ic_opmode == IEEE80211_M_STA) { 796f186073cSJoerg Sonnenberger /* 797841ab66cSSepherosa Ziehau * Delete unusable rates; we've already checked 798841ab66cSSepherosa Ziehau * that the negotiated rate set is acceptable. 799f186073cSJoerg Sonnenberger */ 800208a1285SSepherosa Ziehau ieee80211_fix_rate(selbs, IEEE80211_F_DODEL, 1); 801208a1285SSepherosa Ziehau IEEE80211_PRINT_NODERATES(ic, selbs, 0); 802208a1285SSepherosa Ziehau 803208a1285SSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS) { 804208a1285SSepherosa Ziehau struct ieee80211_node_table *nt; 805208a1285SSepherosa Ziehau 806841ab66cSSepherosa Ziehau /* 807841ab66cSSepherosa Ziehau * Fillin the neighbor table; it will already 808841ab66cSSepherosa Ziehau * exist if we are simply switching mastership. 809841ab66cSSepherosa Ziehau * XXX ic_sta always setup so this is unnecessary? 810841ab66cSSepherosa Ziehau */ 811841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 812841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 813841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 814f186073cSJoerg Sonnenberger } 815208a1285SSepherosa Ziehau } 816841ab66cSSepherosa Ziehau 817841ab66cSSepherosa Ziehau /* 818841ab66cSSepherosa Ziehau * Committed to selbs, setup state. 819841ab66cSSepherosa Ziehau */ 820841ab66cSSepherosa Ziehau obss = ic->ic_bss; 821841ab66cSSepherosa Ziehau ic->ic_bss = selbs; /* NB: caller assumed to bump refcnt */ 822841ab66cSSepherosa Ziehau if (obss != NULL) { 823841ab66cSSepherosa Ziehau copy_bss(selbs, obss); 824841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 825841ab66cSSepherosa Ziehau } 826841ab66cSSepherosa Ziehau /* 827841ab66cSSepherosa Ziehau * Set the erp state (mostly the slot time) to deal with 828841ab66cSSepherosa Ziehau * the auto-select case; this should be redundant if the 829841ab66cSSepherosa Ziehau * mode is locked. 830841ab66cSSepherosa Ziehau */ 831841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan); 832841ab66cSSepherosa Ziehau ic->ic_curchan = selbs->ni_chan; 833841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 834841ab66cSSepherosa Ziehau ieee80211_wme_initparams(ic); 835841ab66cSSepherosa Ziehau 836208a1285SSepherosa Ziehau /* 837208a1285SSepherosa Ziehau * Copy BSS basic rate set. 838208a1285SSepherosa Ziehau */ 839208a1285SSepherosa Ziehau ic->ic_nbasicrates = 840208a1285SSepherosa Ziehau ieee80211_copy_basicrates(&ic->ic_sup_rates[ic->ic_curmode], 841208a1285SSepherosa Ziehau &selbs->ni_rates); 842208a1285SSepherosa Ziehau #ifdef IEEE80211_DEBUG 843208a1285SSepherosa Ziehau if (ieee80211_msg(ic, IEEE80211_MSG_XRATE)) { 844208a1285SSepherosa Ziehau ieee80211_note(ic, "number basic rates %d, " 845208a1285SSepherosa Ziehau "supported rates (mode %d): ", 846208a1285SSepherosa Ziehau ic->ic_nbasicrates, ic->ic_curmode); 847208a1285SSepherosa Ziehau ieee80211_print_rateset(&ic->ic_sup_rates[ic->ic_curmode]); 848208a1285SSepherosa Ziehau kprintf("\n"); 849208a1285SSepherosa Ziehau } 850208a1285SSepherosa Ziehau #endif 851208a1285SSepherosa Ziehau 852841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA) 853841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 854841ab66cSSepherosa Ziehau else 855841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 856841ab66cSSepherosa Ziehau return 1; 857841ab66cSSepherosa Ziehau } 858841ab66cSSepherosa Ziehau 859841ab66cSSepherosa Ziehau /* 860841ab66cSSepherosa Ziehau * Leave the specified IBSS/BSS network. The node is assumed to 861841ab66cSSepherosa Ziehau * be passed in with a held reference. 862841ab66cSSepherosa Ziehau */ 863841ab66cSSepherosa Ziehau void 864841ab66cSSepherosa Ziehau ieee80211_sta_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 865841ab66cSSepherosa Ziehau { 866841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 867841ab66cSSepherosa Ziehau ieee80211_notify_node_leave(ic, ni); 868f186073cSJoerg Sonnenberger } 869f186073cSJoerg Sonnenberger 870f186073cSJoerg Sonnenberger static struct ieee80211_node * 871841ab66cSSepherosa Ziehau node_alloc(struct ieee80211_node_table *nt) 872f186073cSJoerg Sonnenberger { 873f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 874841ab66cSSepherosa Ziehau 875efda3bd0SMatthew Dillon ni = kmalloc(sizeof(struct ieee80211_node), M_80211_NODE, 876841ab66cSSepherosa Ziehau M_NOWAIT | M_ZERO); 877f186073cSJoerg Sonnenberger return ni; 878f186073cSJoerg Sonnenberger } 879f186073cSJoerg Sonnenberger 880841ab66cSSepherosa Ziehau /* 881841ab66cSSepherosa Ziehau * Reclaim any resources in a node and reset any critical 882841ab66cSSepherosa Ziehau * state. Typically nodes are free'd immediately after, 883841ab66cSSepherosa Ziehau * but in some cases the storage may be reused so we need 884841ab66cSSepherosa Ziehau * to insure consistent state (should probably fix that). 885841ab66cSSepherosa Ziehau */ 886f186073cSJoerg Sonnenberger static void 887841ab66cSSepherosa Ziehau node_cleanup(struct ieee80211_node *ni) 888f186073cSJoerg Sonnenberger { 889841ab66cSSepherosa Ziehau #define N(a) (sizeof(a)/sizeof(a[0])) 890841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 891841ab66cSSepherosa Ziehau int i, qlen; 892841ab66cSSepherosa Ziehau 893841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 894841ab66cSSepherosa Ziehau 895841ab66cSSepherosa Ziehau /* NB: preserve ni_table */ 896841ab66cSSepherosa Ziehau if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 897841ab66cSSepherosa Ziehau ic->ic_ps_sta--; 898841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 899841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, 900841ab66cSSepherosa Ziehau "[%6D] power save mode off, %u sta's in ps mode\n", 901841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_ps_sta); 902841ab66cSSepherosa Ziehau } 903841ab66cSSepherosa Ziehau /* 904841ab66cSSepherosa Ziehau * Clear AREF flag that marks the authorization refcnt bump 905841ab66cSSepherosa Ziehau * has happened. This is probably not needed as the node 906841ab66cSSepherosa Ziehau * should always be removed from the table so not found but 907841ab66cSSepherosa Ziehau * do it just in case. 908841ab66cSSepherosa Ziehau */ 909841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AREF; 910841ab66cSSepherosa Ziehau 911841ab66cSSepherosa Ziehau /* 912841ab66cSSepherosa Ziehau * Drain power save queue and, if needed, clear TIM. 913841ab66cSSepherosa Ziehau */ 914841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DRAIN(ni, qlen); 915841ab66cSSepherosa Ziehau if (qlen != 0 && ic->ic_set_tim != NULL) 916841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 917841ab66cSSepherosa Ziehau 918841ab66cSSepherosa Ziehau ni->ni_associd = 0; 919841ab66cSSepherosa Ziehau if (ni->ni_challenge != NULL) { 920efda3bd0SMatthew Dillon kfree(ni->ni_challenge, M_DEVBUF); 921841ab66cSSepherosa Ziehau ni->ni_challenge = NULL; 922841ab66cSSepherosa Ziehau } 923841ab66cSSepherosa Ziehau /* 924841ab66cSSepherosa Ziehau * Preserve SSID, WPA, and WME ie's so the bss node is 925841ab66cSSepherosa Ziehau * reusable during a re-auth/re-assoc state transition. 926841ab66cSSepherosa Ziehau * If we remove these data they will not be recreated 927841ab66cSSepherosa Ziehau * because they come from a probe-response or beacon frame 928841ab66cSSepherosa Ziehau * which cannot be expected prior to the association-response. 929841ab66cSSepherosa Ziehau * This should not be an issue when operating in other modes 930841ab66cSSepherosa Ziehau * as stations leaving always go through a full state transition 931841ab66cSSepherosa Ziehau * which will rebuild this state. 932841ab66cSSepherosa Ziehau * 933841ab66cSSepherosa Ziehau * XXX does this leave us open to inheriting old state? 934841ab66cSSepherosa Ziehau */ 935841ab66cSSepherosa Ziehau for (i = 0; i < N(ni->ni_rxfrag); i++) 936841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[i] != NULL) { 937841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[i]); 938841ab66cSSepherosa Ziehau ni->ni_rxfrag[i] = NULL; 939841ab66cSSepherosa Ziehau } 940841ab66cSSepherosa Ziehau /* 941841ab66cSSepherosa Ziehau * Must be careful here to remove any key map entry w/o a LOR. 942841ab66cSSepherosa Ziehau */ 943841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(ni); 944841ab66cSSepherosa Ziehau #undef N 945f186073cSJoerg Sonnenberger } 946f186073cSJoerg Sonnenberger 947f186073cSJoerg Sonnenberger static void 948841ab66cSSepherosa Ziehau node_free(struct ieee80211_node *ni) 949f186073cSJoerg Sonnenberger { 950841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 951841ab66cSSepherosa Ziehau 952841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 953841ab66cSSepherosa Ziehau if (ni->ni_wpa_ie != NULL) 954efda3bd0SMatthew Dillon kfree(ni->ni_wpa_ie, M_DEVBUF); 955841ab66cSSepherosa Ziehau if (ni->ni_wme_ie != NULL) 956efda3bd0SMatthew Dillon kfree(ni->ni_wme_ie, M_DEVBUF); 957841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DESTROY(ni); 958efda3bd0SMatthew Dillon kfree(ni, M_80211_NODE); 959f186073cSJoerg Sonnenberger } 960f186073cSJoerg Sonnenberger 961f186073cSJoerg Sonnenberger static uint8_t 962841ab66cSSepherosa Ziehau node_getrssi(const struct ieee80211_node *ni) 963f186073cSJoerg Sonnenberger { 964f186073cSJoerg Sonnenberger return ni->ni_rssi; 965f186073cSJoerg Sonnenberger } 966f186073cSJoerg Sonnenberger 967f186073cSJoerg Sonnenberger static void 968841ab66cSSepherosa Ziehau ieee80211_setup_node(struct ieee80211_node_table *nt, 969841ab66cSSepherosa Ziehau struct ieee80211_node *ni, const uint8_t *macaddr) 970f186073cSJoerg Sonnenberger { 971841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 972f186073cSJoerg Sonnenberger int hash; 973f186073cSJoerg Sonnenberger 974841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 975841ab66cSSepherosa Ziehau 976841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 97789625b06SSepherosa Ziehau "%s %p<%6D> in %s table\n", __func__, ni, 978841ab66cSSepherosa Ziehau macaddr, ":", nt->nt_name); 979841ab66cSSepherosa Ziehau 980f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 981f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 982841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 983841ab66cSSepherosa Ziehau ni->ni_chan = IEEE80211_CHAN_ANYC; 984841ab66cSSepherosa Ziehau ni->ni_authmode = IEEE80211_AUTH_OPEN; 985841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 986841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 987841ab66cSSepherosa Ziehau ni->ni_inact_reload = nt->nt_inact_init; 988841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 989841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 990841ab66cSSepherosa Ziehau 991841ab66cSSepherosa Ziehau TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 992841ab66cSSepherosa Ziehau LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 993841ab66cSSepherosa Ziehau ni->ni_table = nt; 994841ab66cSSepherosa Ziehau ni->ni_ic = ic; 995b9334f94SSepherosa Ziehau 996b9334f94SSepherosa Ziehau ieee80211_ratectl_data_alloc(ni); 997f186073cSJoerg Sonnenberger } 998f186073cSJoerg Sonnenberger 999f186073cSJoerg Sonnenberger struct ieee80211_node * 1000841ab66cSSepherosa Ziehau ieee80211_alloc_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1001f186073cSJoerg Sonnenberger { 1002841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1003841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1004841ab66cSSepherosa Ziehau 1005841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1006f186073cSJoerg Sonnenberger if (ni != NULL) 1007841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 1008f186073cSJoerg Sonnenberger else 1009f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 1010f186073cSJoerg Sonnenberger return ni; 1011f186073cSJoerg Sonnenberger } 1012f186073cSJoerg Sonnenberger 1013841ab66cSSepherosa Ziehau /* 1014841ab66cSSepherosa Ziehau * Craft a temporary node suitable for sending a management frame 1015841ab66cSSepherosa Ziehau * to the specified station. We craft only as much state as we 1016841ab66cSSepherosa Ziehau * need to do the work since the node will be immediately reclaimed 1017841ab66cSSepherosa Ziehau * once the send completes. 1018841ab66cSSepherosa Ziehau */ 1019f186073cSJoerg Sonnenberger struct ieee80211_node * 1020841ab66cSSepherosa Ziehau ieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr) 1021f186073cSJoerg Sonnenberger { 1022841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1023841ab66cSSepherosa Ziehau 1024841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(&ic->ic_sta); 1025f186073cSJoerg Sonnenberger if (ni != NULL) { 1026841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1027841ab66cSSepherosa Ziehau "%s %p<%6D>\n", __func__, ni, macaddr, ":"); 1028841ab66cSSepherosa Ziehau 1029841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1030841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1031841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 1032841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1033841ab66cSSepherosa Ziehau /* NB: required by ieee80211_fix_rate */ 1034841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1035841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, 1036841ab66cSSepherosa Ziehau IEEE80211_KEYIX_NONE); 1037841ab66cSSepherosa Ziehau /* XXX optimize away */ 1038841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 1039841ab66cSSepherosa Ziehau 1040841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* NB: pedantic */ 1041841ab66cSSepherosa Ziehau ni->ni_ic = ic; 1042841ab66cSSepherosa Ziehau } else { 1043841ab66cSSepherosa Ziehau /* XXX msg */ 1044841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1045841ab66cSSepherosa Ziehau } 1046841ab66cSSepherosa Ziehau return ni; 1047841ab66cSSepherosa Ziehau } 1048841ab66cSSepherosa Ziehau 1049841ab66cSSepherosa Ziehau struct ieee80211_node * 1050841ab66cSSepherosa Ziehau ieee80211_dup_bss(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1051841ab66cSSepherosa Ziehau { 1052841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1053841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1054841ab66cSSepherosa Ziehau 1055841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1056841ab66cSSepherosa Ziehau if (ni != NULL) { 1057841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 1058f186073cSJoerg Sonnenberger /* 1059f186073cSJoerg Sonnenberger * Inherit from ic_bss. 1060f186073cSJoerg Sonnenberger */ 1061841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1062841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1063841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1064f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1065841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1066841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1067f186073cSJoerg Sonnenberger } else 1068f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 1069f186073cSJoerg Sonnenberger return ni; 1070f186073cSJoerg Sonnenberger } 1071f186073cSJoerg Sonnenberger 1072f186073cSJoerg Sonnenberger static struct ieee80211_node * 1073841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1074841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1075841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1076841ab66cSSepherosa Ziehau #else 1077841ab66cSSepherosa Ziehau _ieee80211_find_node(struct ieee80211_node_table *nt, 1078841ab66cSSepherosa Ziehau const uint8_t *macaddr) 1079841ab66cSSepherosa Ziehau #endif 1080f186073cSJoerg Sonnenberger { 1081f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1082f186073cSJoerg Sonnenberger int hash; 1083f186073cSJoerg Sonnenberger 1084f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1085841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1086f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1087841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1088841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1089841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1090841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1091841ab66cSSepherosa Ziehau func, line, 1092841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1093841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1094841ab66cSSepherosa Ziehau #endif 1095f186073cSJoerg Sonnenberger return ni; 1096f186073cSJoerg Sonnenberger } 1097f186073cSJoerg Sonnenberger } 1098f186073cSJoerg Sonnenberger return NULL; 1099f186073cSJoerg Sonnenberger } 1100841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1101841ab66cSSepherosa Ziehau #define _ieee80211_find_node(nt, mac) \ 1102841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(nt, mac, func, line) 1103841ab66cSSepherosa Ziehau #endif 1104f186073cSJoerg Sonnenberger 1105f186073cSJoerg Sonnenberger struct ieee80211_node * 1106841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1107841ab66cSSepherosa Ziehau ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1108841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1109841ab66cSSepherosa Ziehau #else 1110841ab66cSSepherosa Ziehau ieee80211_find_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1111841ab66cSSepherosa Ziehau #endif 1112f186073cSJoerg Sonnenberger { 1113f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1114f186073cSJoerg Sonnenberger 1115841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1116841ab66cSSepherosa Ziehau 1117841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1118f186073cSJoerg Sonnenberger return ni; 1119f186073cSJoerg Sonnenberger } 1120f186073cSJoerg Sonnenberger 1121f186073cSJoerg Sonnenberger /* 1122841ab66cSSepherosa Ziehau * Fake up a node; this handles node discovery in adhoc mode. 1123841ab66cSSepherosa Ziehau * Note that for the driver's benefit we we treat this like 1124841ab66cSSepherosa Ziehau * an association so the driver has an opportunity to setup 1125841ab66cSSepherosa Ziehau * it's private state. 1126841ab66cSSepherosa Ziehau */ 1127841ab66cSSepherosa Ziehau struct ieee80211_node * 1128841ab66cSSepherosa Ziehau ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, 1129841ab66cSSepherosa Ziehau const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1130841ab66cSSepherosa Ziehau { 1131841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1132841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1133841ab66cSSepherosa Ziehau 1134841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1135841ab66cSSepherosa Ziehau "%s: mac<%6D>\n", __func__, macaddr, ":"); 1136841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(nt, macaddr); 1137841ab66cSSepherosa Ziehau if (ni != NULL) { 1138841ab66cSSepherosa Ziehau /* XXX no rate negotiation; just dup */ 1139841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_bss->ni_rates; 1140b9334f94SSepherosa Ziehau 1141b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, 1); 1142b9334f94SSepherosa Ziehau 1143841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1144841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1145b9334f94SSepherosa Ziehau 1146841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1147841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1148841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 1149841ab66cSSepherosa Ziehau /* 1150841ab66cSSepherosa Ziehau * Blindly propagate capabilities based on the 1151841ab66cSSepherosa Ziehau * local configuration. In particular this permits 1152841ab66cSSepherosa Ziehau * us to use QoS to disable ACK's. 1153841ab66cSSepherosa Ziehau */ 1154841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_WME) 1155841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_QOS; 1156841ab66cSSepherosa Ziehau } 1157841ab66cSSepherosa Ziehau } 1158841ab66cSSepherosa Ziehau return ni; 1159841ab66cSSepherosa Ziehau } 1160841ab66cSSepherosa Ziehau 1161841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1162841ab66cSSepherosa Ziehau static void 1163841ab66cSSepherosa Ziehau dump_probe_beacon(uint8_t subtype, int isnew, 1164841ab66cSSepherosa Ziehau const uint8_t mac[IEEE80211_ADDR_LEN], 1165841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1166841ab66cSSepherosa Ziehau { 1167841ab66cSSepherosa Ziehau 1168a6ec04bcSSascha Wildner kprintf("[%6D] %s%s on chan %u (bss chan %u) ", 1169841ab66cSSepherosa Ziehau mac, ":", isnew ? "new " : "", 1170841ab66cSSepherosa Ziehau ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], 1171841ab66cSSepherosa Ziehau sp->chan, sp->bchan); 1172841ab66cSSepherosa Ziehau ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); 1173a6ec04bcSSascha Wildner kprintf("\n"); 1174841ab66cSSepherosa Ziehau 1175841ab66cSSepherosa Ziehau if (isnew) { 1176a6ec04bcSSascha Wildner kprintf("[%6D] caps 0x%x bintval %u erp 0x%x", 1177841ab66cSSepherosa Ziehau mac, ":", sp->capinfo, sp->bintval, sp->erp); 1178841ab66cSSepherosa Ziehau if (sp->country != NULL) { 1179841ab66cSSepherosa Ziehau #if defined(__FreeBSD__) || defined(__DragonFly__) 1180a6ec04bcSSascha Wildner kprintf(" country info %*D", 1181841ab66cSSepherosa Ziehau sp->country[1], sp->country+2, " "); 1182841ab66cSSepherosa Ziehau #else 1183841ab66cSSepherosa Ziehau int i; 1184a6ec04bcSSascha Wildner kprintf(" country info"); 1185841ab66cSSepherosa Ziehau for (i = 0; i < sp->country[1]; i++) 1186a6ec04bcSSascha Wildner kprintf(" %02x", sp->country[i+2]); 1187841ab66cSSepherosa Ziehau #endif 1188841ab66cSSepherosa Ziehau } 1189a6ec04bcSSascha Wildner kprintf("\n"); 1190841ab66cSSepherosa Ziehau } 1191841ab66cSSepherosa Ziehau } 1192841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 1193841ab66cSSepherosa Ziehau 1194841ab66cSSepherosa Ziehau static void 1195841ab66cSSepherosa Ziehau saveie(uint8_t **iep, const uint8_t *ie) 1196841ab66cSSepherosa Ziehau { 1197841ab66cSSepherosa Ziehau 1198841ab66cSSepherosa Ziehau if (ie == NULL) 1199841ab66cSSepherosa Ziehau *iep = NULL; 1200841ab66cSSepherosa Ziehau else 1201841ab66cSSepherosa Ziehau ieee80211_saveie(iep, ie); 1202841ab66cSSepherosa Ziehau } 1203841ab66cSSepherosa Ziehau 1204841ab66cSSepherosa Ziehau /* 1205841ab66cSSepherosa Ziehau * Process a beacon or probe response frame. 1206841ab66cSSepherosa Ziehau */ 1207841ab66cSSepherosa Ziehau void 1208841ab66cSSepherosa Ziehau ieee80211_add_scan(struct ieee80211com *ic, 1209841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp, 1210841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1211841ab66cSSepherosa Ziehau int subtype, int rssi, int rstamp) 1212841ab66cSSepherosa Ziehau { 1213841ab66cSSepherosa Ziehau #define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1214841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 1215841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1216841ab66cSSepherosa Ziehau int newnode = 0; 1217841ab66cSSepherosa Ziehau 1218841ab66cSSepherosa Ziehau ni = ieee80211_find_node(nt, wh->i_addr2); 1219841ab66cSSepherosa Ziehau if (ni == NULL) { 1220841ab66cSSepherosa Ziehau /* 1221841ab66cSSepherosa Ziehau * Create a new entry. 1222841ab66cSSepherosa Ziehau */ 1223841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1224841ab66cSSepherosa Ziehau if (ni == NULL) { 1225841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1226841ab66cSSepherosa Ziehau return; 1227841ab66cSSepherosa Ziehau } 1228841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, wh->i_addr2); 1229841ab66cSSepherosa Ziehau /* 1230841ab66cSSepherosa Ziehau * XXX inherit from ic_bss. 1231841ab66cSSepherosa Ziehau */ 1232841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1233841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1234841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1235841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_curchan); 1236841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1237841ab66cSSepherosa Ziehau newnode = 1; 1238841ab66cSSepherosa Ziehau } 1239841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1240841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN)) 1241841ab66cSSepherosa Ziehau dump_probe_beacon(subtype, newnode, wh->i_addr2, sp); 1242841ab66cSSepherosa Ziehau #endif 1243841ab66cSSepherosa Ziehau /* XXX ap beaconing multiple ssid w/ same bssid */ 1244841ab66cSSepherosa Ziehau if (sp->ssid[1] != 0 && 1245841ab66cSSepherosa Ziehau (ISPROBE(subtype) || ni->ni_esslen == 0)) { 1246841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1247841ab66cSSepherosa Ziehau memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); 1248841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1249841ab66cSSepherosa Ziehau } 1250841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1251841ab66cSSepherosa Ziehau ni->ni_rssi = rssi; 1252841ab66cSSepherosa Ziehau ni->ni_rstamp = rstamp; 1253841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1254841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1255841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1256841ab66cSSepherosa Ziehau ni->ni_chan = &ic->ic_channels[sp->chan]; 1257841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1258841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1259841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1260841ab66cSSepherosa Ziehau if (sp->tim != NULL) { 1261841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *ie = 1262841ab66cSSepherosa Ziehau (struct ieee80211_tim_ie *) sp->tim; 1263841ab66cSSepherosa Ziehau 1264841ab66cSSepherosa Ziehau ni->ni_dtim_count = ie->tim_count; 1265841ab66cSSepherosa Ziehau ni->ni_dtim_period = ie->tim_period; 1266841ab66cSSepherosa Ziehau } 1267841ab66cSSepherosa Ziehau /* 1268841ab66cSSepherosa Ziehau * Record the byte offset from the mac header to 1269841ab66cSSepherosa Ziehau * the start of the TIM information element for 1270841ab66cSSepherosa Ziehau * use by hardware and/or to speedup software 1271841ab66cSSepherosa Ziehau * processing of beacon frames. 1272841ab66cSSepherosa Ziehau */ 1273841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1274841ab66cSSepherosa Ziehau /* 1275841ab66cSSepherosa Ziehau * Record optional information elements that might be 1276841ab66cSSepherosa Ziehau * used by applications or drivers. 1277841ab66cSSepherosa Ziehau */ 1278841ab66cSSepherosa Ziehau saveie(&ni->ni_wme_ie, sp->wme); 1279841ab66cSSepherosa Ziehau saveie(&ni->ni_wpa_ie, sp->wpa); 1280841ab66cSSepherosa Ziehau 1281841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1282208a1285SSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT, 0); 1283841ab66cSSepherosa Ziehau 1284841ab66cSSepherosa Ziehau if (!newnode) 1285841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1286841ab66cSSepherosa Ziehau #undef ISPROBE 1287841ab66cSSepherosa Ziehau } 1288841ab66cSSepherosa Ziehau 1289841ab66cSSepherosa Ziehau void 1290841ab66cSSepherosa Ziehau ieee80211_init_neighbor(struct ieee80211_node *ni, 1291841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1292841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1293841ab66cSSepherosa Ziehau { 1294841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 129589625b06SSepherosa Ziehau "%s: %p<%6D>\n", __func__, ni, ni->ni_macaddr, ":"); 1296841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1297841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1298841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1299841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1300841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1301841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1302841ab66cSSepherosa Ziehau ni->ni_chan = ni->ni_ic->ic_curchan; 1303841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1304841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1305841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1306841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1307841ab66cSSepherosa Ziehau if (sp->wme != NULL) 1308841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wme_ie, sp->wme); 1309841ab66cSSepherosa Ziehau if (sp->wpa != NULL) 1310841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa); 1311841ab66cSSepherosa Ziehau 1312841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1313208a1285SSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, 1314208a1285SSepherosa Ziehau IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | 1315208a1285SSepherosa Ziehau IEEE80211_F_DONEGO | IEEE80211_F_DODEL, 0); 1316476d885dSSepherosa Ziehau IEEE80211_PRINT_NODERATES(ni->ni_ic, ni, IEEE80211_MSG_NODE); 1317841ab66cSSepherosa Ziehau } 1318841ab66cSSepherosa Ziehau 1319841ab66cSSepherosa Ziehau /* 1320841ab66cSSepherosa Ziehau * Do node discovery in adhoc mode on receipt of a beacon 1321841ab66cSSepherosa Ziehau * or probe response frame. Note that for the driver's 1322841ab66cSSepherosa Ziehau * benefit we we treat this like an association so the 1323841ab66cSSepherosa Ziehau * driver has an opportunity to setup it's private state. 1324841ab66cSSepherosa Ziehau */ 1325841ab66cSSepherosa Ziehau struct ieee80211_node * 1326841ab66cSSepherosa Ziehau ieee80211_add_neighbor(struct ieee80211com *ic, 1327841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1328841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1329841ab66cSSepherosa Ziehau { 1330841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1331841ab66cSSepherosa Ziehau 1332841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1333841ab66cSSepherosa Ziehau "%s: mac<%s>\n", __func__, wh->i_addr2, ":"); 1334841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */ 1335841ab66cSSepherosa Ziehau if (ni != NULL) { 1336841ab66cSSepherosa Ziehau ieee80211_init_neighbor(ni, wh, sp); 1337b9334f94SSepherosa Ziehau 1338b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, 1); 1339b9334f94SSepherosa Ziehau 1340841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1341841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1342b9334f94SSepherosa Ziehau 1343841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1344841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1345841ab66cSSepherosa Ziehau } 1346841ab66cSSepherosa Ziehau return ni; 1347841ab66cSSepherosa Ziehau } 1348841ab66cSSepherosa Ziehau 1349841ab66cSSepherosa Ziehau #define IS_CTL(wh) \ 1350841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 1351841ab66cSSepherosa Ziehau #define IS_PSPOLL(wh) \ 1352841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) 1353841ab66cSSepherosa Ziehau /* 1354841ab66cSSepherosa Ziehau * Locate the node for sender, track state, and then pass the 1355841ab66cSSepherosa Ziehau * (referenced) node up to the 802.11 layer for its use. We 1356841ab66cSSepherosa Ziehau * are required to pass some node so we fall back to ic_bss 1357841ab66cSSepherosa Ziehau * when this frame is from an unknown sender. The 802.11 layer 1358841ab66cSSepherosa Ziehau * knows this means the sender wasn't in the node table and 1359841ab66cSSepherosa Ziehau * acts accordingly. 1360841ab66cSSepherosa Ziehau */ 1361841ab66cSSepherosa Ziehau struct ieee80211_node * 1362841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1363841ab66cSSepherosa Ziehau ieee80211_find_rxnode_debug(struct ieee80211com *ic, 1364841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, const char *func, int line) 1365841ab66cSSepherosa Ziehau #else 1366841ab66cSSepherosa Ziehau ieee80211_find_rxnode(struct ieee80211com *ic, 1367841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh) 1368841ab66cSSepherosa Ziehau #endif 1369841ab66cSSepherosa Ziehau { 1370841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1371841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1372841ab66cSSepherosa Ziehau 1373841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1374841ab66cSSepherosa Ziehau 1375841ab66cSSepherosa Ziehau /* XXX may want scanned nodes in the neighbor table for adhoc */ 1376841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1377841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1378841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1379841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1380841ab66cSSepherosa Ziehau else 1381841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1382841ab66cSSepherosa Ziehau /* XXX check ic_bss first in station mode */ 1383841ab66cSSepherosa Ziehau /* XXX 4-address frames? */ 1384841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1385841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1386841ab66cSSepherosa Ziehau else 1387841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1388841ab66cSSepherosa Ziehau if (ni == NULL) 1389841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1390841ab66cSSepherosa Ziehau 1391841ab66cSSepherosa Ziehau return ni; 1392841ab66cSSepherosa Ziehau } 1393841ab66cSSepherosa Ziehau 1394841ab66cSSepherosa Ziehau /* 1395841ab66cSSepherosa Ziehau * Like ieee80211_find_rxnode but use the supplied h/w 1396841ab66cSSepherosa Ziehau * key index as a hint to locate the node in the key 1397841ab66cSSepherosa Ziehau * mapping table. If an entry is present at the key 1398841ab66cSSepherosa Ziehau * index we return it; otherwise do a normal lookup and 1399841ab66cSSepherosa Ziehau * update the mapping table if the station has a unicast 1400841ab66cSSepherosa Ziehau * key assigned to it. 1401841ab66cSSepherosa Ziehau */ 1402841ab66cSSepherosa Ziehau struct ieee80211_node * 1403841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1404841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1405841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1406841ab66cSSepherosa Ziehau const char *func, int line) 1407841ab66cSSepherosa Ziehau #else 1408841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1409841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1410841ab66cSSepherosa Ziehau #endif 1411841ab66cSSepherosa Ziehau { 1412841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1413841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1414841ab66cSSepherosa Ziehau 1415841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1416841ab66cSSepherosa Ziehau 1417841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1418841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1419841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1420841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1421841ab66cSSepherosa Ziehau else 1422841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1423841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1424841ab66cSSepherosa Ziehau ni = nt->nt_keyixmap[keyix]; 1425841ab66cSSepherosa Ziehau else 1426841ab66cSSepherosa Ziehau ni = NULL; 1427841ab66cSSepherosa Ziehau if (ni == NULL) { 1428841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1429841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1430841ab66cSSepherosa Ziehau else 1431841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1432841ab66cSSepherosa Ziehau if (ni == NULL) 1433841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1434841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 1435841ab66cSSepherosa Ziehau /* 1436841ab66cSSepherosa Ziehau * If the station has a unicast key cache slot 1437841ab66cSSepherosa Ziehau * assigned update the key->node mapping table. 1438841ab66cSSepherosa Ziehau */ 1439841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1440841ab66cSSepherosa Ziehau /* XXX can keyixmap[keyix] != NULL? */ 1441841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1442841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == NULL) { 1443841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1444841ab66cSSepherosa Ziehau "%s: add key map entry %p<%6D> refcnt %d\n", 1445841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1446841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 1447841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1448841ab66cSSepherosa Ziehau } 1449841ab66cSSepherosa Ziehau } 1450841ab66cSSepherosa Ziehau } else { 1451841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1452841ab66cSSepherosa Ziehau } 1453841ab66cSSepherosa Ziehau 1454841ab66cSSepherosa Ziehau return ni; 1455841ab66cSSepherosa Ziehau } 1456841ab66cSSepherosa Ziehau #undef IS_PSPOLL 1457841ab66cSSepherosa Ziehau #undef IS_CTL 1458841ab66cSSepherosa Ziehau 1459841ab66cSSepherosa Ziehau /* 1460f186073cSJoerg Sonnenberger * Return a reference to the appropriate node for sending 1461f186073cSJoerg Sonnenberger * a data frame. This handles node discovery in adhoc networks. 1462f186073cSJoerg Sonnenberger */ 1463f186073cSJoerg Sonnenberger struct ieee80211_node * 1464841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1465841ab66cSSepherosa Ziehau ieee80211_find_txnode_debug(struct ieee80211com *ic, const uint8_t *macaddr, 1466841ab66cSSepherosa Ziehau const char *func, int line) 1467841ab66cSSepherosa Ziehau #else 1468841ab66cSSepherosa Ziehau ieee80211_find_txnode(struct ieee80211com *ic, const uint8_t *macaddr) 1469841ab66cSSepherosa Ziehau #endif 1470f186073cSJoerg Sonnenberger { 1471841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1472f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1473841ab66cSSepherosa Ziehau 1474841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1475f186073cSJoerg Sonnenberger 1476f186073cSJoerg Sonnenberger /* 1477f186073cSJoerg Sonnenberger * The destination address should be in the node table 1478841ab66cSSepherosa Ziehau * unless this is a multicast/broadcast frame. We can 1479841ab66cSSepherosa Ziehau * also optimize station mode operation, all frames go 1480841ab66cSSepherosa Ziehau * to the bss node. 1481f186073cSJoerg Sonnenberger */ 1482a6226bb4SSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1483a6226bb4SSepherosa Ziehau IEEE80211_IS_MULTICAST(macaddr)) { 1484841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1485a6226bb4SSepherosa Ziehau } else { 1486841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1487a6226bb4SSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1488a6226bb4SSepherosa Ziehau (ni != NULL && ni->ni_associd == 0)) { 1489a6226bb4SSepherosa Ziehau /* 1490a6226bb4SSepherosa Ziehau * Station is not associated; don't permit the 1491a6226bb4SSepherosa Ziehau * data frame to be sent by returning NULL. This 1492a6226bb4SSepherosa Ziehau * is kinda a kludge but the least intrusive way 1493a6226bb4SSepherosa Ziehau * to add this check into all drivers. 1494a6226bb4SSepherosa Ziehau */ 1495a6226bb4SSepherosa Ziehau ieee80211_unref_node(&ni); /* NB: null's ni */ 1496a6226bb4SSepherosa Ziehau } 1497a6226bb4SSepherosa Ziehau } 1498f186073cSJoerg Sonnenberger 1499841ab66cSSepherosa Ziehau if (ni == NULL) { 1500841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS || 1501841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO) { 1502f186073cSJoerg Sonnenberger /* 1503841ab66cSSepherosa Ziehau * In adhoc mode cons up a node for the destination. 1504841ab66cSSepherosa Ziehau * Note that we need an additional reference for the 1505841ab66cSSepherosa Ziehau * caller to be consistent with _ieee80211_find_node. 1506f186073cSJoerg Sonnenberger */ 1507841ab66cSSepherosa Ziehau ni = ieee80211_fakeup_adhoc_node(nt, macaddr); 1508841ab66cSSepherosa Ziehau if (ni != NULL) 1509841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1510841ab66cSSepherosa Ziehau } else { 1511841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, 1512841ab66cSSepherosa Ziehau "[%6D] no node, discard frame (%s)\n", 1513841ab66cSSepherosa Ziehau macaddr, ":", __func__); 1514841ab66cSSepherosa Ziehau ic->ic_stats.is_tx_nonode++; 1515f186073cSJoerg Sonnenberger } 1516f186073cSJoerg Sonnenberger } 1517f186073cSJoerg Sonnenberger return ni; 1518f186073cSJoerg Sonnenberger } 1519f186073cSJoerg Sonnenberger 1520f186073cSJoerg Sonnenberger /* 1521f186073cSJoerg Sonnenberger * Like find but search based on the channel too. 1522f186073cSJoerg Sonnenberger */ 1523f186073cSJoerg Sonnenberger struct ieee80211_node * 1524841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1525841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel_debug(struct ieee80211_node_table *nt, 1526841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan, 1527841ab66cSSepherosa Ziehau const char *func, int line) 1528841ab66cSSepherosa Ziehau #else 1529841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel(struct ieee80211_node_table *nt, 1530841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan) 1531841ab66cSSepherosa Ziehau #endif 1532f186073cSJoerg Sonnenberger { 1533f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1534f186073cSJoerg Sonnenberger int hash; 1535841ab66cSSepherosa Ziehau 1536841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1537f186073cSJoerg Sonnenberger 1538f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1539841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1540f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1541f186073cSJoerg Sonnenberger ni->ni_chan == chan) { 1542841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1543841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 15445d004897SSepherosa Ziehau REFCNT_LOC, ni, ni->ni_macaddr, ":", 1545841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1546f186073cSJoerg Sonnenberger break; 1547f186073cSJoerg Sonnenberger } 1548f186073cSJoerg Sonnenberger } 1549f186073cSJoerg Sonnenberger return ni; 1550f186073cSJoerg Sonnenberger } 1551f186073cSJoerg Sonnenberger 1552841ab66cSSepherosa Ziehau /* 1553841ab66cSSepherosa Ziehau * Like find but search based on the ssid too. 1554841ab66cSSepherosa Ziehau */ 1555841ab66cSSepherosa Ziehau struct ieee80211_node * 1556841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1557841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid_debug(struct ieee80211_node_table *nt, 1558841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid, 1559841ab66cSSepherosa Ziehau const char *func, int line) 1560841ab66cSSepherosa Ziehau #else 1561841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid(struct ieee80211_node_table *nt, 1562841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid) 1563841ab66cSSepherosa Ziehau #endif 1564f186073cSJoerg Sonnenberger { 1565841ab66cSSepherosa Ziehau #define MATCH_SSID(ni, ssid, ssidlen) \ 1566841ab66cSSepherosa Ziehau (ni->ni_esslen == ssidlen && memcmp(ni->ni_essid, ssid, ssidlen) == 0) 1567841ab66cSSepherosa Ziehau static const uint8_t zeromac[IEEE80211_ADDR_LEN]; 1568841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1569f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1570841ab66cSSepherosa Ziehau int hash; 1571f186073cSJoerg Sonnenberger 1572841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1573841ab66cSSepherosa Ziehau 1574841ab66cSSepherosa Ziehau /* 1575841ab66cSSepherosa Ziehau * A mac address that is all zero means match only the ssid; 1576841ab66cSSepherosa Ziehau * otherwise we must match both. 1577841ab66cSSepherosa Ziehau */ 1578841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(macaddr, zeromac)) { 1579841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1580841ab66cSSepherosa Ziehau if (MATCH_SSID(ni, ssid, ssidlen)) 1581841ab66cSSepherosa Ziehau break; 1582841ab66cSSepherosa Ziehau } 1583841ab66cSSepherosa Ziehau } else { 1584841ab66cSSepherosa Ziehau hash = IEEE80211_NODE_HASH(macaddr); 1585841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1586841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1587841ab66cSSepherosa Ziehau MATCH_SSID(ni, ssid, ssidlen)) 1588841ab66cSSepherosa Ziehau break; 1589841ab66cSSepherosa Ziehau } 1590841ab66cSSepherosa Ziehau } 1591841ab66cSSepherosa Ziehau if (ni != NULL) { 1592841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1593841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 15945d004897SSepherosa Ziehau REFCNT_LOC, ni, ni->ni_macaddr, ":", 1595841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1596841ab66cSSepherosa Ziehau } 1597841ab66cSSepherosa Ziehau return ni; 1598841ab66cSSepherosa Ziehau #undef MATCH_SSID 1599841ab66cSSepherosa Ziehau } 1600841ab66cSSepherosa Ziehau 1601841ab66cSSepherosa Ziehau static void 1602841ab66cSSepherosa Ziehau _ieee80211_free_node(struct ieee80211_node *ni) 1603841ab66cSSepherosa Ziehau { 1604841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1605841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1606841ab66cSSepherosa Ziehau 1607841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1608841ab66cSSepherosa Ziehau "%s %p<%6D> in %s table\n", __func__, ni, 1609841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1610841ab66cSSepherosa Ziehau nt != NULL ? nt->nt_name : "<gone>"); 1611841ab66cSSepherosa Ziehau 1612b9334f94SSepherosa Ziehau ieee80211_ratectl_data_free(ni); 1613b9334f94SSepherosa Ziehau 1614841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1615841ab66cSSepherosa Ziehau if (nt != NULL) { 1616841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1617841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1618841ab66cSSepherosa Ziehau } 1619841ab66cSSepherosa Ziehau ic->ic_node_free(ni); 1620841ab66cSSepherosa Ziehau } 1621841ab66cSSepherosa Ziehau 1622841ab66cSSepherosa Ziehau void 1623841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1624841ab66cSSepherosa Ziehau ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1625841ab66cSSepherosa Ziehau #else 1626841ab66cSSepherosa Ziehau ieee80211_free_node(struct ieee80211_node *ni) 1627841ab66cSSepherosa Ziehau #endif 1628841ab66cSSepherosa Ziehau { 1629841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1630841ab66cSSepherosa Ziehau 1631841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ni->ni_ic->ic_ifp->if_serializer); 1632841ab66cSSepherosa Ziehau 1633841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1634841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1635841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, func, line, ni, 1636841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni) - 1); 1637841ab66cSSepherosa Ziehau #endif 1638841ab66cSSepherosa Ziehau if (nt != NULL) { 1639841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) { 1640841ab66cSSepherosa Ziehau /* 1641841ab66cSSepherosa Ziehau * Last reference, reclaim state. 1642841ab66cSSepherosa Ziehau */ 1643841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1644841ab66cSSepherosa Ziehau } else if (ieee80211_node_refcnt(ni) == 1 && 1645841ab66cSSepherosa Ziehau nt->nt_keyixmap != NULL) { 1646841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1647841ab66cSSepherosa Ziehau /* 1648841ab66cSSepherosa Ziehau * Check for a last reference in the key mapping table. 1649841ab66cSSepherosa Ziehau */ 1650841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1651841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1652841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1653841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1654841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry", __func__, 1655841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":"); 1656841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1657841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* XXX needed? */ 1658841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1659841ab66cSSepherosa Ziehau } 1660841ab66cSSepherosa Ziehau } 1661841ab66cSSepherosa Ziehau } else { 1662841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) 1663841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1664841ab66cSSepherosa Ziehau } 1665f186073cSJoerg Sonnenberger } 1666f186073cSJoerg Sonnenberger 1667f186073cSJoerg Sonnenberger /* 1668841ab66cSSepherosa Ziehau * Reclaim a unicast key and clear any key cache state. 1669841ab66cSSepherosa Ziehau */ 1670841ab66cSSepherosa Ziehau int 1671841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(struct ieee80211_node *ni) 1672841ab66cSSepherosa Ziehau { 1673841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1674841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1675841ab66cSSepherosa Ziehau struct ieee80211_node *nikey; 1676841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1677841ab66cSSepherosa Ziehau int status; 1678841ab66cSSepherosa Ziehau 1679841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1680841ab66cSSepherosa Ziehau 1681841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1682841ab66cSSepherosa Ziehau status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey); 1683841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1684841ab66cSSepherosa Ziehau nikey = nt->nt_keyixmap[keyix]; 1685fc6d0222SSascha Wildner nt->nt_keyixmap[keyix] = NULL; 1686841ab66cSSepherosa Ziehau } else 1687841ab66cSSepherosa Ziehau nikey = NULL; 1688841ab66cSSepherosa Ziehau 1689841ab66cSSepherosa Ziehau if (nikey != NULL) { 1690841ab66cSSepherosa Ziehau KASSERT(nikey == ni, 1691841ab66cSSepherosa Ziehau ("key map out of sync, ni %p nikey %p", ni, nikey)); 1692841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1693841ab66cSSepherosa Ziehau "%s: delete key map entry %p<%6D> refcnt %d\n", 1694841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1695841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)-1); 1696841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1697841ab66cSSepherosa Ziehau } 1698841ab66cSSepherosa Ziehau return status; 1699841ab66cSSepherosa Ziehau } 1700841ab66cSSepherosa Ziehau 1701841ab66cSSepherosa Ziehau /* 1702841ab66cSSepherosa Ziehau * Reclaim a node. If this is the last reference count then 1703841ab66cSSepherosa Ziehau * do the normal free work. Otherwise remove it from the node 1704841ab66cSSepherosa Ziehau * table and mark it gone by clearing the back-reference. 1705841ab66cSSepherosa Ziehau */ 1706841ab66cSSepherosa Ziehau static void 1707841ab66cSSepherosa Ziehau node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1708841ab66cSSepherosa Ziehau { 1709841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1710841ab66cSSepherosa Ziehau 1711841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1712841ab66cSSepherosa Ziehau 1713841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1714841ab66cSSepherosa Ziehau "%s: remove %p<%6D> from %s table, refcnt %d\n", 1715841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1716841ab66cSSepherosa Ziehau nt->nt_name, ieee80211_node_refcnt(ni)-1); 1717b9334f94SSepherosa Ziehau 1718841ab66cSSepherosa Ziehau /* 1719841ab66cSSepherosa Ziehau * Clear any entry in the unicast key mapping table. 1720841ab66cSSepherosa Ziehau * We need to do it here so rx lookups don't find it 1721841ab66cSSepherosa Ziehau * in the mapping table even if it's not in the hash 1722841ab66cSSepherosa Ziehau * table. We cannot depend on the mapping table entry 1723841ab66cSSepherosa Ziehau * being cleared because the node may not be free'd. 1724841ab66cSSepherosa Ziehau */ 1725841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1726841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1727841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1728841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1729841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry\n", 1730841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":"); 1731841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1732841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* NB: don't need free */ 1733841ab66cSSepherosa Ziehau } 1734841ab66cSSepherosa Ziehau if (!ieee80211_node_dectestref(ni)) { 1735841ab66cSSepherosa Ziehau /* 1736841ab66cSSepherosa Ziehau * Other references are present, just remove the 1737841ab66cSSepherosa Ziehau * node from the table so it cannot be found. When 1738841ab66cSSepherosa Ziehau * the references are dropped storage will be 1739841ab66cSSepherosa Ziehau * reclaimed. 1740841ab66cSSepherosa Ziehau */ 1741841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1742841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1743841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* clear reference */ 17449639b71dSSepherosa Ziehau 17459639b71dSSepherosa Ziehau /* 17469639b71dSSepherosa Ziehau * XXX 17479639b71dSSepherosa Ziehau * We may want to put reclaimed node on <gone> table 17489639b71dSSepherosa Ziehau * so that ratectl modules can find them and free 17499639b71dSSepherosa Ziehau * the resources in their detach routines instead of 17509639b71dSSepherosa Ziehau * freeing the resources here. 17519639b71dSSepherosa Ziehau */ 17529639b71dSSepherosa Ziehau ieee80211_ratectl_data_free(ni); 1753841ab66cSSepherosa Ziehau } else 1754841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1755841ab66cSSepherosa Ziehau } 1756841ab66cSSepherosa Ziehau 1757841ab66cSSepherosa Ziehau static void 1758841ab66cSSepherosa Ziehau ieee80211_free_allnodes(struct ieee80211_node_table *nt) 1759841ab66cSSepherosa Ziehau { 1760841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1761841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1762841ab66cSSepherosa Ziehau 1763841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1764841ab66cSSepherosa Ziehau "%s: free all nodes in %s table\n", __func__, nt->nt_name); 1765841ab66cSSepherosa Ziehau 1766841ab66cSSepherosa Ziehau while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) { 1767841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1768841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 1769841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 1770841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1771841ab66cSSepherosa Ziehau } 1772841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1773841ab66cSSepherosa Ziehau } 1774841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 1775841ab66cSSepherosa Ziehau } 1776841ab66cSSepherosa Ziehau 1777841ab66cSSepherosa Ziehau /* 1778841ab66cSSepherosa Ziehau * Timeout entries in the scan cache. 1779841ab66cSSepherosa Ziehau */ 1780841ab66cSSepherosa Ziehau static void 1781841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates(struct ieee80211_node_table *nt) 1782841ab66cSSepherosa Ziehau { 1783841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1784841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *tni; 1785841ab66cSSepherosa Ziehau 1786841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1787841ab66cSSepherosa Ziehau 1788841ab66cSSepherosa Ziehau ni = ic->ic_bss; 1789841ab66cSSepherosa Ziehau /* XXX belongs elsewhere */ 1790841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && ticks > ni->ni_rxfragstamp + hz) { 1791841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1792841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1793841ab66cSSepherosa Ziehau } 1794841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, tni) { 1795841ab66cSSepherosa Ziehau if (ni->ni_inact && --ni->ni_inact == 0) { 1796841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1797841ab66cSSepherosa Ziehau "[%6D] scan candidate purged from cache " 1798841ab66cSSepherosa Ziehau "(refcnt %u)\n", ni->ni_macaddr, ":", 1799841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1800841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1801841ab66cSSepherosa Ziehau } 1802841ab66cSSepherosa Ziehau } 1803841ab66cSSepherosa Ziehau 1804841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1805841ab66cSSepherosa Ziehau } 1806841ab66cSSepherosa Ziehau 1807841ab66cSSepherosa Ziehau /* 1808841ab66cSSepherosa Ziehau * Timeout inactive stations and do related housekeeping. 1809841ab66cSSepherosa Ziehau * Note that we cannot hold the node lock while sending a 1810841ab66cSSepherosa Ziehau * frame as this would lead to a LOR. Instead we use a 1811841ab66cSSepherosa Ziehau * generation number to mark nodes that we've scanned and 1812841ab66cSSepherosa Ziehau * drop the lock and restart a scan if we have to time out 1813841ab66cSSepherosa Ziehau * a node. Since we are single-threaded by virtue of 1814f186073cSJoerg Sonnenberger * controlling the inactivity timer we can be sure this will 1815f186073cSJoerg Sonnenberger * process each node only once. 1816f186073cSJoerg Sonnenberger */ 1817841ab66cSSepherosa Ziehau static void 1818841ab66cSSepherosa Ziehau ieee80211_timeout_stations(struct ieee80211_node_table *nt) 1819f186073cSJoerg Sonnenberger { 1820841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1821841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1822841ab66cSSepherosa Ziehau int isadhoc; 1823f186073cSJoerg Sonnenberger 1824841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1825841ab66cSSepherosa Ziehau 1826841ab66cSSepherosa Ziehau isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS || 1827841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO); 1828841ab66cSSepherosa Ziehau 1829841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) { 1830f186073cSJoerg Sonnenberger /* 1831841ab66cSSepherosa Ziehau * Ignore entries for which have yet to receive an 1832841ab66cSSepherosa Ziehau * authentication frame. These are transient and 1833841ab66cSSepherosa Ziehau * will be reclaimed when the last reference to them 1834841ab66cSSepherosa Ziehau * goes away (when frame xmits complete). 1835f186073cSJoerg Sonnenberger */ 1836841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1837841ab66cSSepherosa Ziehau (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1838841ab66cSSepherosa Ziehau continue; 1839841ab66cSSepherosa Ziehau /* 1840841ab66cSSepherosa Ziehau * Free fragment if not needed anymore 1841841ab66cSSepherosa Ziehau * (last fragment older than 1s). 1842841ab66cSSepherosa Ziehau * XXX doesn't belong here 1843841ab66cSSepherosa Ziehau */ 1844841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && 1845841ab66cSSepherosa Ziehau ticks > ni->ni_rxfragstamp + hz) { 1846841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1847841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1848841ab66cSSepherosa Ziehau } 1849841ab66cSSepherosa Ziehau /* 1850841ab66cSSepherosa Ziehau * Special case ourself; we may be idle for extended periods 1851841ab66cSSepherosa Ziehau * of time and regardless reclaiming our state is wrong. 1852841ab66cSSepherosa Ziehau */ 1853841ab66cSSepherosa Ziehau if (ni == ic->ic_bss) 1854841ab66cSSepherosa Ziehau continue; 1855841ab66cSSepherosa Ziehau ni->ni_inact--; 1856841ab66cSSepherosa Ziehau if (ni->ni_associd != 0 || isadhoc) { 1857841ab66cSSepherosa Ziehau /* 1858841ab66cSSepherosa Ziehau * Age frames on the power save queue. The 1859841ab66cSSepherosa Ziehau * aging interval is 4 times the listen 1860841ab66cSSepherosa Ziehau * interval specified by the station. This 1861841ab66cSSepherosa Ziehau * number is factored into the age calculations 1862841ab66cSSepherosa Ziehau * when the frame is placed on the queue. We 1863841ab66cSSepherosa Ziehau * store ages as time differences we can check 1864841ab66cSSepherosa Ziehau * and/or adjust only the head of the list. 1865841ab66cSSepherosa Ziehau */ 1866841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) { 1867841ab66cSSepherosa Ziehau struct mbuf *m; 1868841ab66cSSepherosa Ziehau int discard = 0; 1869841ab66cSSepherosa Ziehau 1870841ab66cSSepherosa Ziehau while (IF_POLL(&ni->ni_savedq, m) != NULL && 1871841ab66cSSepherosa Ziehau M_AGE_GET(m) < IEEE80211_INACT_WAIT) { 1872841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1873841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1874841ab66cSSepherosa Ziehau "[%6D] discard frame, age %u\n", 1875841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1876841ab66cSSepherosa Ziehau M_AGE_GET(m));/*XXX*/ 1877841ab66cSSepherosa Ziehau _IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m); 1878841ab66cSSepherosa Ziehau m_freem(m); 1879841ab66cSSepherosa Ziehau discard++; 1880841ab66cSSepherosa Ziehau } 1881841ab66cSSepherosa Ziehau if (m != NULL) 1882841ab66cSSepherosa Ziehau M_AGE_SUB(m, IEEE80211_INACT_WAIT); 1883841ab66cSSepherosa Ziehau 1884841ab66cSSepherosa Ziehau if (discard != 0) { 1885841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1886841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1887841ab66cSSepherosa Ziehau "[%6D] discard %u frames for age\n", 1888841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1889841ab66cSSepherosa Ziehau discard); 1890841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_ADD(ni, 1891841ab66cSSepherosa Ziehau ps_discard, discard); 1892841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) 1893841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 1894841ab66cSSepherosa Ziehau } 1895841ab66cSSepherosa Ziehau } 1896841ab66cSSepherosa Ziehau /* 1897841ab66cSSepherosa Ziehau * Probe the station before time it out. We 1898841ab66cSSepherosa Ziehau * send a null data frame which may not be 1899841ab66cSSepherosa Ziehau * universally supported by drivers (need it 1900841ab66cSSepherosa Ziehau * for ps-poll support so it should be...). 1901841ab66cSSepherosa Ziehau */ 1902841ab66cSSepherosa Ziehau if (0 < ni->ni_inact && 1903841ab66cSSepherosa Ziehau ni->ni_inact <= ic->ic_inact_probe) { 1904841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1905841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 1906841ab66cSSepherosa Ziehau ni, "%s", 1907841ab66cSSepherosa Ziehau "probe station due to inactivity"); 1908841ab66cSSepherosa Ziehau /* 1909841ab66cSSepherosa Ziehau * Grab a reference before unlocking the table 1910841ab66cSSepherosa Ziehau * so the node cannot be reclaimed before we 1911841ab66cSSepherosa Ziehau * send the frame. ieee80211_send_nulldata 1912841ab66cSSepherosa Ziehau * understands we've done this and reclaims the 1913841ab66cSSepherosa Ziehau * ref for us as needed. 1914841ab66cSSepherosa Ziehau */ 1915841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1916841ab66cSSepherosa Ziehau ieee80211_send_nulldata(ni); 1917841ab66cSSepherosa Ziehau /* XXX stat? */ 1918841ab66cSSepherosa Ziehau continue; 1919841ab66cSSepherosa Ziehau } 1920841ab66cSSepherosa Ziehau } 1921841ab66cSSepherosa Ziehau if (ni->ni_inact <= 0) { 1922841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1923841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 1924841ab66cSSepherosa Ziehau "station timed out due to inactivity " 1925841ab66cSSepherosa Ziehau "(refcnt %u)", ieee80211_node_refcnt(ni)); 1926841ab66cSSepherosa Ziehau /* 1927841ab66cSSepherosa Ziehau * Send a deauthenticate frame and drop the station. 1928841ab66cSSepherosa Ziehau * This is somewhat complicated due to reference counts 1929841ab66cSSepherosa Ziehau * and locking. At this point a station will typically 1930841ab66cSSepherosa Ziehau * have a reference count of 1. ieee80211_node_leave 1931841ab66cSSepherosa Ziehau * will do a "free" of the node which will drop the 1932841ab66cSSepherosa Ziehau * reference count. But in the meantime a reference 1933841ab66cSSepherosa Ziehau * wil be held by the deauth frame. The actual reclaim 1934841ab66cSSepherosa Ziehau * of the node will happen either after the tx is 1935841ab66cSSepherosa Ziehau * completed or by ieee80211_node_leave. 1936841ab66cSSepherosa Ziehau */ 1937841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1938f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1939f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 1940f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_EXPIRE); 1941841ab66cSSepherosa Ziehau } 1942841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 1943f186073cSJoerg Sonnenberger ic->ic_stats.is_node_timeout++; 1944841ab66cSSepherosa Ziehau continue; 1945f186073cSJoerg Sonnenberger } 1946f186073cSJoerg Sonnenberger } 1947841ab66cSSepherosa Ziehau 1948841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1949f186073cSJoerg Sonnenberger } 1950f186073cSJoerg Sonnenberger 1951f186073cSJoerg Sonnenberger void 1952841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg) 1953f186073cSJoerg Sonnenberger { 1954841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1955f186073cSJoerg Sonnenberger 1956841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1957841ab66cSSepherosa Ziehau 1958841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) 1959841ab66cSSepherosa Ziehau f(arg, ni); 1960841ab66cSSepherosa Ziehau } 1961841ab66cSSepherosa Ziehau 1962841ab66cSSepherosa Ziehau void 1963841ab66cSSepherosa Ziehau ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1964841ab66cSSepherosa Ziehau { 1965a6ec04bcSSascha Wildner kprintf("0x%p: mac %6D refcnt %d\n", ni, 1966841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)); 1967a6ec04bcSSascha Wildner kprintf("\tauthmode %u flags 0x%x\n", 1968841ab66cSSepherosa Ziehau ni->ni_authmode, ni->ni_flags); 1969a6ec04bcSSascha Wildner kprintf("\tassocid 0x%x txpower %u vlan %u\n", 1970841ab66cSSepherosa Ziehau ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 1971a6ec04bcSSascha Wildner kprintf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 1972841ab66cSSepherosa Ziehau ni->ni_txseqs[0], 1973841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] >> IEEE80211_SEQ_SEQ_SHIFT, 1974841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] & IEEE80211_SEQ_FRAG_MASK, 1975841ab66cSSepherosa Ziehau ni->ni_rxfragstamp); 1976a6ec04bcSSascha Wildner kprintf("\trstamp %u rssi %u intval %u capinfo 0x%x\n", 1977841ab66cSSepherosa Ziehau ni->ni_rstamp, ni->ni_rssi, ni->ni_intval, ni->ni_capinfo); 1978a6ec04bcSSascha Wildner kprintf("\tbssid %6D essid \"%.*s\" channel %u:0x%x\n", 1979841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 1980841ab66cSSepherosa Ziehau ni->ni_esslen, ni->ni_essid, 1981841ab66cSSepherosa Ziehau ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 1982a6ec04bcSSascha Wildner kprintf("\tfails %u inact %u txrate %u\n", 1983841ab66cSSepherosa Ziehau ni->ni_fails, ni->ni_inact, ni->ni_txrate); 1984841ab66cSSepherosa Ziehau } 1985841ab66cSSepherosa Ziehau 1986841ab66cSSepherosa Ziehau void 1987841ab66cSSepherosa Ziehau ieee80211_dump_nodes(struct ieee80211_node_table *nt) 1988841ab66cSSepherosa Ziehau { 1989841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(nt, 1990841ab66cSSepherosa Ziehau (ieee80211_iter_func *) ieee80211_dump_node, nt); 1991841ab66cSSepherosa Ziehau } 1992841ab66cSSepherosa Ziehau 1993841ab66cSSepherosa Ziehau /* 1994841ab66cSSepherosa Ziehau * Handle a station joining an 11g network. 1995841ab66cSSepherosa Ziehau */ 1996841ab66cSSepherosa Ziehau static void 1997841ab66cSSepherosa Ziehau ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 1998841ab66cSSepherosa Ziehau { 1999841ab66cSSepherosa Ziehau 2000841ab66cSSepherosa Ziehau /* 2001841ab66cSSepherosa Ziehau * Station isn't capable of short slot time. Bump 2002841ab66cSSepherosa Ziehau * the count of long slot time stations and disable 2003841ab66cSSepherosa Ziehau * use of short slot time. Note that the actual switch 2004841ab66cSSepherosa Ziehau * over to long slot time use may not occur until the 2005841ab66cSSepherosa Ziehau * next beacon transmission (per sec. 7.3.1.4 of 11g). 2006841ab66cSSepherosa Ziehau */ 2007841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2008841ab66cSSepherosa Ziehau ic->ic_longslotsta++; 2009841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2010841ab66cSSepherosa Ziehau "[%6D] station needs long slot time, count %d\n", 2011841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 2012841ab66cSSepherosa Ziehau /* XXX vap's w/ conflicting needs won't work */ 2013841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 0); 2014841ab66cSSepherosa Ziehau } 2015841ab66cSSepherosa Ziehau /* 2016841ab66cSSepherosa Ziehau * If the new station is not an ERP station 2017841ab66cSSepherosa Ziehau * then bump the counter and enable protection 2018841ab66cSSepherosa Ziehau * if configured. 2019841ab66cSSepherosa Ziehau */ 2020841ab66cSSepherosa Ziehau if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) { 2021841ab66cSSepherosa Ziehau ic->ic_nonerpsta++; 2022841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2023841ab66cSSepherosa Ziehau "[%6D] station is !ERP, %d non-ERP stations associated\n", 2024841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 2025841ab66cSSepherosa Ziehau /* 2026841ab66cSSepherosa Ziehau * If protection is configured, enable it. 2027841ab66cSSepherosa Ziehau */ 2028841ab66cSSepherosa Ziehau if (ic->ic_protmode != IEEE80211_PROT_NONE) { 2029841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2030841ab66cSSepherosa Ziehau "%s: enable use of protection\n", __func__); 2031841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEPROT; 2032841ab66cSSepherosa Ziehau } 2033841ab66cSSepherosa Ziehau /* 2034841ab66cSSepherosa Ziehau * If station does not support short preamble 2035841ab66cSSepherosa Ziehau * then we must enable use of Barker preamble. 2036841ab66cSSepherosa Ziehau */ 2037841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 2038841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2039841ab66cSSepherosa Ziehau "[%6D] station needs long preamble\n", 2040841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 2041ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, 0); 2042841ab66cSSepherosa Ziehau } 2043841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 1) 2044841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2045841ab66cSSepherosa Ziehau } else 2046841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_ERP; 2047841ab66cSSepherosa Ziehau } 2048841ab66cSSepherosa Ziehau 2049841ab66cSSepherosa Ziehau void 2050841ab66cSSepherosa Ziehau ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) 2051841ab66cSSepherosa Ziehau { 2052841ab66cSSepherosa Ziehau int newassoc; 2053841ab66cSSepherosa Ziehau 2054841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) { 2055841ab66cSSepherosa Ziehau uint16_t aid; 2056841ab66cSSepherosa Ziehau 2057841ab66cSSepherosa Ziehau /* 2058841ab66cSSepherosa Ziehau * It would be good to search the bitmap 2059841ab66cSSepherosa Ziehau * more efficiently, but this will do for now. 2060841ab66cSSepherosa Ziehau */ 2061841ab66cSSepherosa Ziehau for (aid = 1; aid < ic->ic_max_aid; aid++) { 2062841ab66cSSepherosa Ziehau if (!IEEE80211_AID_ISSET(aid, 2063841ab66cSSepherosa Ziehau ic->ic_aid_bitmap)) 2064841ab66cSSepherosa Ziehau break; 2065841ab66cSSepherosa Ziehau } 2066841ab66cSSepherosa Ziehau if (aid >= ic->ic_max_aid) { 2067841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, 2068841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_TOOMANY); 2069841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 2070841ab66cSSepherosa Ziehau return; 2071841ab66cSSepherosa Ziehau } 2072841ab66cSSepherosa Ziehau ni->ni_associd = aid | 0xc000; 2073841ab66cSSepherosa Ziehau IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); 2074841ab66cSSepherosa Ziehau ic->ic_sta_assoc++; 2075841ab66cSSepherosa Ziehau newassoc = 1; 2076841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2077841ab66cSSepherosa Ziehau ieee80211_node_join_11g(ic, ni); 2078841ab66cSSepherosa Ziehau } else 2079841ab66cSSepherosa Ziehau newassoc = 0; 2080841ab66cSSepherosa Ziehau 2081841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2082841ab66cSSepherosa Ziehau "[%6D] station %sassociated at aid %d: %s preamble, %s slot time%s%s\n", 2083841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", newassoc ? "" : "re", 2084841ab66cSSepherosa Ziehau IEEE80211_NODE_AID(ni), 2085841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2086841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2087841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2088841ab66cSSepherosa Ziehau ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "" 2089841ab66cSSepherosa Ziehau ); 2090841ab66cSSepherosa Ziehau 2091476d885dSSepherosa Ziehau IEEE80211_PRINT_NODERATES(ic, ni, 2092476d885dSSepherosa Ziehau IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG); 209321152d39SSepherosa Ziehau 2094b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, newassoc); 2095b9334f94SSepherosa Ziehau 2096841ab66cSSepherosa Ziehau /* give driver a chance to setup state like ni_txrate */ 2097841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 2098841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, newassoc); 2099b9334f94SSepherosa Ziehau 2100841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_auth; 2101841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 2102841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); 2103841ab66cSSepherosa Ziehau /* tell the authenticator about new station */ 2104841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_join != NULL) 2105841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_join(ic, ni); 2106841ab66cSSepherosa Ziehau ieee80211_notify_node_join(ic, ni, newassoc); 2107841ab66cSSepherosa Ziehau } 2108841ab66cSSepherosa Ziehau 2109841ab66cSSepherosa Ziehau /* 2110841ab66cSSepherosa Ziehau * Handle a station leaving an 11g network. 2111841ab66cSSepherosa Ziehau */ 2112841ab66cSSepherosa Ziehau static void 2113841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 2114841ab66cSSepherosa Ziehau { 2115841ab66cSSepherosa Ziehau 2116841ab66cSSepherosa Ziehau KASSERT(ic->ic_curmode == IEEE80211_MODE_11G, 2117841ab66cSSepherosa Ziehau ("not in 11g, bss %u:0x%x, curmode %u", ni->ni_chan->ic_freq, 2118841ab66cSSepherosa Ziehau ni->ni_chan->ic_flags, ic->ic_curmode)); 2119841ab66cSSepherosa Ziehau 2120841ab66cSSepherosa Ziehau /* 2121841ab66cSSepherosa Ziehau * If a long slot station do the slot time bookkeeping. 2122841ab66cSSepherosa Ziehau */ 2123841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2124841ab66cSSepherosa Ziehau KASSERT(ic->ic_longslotsta > 0, 2125841ab66cSSepherosa Ziehau ("bogus long slot station count %d", ic->ic_longslotsta)); 2126841ab66cSSepherosa Ziehau ic->ic_longslotsta--; 2127841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2128841ab66cSSepherosa Ziehau "[%6D] long slot time station leaves, count now %d\n", 2129841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 2130841ab66cSSepherosa Ziehau if (ic->ic_longslotsta == 0) { 2131841ab66cSSepherosa Ziehau /* 2132841ab66cSSepherosa Ziehau * Re-enable use of short slot time if supported 2133841ab66cSSepherosa Ziehau * and not operating in IBSS mode (per spec). 2134841ab66cSSepherosa Ziehau */ 2135841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2136841ab66cSSepherosa Ziehau ic->ic_opmode != IEEE80211_M_IBSS) { 2137841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2138841ab66cSSepherosa Ziehau "%s: re-enable use of short slot time\n", 2139841ab66cSSepherosa Ziehau __func__); 2140841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 1); 2141841ab66cSSepherosa Ziehau } 2142841ab66cSSepherosa Ziehau } 2143841ab66cSSepherosa Ziehau } 2144841ab66cSSepherosa Ziehau /* 2145841ab66cSSepherosa Ziehau * If a non-ERP station do the protection-related bookkeeping. 2146841ab66cSSepherosa Ziehau */ 2147841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2148841ab66cSSepherosa Ziehau KASSERT(ic->ic_nonerpsta > 0, 2149841ab66cSSepherosa Ziehau ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2150841ab66cSSepherosa Ziehau ic->ic_nonerpsta--; 2151841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2152841ab66cSSepherosa Ziehau "[%6D] non-ERP station leaves, count now %d\n", 2153841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 2154841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 0) { 2155841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2156841ab66cSSepherosa Ziehau "%s: disable use of protection\n", __func__); 2157841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT; 2158841ab66cSSepherosa Ziehau /* XXX verify mode? */ 2159841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2160841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2161841ab66cSSepherosa Ziehau "%s: re-enable use of short preamble\n", 2162841ab66cSSepherosa Ziehau __func__); 2163ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, 1); 2164841ab66cSSepherosa Ziehau } 2165841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2166841ab66cSSepherosa Ziehau } 2167841ab66cSSepherosa Ziehau } 2168841ab66cSSepherosa Ziehau } 2169841ab66cSSepherosa Ziehau 2170841ab66cSSepherosa Ziehau /* 2171841ab66cSSepherosa Ziehau * Handle bookkeeping for station deauthentication/disassociation 2172841ab66cSSepherosa Ziehau * when operating as an ap. 2173841ab66cSSepherosa Ziehau */ 2174841ab66cSSepherosa Ziehau void 2175841ab66cSSepherosa Ziehau ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 2176841ab66cSSepherosa Ziehau { 2177841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 2178841ab66cSSepherosa Ziehau 2179841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2180841ab66cSSepherosa Ziehau 2181841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2182841ab66cSSepherosa Ziehau "[%6D] station with aid %d leaves\n", 2183841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", IEEE80211_NODE_AID(ni)); 2184841ab66cSSepherosa Ziehau 2185841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2186841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS || 2187841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO, 2188841ab66cSSepherosa Ziehau ("unexpected operating mode %u", ic->ic_opmode)); 2189841ab66cSSepherosa Ziehau /* 2190841ab66cSSepherosa Ziehau * If node wasn't previously associated all 2191841ab66cSSepherosa Ziehau * we need to do is reclaim the reference. 2192841ab66cSSepherosa Ziehau */ 2193841ab66cSSepherosa Ziehau /* XXX ibss mode bypasses 11g and notification */ 2194841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) 2195841ab66cSSepherosa Ziehau goto done; 2196841ab66cSSepherosa Ziehau /* 2197841ab66cSSepherosa Ziehau * Tell the authenticator the station is leaving. 2198841ab66cSSepherosa Ziehau * Note that we must do this before yanking the 2199841ab66cSSepherosa Ziehau * association id as the authenticator uses the 2200841ab66cSSepherosa Ziehau * associd to locate it's state block. 2201841ab66cSSepherosa Ziehau */ 2202841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 2203841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 2204841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 2205841ab66cSSepherosa Ziehau ni->ni_associd = 0; 2206841ab66cSSepherosa Ziehau ic->ic_sta_assoc--; 2207841ab66cSSepherosa Ziehau 2208841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2209841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(ic, ni); 2210841ab66cSSepherosa Ziehau /* 2211841ab66cSSepherosa Ziehau * Cleanup station state. In particular clear various 2212841ab66cSSepherosa Ziehau * state that might otherwise be reused if the node 2213841ab66cSSepherosa Ziehau * is reused before the reference count goes to zero 2214841ab66cSSepherosa Ziehau * (and memory is reclaimed). 2215841ab66cSSepherosa Ziehau */ 2216841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 2217841ab66cSSepherosa Ziehau done: 2218841ab66cSSepherosa Ziehau /* 2219841ab66cSSepherosa Ziehau * Remove the node from any table it's recorded in and 2220841ab66cSSepherosa Ziehau * drop the caller's reference. Removal from the table 2221841ab66cSSepherosa Ziehau * is important to insure the node is not reprocessed 2222841ab66cSSepherosa Ziehau * for inactivity. 2223841ab66cSSepherosa Ziehau */ 2224841ab66cSSepherosa Ziehau if (nt != NULL) 2225841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 2226841ab66cSSepherosa Ziehau else 2227841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2228841ab66cSSepherosa Ziehau } 2229841ab66cSSepherosa Ziehau 2230841ab66cSSepherosa Ziehau uint8_t 2231841ab66cSSepherosa Ziehau ieee80211_getrssi(struct ieee80211com *ic) 2232841ab66cSSepherosa Ziehau { 2233841ab66cSSepherosa Ziehau #define NZ(x) ((x) == 0 ? 1 : (x)) 2234841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 2235841ab66cSSepherosa Ziehau uint32_t rssi_samples, rssi_total; 2236841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 2237841ab66cSSepherosa Ziehau 2238841ab66cSSepherosa Ziehau rssi_total = 0; 2239841ab66cSSepherosa Ziehau rssi_samples = 0; 2240841ab66cSSepherosa Ziehau switch (ic->ic_opmode) { 2241841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2242841ab66cSSepherosa Ziehau /* XXX locking */ 2243841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2244841ab66cSSepherosa Ziehau if (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) { 2245841ab66cSSepherosa Ziehau rssi_samples++; 2246841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2247841ab66cSSepherosa Ziehau } 2248841ab66cSSepherosa Ziehau break; 2249841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2250841ab66cSSepherosa Ziehau /* XXX locking */ 2251841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2252841ab66cSSepherosa Ziehau rssi_samples++; 2253841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2254841ab66cSSepherosa Ziehau } 2255841ab66cSSepherosa Ziehau break; 2256841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2257841ab66cSSepherosa Ziehau /* XXX locking */ 2258841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2259841ab66cSSepherosa Ziehau if (IEEE80211_AID(ni->ni_associd) != 0) { 2260841ab66cSSepherosa Ziehau rssi_samples++; 2261841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2262841ab66cSSepherosa Ziehau } 2263841ab66cSSepherosa Ziehau break; 2264841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* XXX */ 2265841ab66cSSepherosa Ziehau case IEEE80211_M_STA: /* use stats from associated ap */ 2266841ab66cSSepherosa Ziehau default: 2267841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) 2268841ab66cSSepherosa Ziehau rssi_total = ic->ic_node_getrssi(ic->ic_bss); 2269841ab66cSSepherosa Ziehau rssi_samples = 1; 2270841ab66cSSepherosa Ziehau break; 2271841ab66cSSepherosa Ziehau } 2272841ab66cSSepherosa Ziehau return rssi_total / NZ(rssi_samples); 2273841ab66cSSepherosa Ziehau #undef NZ 2274841ab66cSSepherosa Ziehau } 2275841ab66cSSepherosa Ziehau 2276841ab66cSSepherosa Ziehau /* 2277841ab66cSSepherosa Ziehau * Indicate whether there are frames queued for a station in power-save mode. 2278841ab66cSSepherosa Ziehau */ 2279841ab66cSSepherosa Ziehau static void 2280841ab66cSSepherosa Ziehau ieee80211_set_tim(struct ieee80211_node *ni, int set) 2281841ab66cSSepherosa Ziehau { 2282841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 2283841ab66cSSepherosa Ziehau uint16_t aid; 2284841ab66cSSepherosa Ziehau 2285841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2286841ab66cSSepherosa Ziehau 2287841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2288841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS, 2289841ab66cSSepherosa Ziehau ("operating mode %u", ic->ic_opmode)); 2290841ab66cSSepherosa Ziehau 2291841ab66cSSepherosa Ziehau aid = IEEE80211_AID(ni->ni_associd); 2292841ab66cSSepherosa Ziehau KASSERT(aid < ic->ic_max_aid, 2293841ab66cSSepherosa Ziehau ("bogus aid %u, max %u", aid, ic->ic_max_aid)); 2294841ab66cSSepherosa Ziehau 2295841ab66cSSepherosa Ziehau if (set != (isset(ic->ic_tim_bitmap, aid) != 0)) { 2296841ab66cSSepherosa Ziehau if (set) { 2297841ab66cSSepherosa Ziehau setbit(ic->ic_tim_bitmap, aid); 2298841ab66cSSepherosa Ziehau ic->ic_ps_pending++; 2299841ab66cSSepherosa Ziehau } else { 2300841ab66cSSepherosa Ziehau clrbit(ic->ic_tim_bitmap, aid); 2301841ab66cSSepherosa Ziehau ic->ic_ps_pending--; 2302841ab66cSSepherosa Ziehau } 2303841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_TIMUPDATE; 2304841ab66cSSepherosa Ziehau } 2305841ab66cSSepherosa Ziehau } 2306841ab66cSSepherosa Ziehau 2307841ab66cSSepherosa Ziehau /* 2308841ab66cSSepherosa Ziehau * Node table support. 2309841ab66cSSepherosa Ziehau */ 2310841ab66cSSepherosa Ziehau 2311841ab66cSSepherosa Ziehau static void 2312841ab66cSSepherosa Ziehau ieee80211_node_table_init(struct ieee80211com *ic, 2313841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, 2314841ab66cSSepherosa Ziehau const char *name, int inact, int keyixmax, 2315841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)) 2316841ab66cSSepherosa Ziehau { 2317841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 2318841ab66cSSepherosa Ziehau "%s %s table, inact %u\n", __func__, name, inact); 2319841ab66cSSepherosa Ziehau 2320841ab66cSSepherosa Ziehau nt->nt_ic = ic; 2321841ab66cSSepherosa Ziehau TAILQ_INIT(&nt->nt_node); 2322841ab66cSSepherosa Ziehau nt->nt_name = name; 2323841ab66cSSepherosa Ziehau nt->nt_inact_init = inact; 2324841ab66cSSepherosa Ziehau nt->nt_timeout = timeout; 2325841ab66cSSepherosa Ziehau nt->nt_keyixmax = keyixmax; 2326841ab66cSSepherosa Ziehau if (nt->nt_keyixmax > 0) { 2327841ab66cSSepherosa Ziehau nt->nt_keyixmap = 232877652cadSMatthew Dillon kmalloc(keyixmax * sizeof(struct ieee80211_node *), 2329841ab66cSSepherosa Ziehau M_80211_NODE, M_WAITOK | M_ZERO); 2330841ab66cSSepherosa Ziehau } else { 2331841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2332841ab66cSSepherosa Ziehau } 2333841ab66cSSepherosa Ziehau } 2334841ab66cSSepherosa Ziehau 2335841ab66cSSepherosa Ziehau void 2336841ab66cSSepherosa Ziehau ieee80211_node_table_reset(struct ieee80211_node_table *nt) 2337841ab66cSSepherosa Ziehau { 2338841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2339841ab66cSSepherosa Ziehau 2340841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2341841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2342841ab66cSSepherosa Ziehau 2343841ab66cSSepherosa Ziehau nt->nt_inact_timer = 0; 2344841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2345841ab66cSSepherosa Ziehau } 2346841ab66cSSepherosa Ziehau 2347841ab66cSSepherosa Ziehau static void 2348841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 2349841ab66cSSepherosa Ziehau { 2350841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2351841ab66cSSepherosa Ziehau 2352841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2353841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2354841ab66cSSepherosa Ziehau 2355841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2356841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 2357841ab66cSSepherosa Ziehau /* XXX verify all entries are NULL */ 2358841ab66cSSepherosa Ziehau int i; 2359841ab66cSSepherosa Ziehau for (i = 0; i < nt->nt_keyixmax; i++) 2360841ab66cSSepherosa Ziehau if (nt->nt_keyixmap[i] != NULL) { 2361a6ec04bcSSascha Wildner kprintf("%s: %s[%u] still active\n", __func__, 2362841ab66cSSepherosa Ziehau nt->nt_name, i); 2363841ab66cSSepherosa Ziehau } 2364efda3bd0SMatthew Dillon kfree(nt->nt_keyixmap, M_80211_NODE); 2365841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2366841ab66cSSepherosa Ziehau } 2367f186073cSJoerg Sonnenberger } 2368ab0665aaSSepherosa Ziehau 2369ab0665aaSSepherosa Ziehau /* 2370ab0665aaSSepherosa Ziehau * Update short preamble state 2371ab0665aaSSepherosa Ziehau */ 2372ab0665aaSSepherosa Ziehau void 2373ab0665aaSSepherosa Ziehau ieee80211_update_shpreamble(struct ieee80211com *ic, 2374ab0665aaSSepherosa Ziehau const struct ieee80211_node *ni) 2375ab0665aaSSepherosa Ziehau { 2376ab0665aaSSepherosa Ziehau int shpreamble = 0; 2377ab0665aaSSepherosa Ziehau 2378ab0665aaSSepherosa Ziehau switch (ic->ic_curmode) { 2379ab0665aaSSepherosa Ziehau case IEEE80211_MODE_11A: 2380ab0665aaSSepherosa Ziehau shpreamble = 1; 2381ab0665aaSSepherosa Ziehau break; 2382ab0665aaSSepherosa Ziehau case IEEE80211_MODE_11G: 2383ab0665aaSSepherosa Ziehau if (ni->ni_erp & IEEE80211_ERP_LONG_PREAMBLE) { 2384ab0665aaSSepherosa Ziehau /* 2385ab0665aaSSepherosa Ziehau * According to IEEE Std 802.11g-2003 subclause 2386ab0665aaSSepherosa Ziehau * 7.3.2.13, page 10: 2387ab0665aaSSepherosa Ziehau * Short preamble should not be used, if barker 2388ab0665aaSSepherosa Ziehau * preamble mode bit is 1 in ERP informarion, 2389ab0665aaSSepherosa Ziehau * _regardless_ of the short preamble bit in 2390ab0665aaSSepherosa Ziehau * capability information. 2391ab0665aaSSepherosa Ziehau */ 2392ab0665aaSSepherosa Ziehau break; 2393ab0665aaSSepherosa Ziehau } 2394ab0665aaSSepherosa Ziehau /* FALL THROUGH */ 2395ab0665aaSSepherosa Ziehau default: 2396ab0665aaSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) && 2397ab0665aaSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) 2398ab0665aaSSepherosa Ziehau shpreamble = 1; 2399ab0665aaSSepherosa Ziehau break; 2400ab0665aaSSepherosa Ziehau } 2401ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, shpreamble); 2402ab0665aaSSepherosa Ziehau } 2403