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 * 32841ab66cSSepherosa Ziehau * $FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.48.2.10 2006/03/13 03:05:47 sam Exp $ 33*77652cadSMatthew Dillon * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_node.c,v 1.6 2006/09/05 03:48:12 dillon 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 63841ab66cSSepherosa Ziehau static struct ieee80211_node *node_alloc(struct ieee80211_node_table *); 64841ab66cSSepherosa Ziehau static void node_cleanup(struct ieee80211_node *); 65841ab66cSSepherosa Ziehau static void node_free(struct ieee80211_node *); 66841ab66cSSepherosa Ziehau static uint8_t node_getrssi(const struct ieee80211_node *); 67f186073cSJoerg Sonnenberger 68841ab66cSSepherosa Ziehau static void ieee80211_setup_node(struct ieee80211_node_table *, 69841ab66cSSepherosa Ziehau struct ieee80211_node *, const uint8_t *); 70841ab66cSSepherosa Ziehau static void _ieee80211_free_node(struct ieee80211_node *); 71841ab66cSSepherosa Ziehau static void ieee80211_free_allnodes(struct ieee80211_node_table *); 72841ab66cSSepherosa Ziehau 73841ab66cSSepherosa Ziehau static void ieee80211_timeout_scan_candidates(struct ieee80211_node_table *); 74841ab66cSSepherosa Ziehau static void ieee80211_timeout_stations(struct ieee80211_node_table *); 75841ab66cSSepherosa Ziehau 76841ab66cSSepherosa Ziehau static void ieee80211_set_tim(struct ieee80211_node *, int set); 77841ab66cSSepherosa Ziehau 78841ab66cSSepherosa Ziehau static void ieee80211_node_table_init(struct ieee80211com *ic, 79841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, const char *name, 80841ab66cSSepherosa Ziehau int inact, int keyixmax, 81841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)); 82841ab66cSSepherosa Ziehau static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); 83f186073cSJoerg Sonnenberger 84f186073cSJoerg Sonnenberger MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); 85f186073cSJoerg Sonnenberger 86f186073cSJoerg Sonnenberger void 87841ab66cSSepherosa Ziehau ieee80211_node_attach(struct ieee80211com *ic) 88f186073cSJoerg Sonnenberger { 89841ab66cSSepherosa Ziehau ic->ic_node_alloc = node_alloc; 90841ab66cSSepherosa Ziehau ic->ic_node_free = node_free; 91841ab66cSSepherosa Ziehau ic->ic_node_cleanup = node_cleanup; 92841ab66cSSepherosa Ziehau ic->ic_node_getrssi = node_getrssi; 93f186073cSJoerg Sonnenberger 94841ab66cSSepherosa Ziehau /* default station inactivity timer setings */ 95841ab66cSSepherosa Ziehau ic->ic_inact_init = IEEE80211_INACT_INIT; 96841ab66cSSepherosa Ziehau ic->ic_inact_auth = IEEE80211_INACT_AUTH; 97841ab66cSSepherosa Ziehau ic->ic_inact_run = IEEE80211_INACT_RUN; 98841ab66cSSepherosa Ziehau ic->ic_inact_probe = IEEE80211_INACT_PROBE; 99841ab66cSSepherosa Ziehau 100841ab66cSSepherosa Ziehau /* NB: driver should override */ 101841ab66cSSepherosa Ziehau ic->ic_max_aid = IEEE80211_AID_DEF; 102841ab66cSSepherosa Ziehau ic->ic_set_tim = ieee80211_set_tim; 103f186073cSJoerg Sonnenberger } 104f186073cSJoerg Sonnenberger 105f186073cSJoerg Sonnenberger void 106841ab66cSSepherosa Ziehau ieee80211_node_lateattach(struct ieee80211com *ic) 107f186073cSJoerg Sonnenberger { 108841ab66cSSepherosa Ziehau struct ieee80211_rsnparms *rsn; 109f186073cSJoerg Sonnenberger 110841ab66cSSepherosa Ziehau if (ic->ic_max_aid > IEEE80211_AID_MAX) 111841ab66cSSepherosa Ziehau ic->ic_max_aid = IEEE80211_AID_MAX; 112841ab66cSSepherosa Ziehau 113841ab66cSSepherosa Ziehau ic->ic_aid_bitmap = 114*77652cadSMatthew Dillon kmalloc(howmany(ic->ic_max_aid, 32) * sizeof(uint32_t), 115841ab66cSSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 116841ab66cSSepherosa Ziehau 117841ab66cSSepherosa Ziehau /* XXX defer until using hostap/ibss mode */ 118841ab66cSSepherosa Ziehau ic->ic_tim_len = howmany(ic->ic_max_aid, 8) * sizeof(uint8_t); 119efda3bd0SMatthew Dillon ic->ic_tim_bitmap = kmalloc(ic->ic_tim_len, M_DEVBUF, 120841ab66cSSepherosa Ziehau M_WAITOK | M_ZERO); 121841ab66cSSepherosa Ziehau 122841ab66cSSepherosa Ziehau ieee80211_node_table_init(ic, &ic->ic_sta, "station", 123841ab66cSSepherosa Ziehau IEEE80211_INACT_INIT, ic->ic_crypto.cs_max_keyix, 124841ab66cSSepherosa Ziehau ieee80211_timeout_stations); 125841ab66cSSepherosa Ziehau ieee80211_node_table_init(ic, &ic->ic_scan, "scan", 126841ab66cSSepherosa Ziehau IEEE80211_INACT_SCAN, 0, 127841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates); 128841ab66cSSepherosa Ziehau 129841ab66cSSepherosa Ziehau ieee80211_reset_bss(ic); 130841ab66cSSepherosa Ziehau /* 131841ab66cSSepherosa Ziehau * Setup "global settings" in the bss node so that 132841ab66cSSepherosa Ziehau * each new station automatically inherits them. 133841ab66cSSepherosa Ziehau */ 134841ab66cSSepherosa Ziehau rsn = &ic->ic_bss->ni_rsn; 135841ab66cSSepherosa Ziehau /* WEP, TKIP, and AES-CCM are always supported */ 136841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_WEP; 137841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_TKIP; 138841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_CCM; 139841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_AES) 140841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_AES_OCB; 141841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_CKIP) 142841ab66cSSepherosa Ziehau rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_CKIP; 143841ab66cSSepherosa Ziehau /* 144841ab66cSSepherosa Ziehau * Default unicast cipher to WEP for 802.1x use. If 145841ab66cSSepherosa Ziehau * WPA is enabled the management code will set these 146841ab66cSSepherosa Ziehau * values to reflect. 147841ab66cSSepherosa Ziehau */ 148841ab66cSSepherosa Ziehau rsn->rsn_ucastcipher = IEEE80211_CIPHER_WEP; 149841ab66cSSepherosa Ziehau rsn->rsn_ucastkeylen = 104 / NBBY; 150841ab66cSSepherosa Ziehau /* 151841ab66cSSepherosa Ziehau * WPA says the multicast cipher is the lowest unicast 152841ab66cSSepherosa Ziehau * cipher supported. But we skip WEP which would 153841ab66cSSepherosa Ziehau * otherwise be used based on this criteria. 154841ab66cSSepherosa Ziehau */ 155841ab66cSSepherosa Ziehau rsn->rsn_mcastcipher = IEEE80211_CIPHER_TKIP; 156841ab66cSSepherosa Ziehau rsn->rsn_mcastkeylen = 128 / NBBY; 157841ab66cSSepherosa Ziehau 158841ab66cSSepherosa Ziehau /* 159841ab66cSSepherosa Ziehau * We support both WPA-PSK and 802.1x; the one used 160841ab66cSSepherosa Ziehau * is determined by the authentication mode and the 161841ab66cSSepherosa Ziehau * setting of the PSK state. 162841ab66cSSepherosa Ziehau */ 163841ab66cSSepherosa Ziehau rsn->rsn_keymgmtset = WPA_ASE_8021X_UNSPEC | WPA_ASE_8021X_PSK; 164841ab66cSSepherosa Ziehau rsn->rsn_keymgmt = WPA_ASE_8021X_PSK; 165841ab66cSSepherosa Ziehau 166841ab66cSSepherosa Ziehau ic->ic_auth = ieee80211_authenticator_get(ic->ic_bss->ni_authmode); 167f186073cSJoerg Sonnenberger } 168f186073cSJoerg Sonnenberger 169f186073cSJoerg Sonnenberger void 170841ab66cSSepherosa Ziehau ieee80211_node_detach(struct ieee80211com *ic) 171f186073cSJoerg Sonnenberger { 172841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) { 173841ab66cSSepherosa Ziehau ieee80211_free_node(ic->ic_bss); 174841ab66cSSepherosa Ziehau ic->ic_bss = NULL; 175841ab66cSSepherosa Ziehau } 176841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_scan); 177841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(&ic->ic_sta); 178841ab66cSSepherosa Ziehau if (ic->ic_aid_bitmap != NULL) { 179efda3bd0SMatthew Dillon kfree(ic->ic_aid_bitmap, M_DEVBUF); 180841ab66cSSepherosa Ziehau ic->ic_aid_bitmap = NULL; 181841ab66cSSepherosa Ziehau } 182841ab66cSSepherosa Ziehau if (ic->ic_tim_bitmap != NULL) { 183efda3bd0SMatthew Dillon kfree(ic->ic_tim_bitmap, M_DEVBUF); 184841ab66cSSepherosa Ziehau ic->ic_tim_bitmap = NULL; 185841ab66cSSepherosa Ziehau } 186841ab66cSSepherosa Ziehau } 187f186073cSJoerg Sonnenberger 188841ab66cSSepherosa Ziehau /* 189841ab66cSSepherosa Ziehau * Port authorize/unauthorize interfaces for use by an authenticator. 190841ab66cSSepherosa Ziehau */ 191841ab66cSSepherosa Ziehau 192841ab66cSSepherosa Ziehau void 193841ab66cSSepherosa Ziehau ieee80211_node_authorize(struct ieee80211_node *ni) 194841ab66cSSepherosa Ziehau { 195841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 196841ab66cSSepherosa Ziehau 197841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_AUTH; 198841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_run; 199841ab66cSSepherosa Ziehau } 200841ab66cSSepherosa Ziehau 201841ab66cSSepherosa Ziehau void 202841ab66cSSepherosa Ziehau ieee80211_node_unauthorize(struct ieee80211_node *ni) 203841ab66cSSepherosa Ziehau { 204841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AUTH; 205841ab66cSSepherosa Ziehau } 206841ab66cSSepherosa Ziehau 207841ab66cSSepherosa Ziehau /* 208841ab66cSSepherosa Ziehau * Set/change the channel. The rate set is also updated as 209841ab66cSSepherosa Ziehau * to insure a consistent view by drivers. 210841ab66cSSepherosa Ziehau */ 211841ab66cSSepherosa Ziehau static void 212841ab66cSSepherosa Ziehau ieee80211_set_chan(struct ieee80211com *ic, 213841ab66cSSepherosa Ziehau struct ieee80211_node *ni, struct ieee80211_channel *chan) 214841ab66cSSepherosa Ziehau { 215841ab66cSSepherosa Ziehau if (chan == IEEE80211_CHAN_ANYC) /* XXX while scanning */ 216841ab66cSSepherosa Ziehau chan = ic->ic_curchan; 217841ab66cSSepherosa Ziehau ni->ni_chan = chan; 218841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 219f186073cSJoerg Sonnenberger } 220f186073cSJoerg Sonnenberger 221f186073cSJoerg Sonnenberger /* 222f186073cSJoerg Sonnenberger * AP scanning support. 223f186073cSJoerg Sonnenberger */ 224f186073cSJoerg Sonnenberger 225841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 226841ab66cSSepherosa Ziehau static void 227841ab66cSSepherosa Ziehau dump_chanlist(const u_char chans[]) 228841ab66cSSepherosa Ziehau { 229841ab66cSSepherosa Ziehau const char *sep; 230841ab66cSSepherosa Ziehau int i; 231841ab66cSSepherosa Ziehau 232841ab66cSSepherosa Ziehau sep = " "; 233841ab66cSSepherosa Ziehau for (i = 0; i < IEEE80211_CHAN_MAX; i++) 234841ab66cSSepherosa Ziehau if (isset(chans, i)) { 235841ab66cSSepherosa Ziehau printf("%s%u", sep, i); 236841ab66cSSepherosa Ziehau sep = ", "; 237841ab66cSSepherosa Ziehau } 238841ab66cSSepherosa Ziehau } 239841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 240841ab66cSSepherosa Ziehau 241f186073cSJoerg Sonnenberger /* 242841ab66cSSepherosa Ziehau * Initialize the channel set to scan based on the 243f186073cSJoerg Sonnenberger * of available channels and the current PHY mode. 244f186073cSJoerg Sonnenberger */ 245f186073cSJoerg Sonnenberger static void 246841ab66cSSepherosa Ziehau ieee80211_reset_scan(struct ieee80211com *ic) 247f186073cSJoerg Sonnenberger { 248f186073cSJoerg Sonnenberger 249841ab66cSSepherosa Ziehau /* XXX ic_des_chan should be handled with ic_chan_active */ 250841ab66cSSepherosa Ziehau if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 251841ab66cSSepherosa Ziehau memset(ic->ic_chan_scan, 0, sizeof(ic->ic_chan_scan)); 252841ab66cSSepherosa Ziehau setbit(ic->ic_chan_scan, 253841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_des_chan)); 254841ab66cSSepherosa Ziehau } else 255f186073cSJoerg Sonnenberger memcpy(ic->ic_chan_scan, ic->ic_chan_active, 256f186073cSJoerg Sonnenberger sizeof(ic->ic_chan_active)); 257841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 258841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 259841ab66cSSepherosa Ziehau printf("%s: scan set:", __func__); 260841ab66cSSepherosa Ziehau dump_chanlist(ic->ic_chan_scan); 261841ab66cSSepherosa Ziehau printf(" start chan %u\n", 262841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan)); 263841ab66cSSepherosa Ziehau } 264841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 265f186073cSJoerg Sonnenberger } 266f186073cSJoerg Sonnenberger 267f186073cSJoerg Sonnenberger /* 268f186073cSJoerg Sonnenberger * Begin an active scan. 269f186073cSJoerg Sonnenberger */ 270f186073cSJoerg Sonnenberger void 271841ab66cSSepherosa Ziehau ieee80211_begin_scan(struct ieee80211com *ic, int reset) 272f186073cSJoerg Sonnenberger { 273841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 274f186073cSJoerg Sonnenberger 275f186073cSJoerg Sonnenberger /* 276f186073cSJoerg Sonnenberger * In all but hostap mode scanning starts off in 277f186073cSJoerg Sonnenberger * an active mode before switching to passive. 278f186073cSJoerg Sonnenberger */ 279f186073cSJoerg Sonnenberger if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 280f186073cSJoerg Sonnenberger ic->ic_flags |= IEEE80211_F_ASCAN; 281f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_active++; 282f186073cSJoerg Sonnenberger } else 283f186073cSJoerg Sonnenberger ic->ic_stats.is_scan_passive++; 284841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 285841ab66cSSepherosa Ziehau "begin %s scan in %s mode\n", 286841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive", 287841ab66cSSepherosa Ziehau ieee80211_phymode_name[ic->ic_curmode]); 288f186073cSJoerg Sonnenberger /* 289841ab66cSSepherosa Ziehau * Clear scan state and flush any previously seen AP's. 290f186073cSJoerg Sonnenberger */ 291841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 292841ab66cSSepherosa Ziehau if (reset) 293841ab66cSSepherosa Ziehau ieee80211_free_allnodes(&ic->ic_scan); 294841ab66cSSepherosa Ziehau 295841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 296f186073cSJoerg Sonnenberger 297f186073cSJoerg Sonnenberger /* Scan the next channel. */ 298841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 299f186073cSJoerg Sonnenberger } 300f186073cSJoerg Sonnenberger 301f186073cSJoerg Sonnenberger /* 302f186073cSJoerg Sonnenberger * Switch to the next channel marked for scanning. 303f186073cSJoerg Sonnenberger */ 304841ab66cSSepherosa Ziehau int 305841ab66cSSepherosa Ziehau ieee80211_next_scan(struct ieee80211com *ic) 306f186073cSJoerg Sonnenberger { 307f186073cSJoerg Sonnenberger struct ieee80211_channel *chan; 308f186073cSJoerg Sonnenberger 309841ab66cSSepherosa Ziehau /* 310841ab66cSSepherosa Ziehau * Insure any previous mgt frame timeouts don't fire. 311841ab66cSSepherosa Ziehau * This assumes the driver does the right thing in 312841ab66cSSepherosa Ziehau * flushing anything queued in the driver and below. 313841ab66cSSepherosa Ziehau */ 314841ab66cSSepherosa Ziehau ic->ic_mgt_timer = 0; 315841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 316841ab66cSSepherosa Ziehau 317841ab66cSSepherosa Ziehau chan = ic->ic_curchan; 318841ab66cSSepherosa Ziehau do { 319f186073cSJoerg Sonnenberger if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) 320f186073cSJoerg Sonnenberger chan = &ic->ic_channels[0]; 321f186073cSJoerg Sonnenberger if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) { 322f186073cSJoerg Sonnenberger clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); 323841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 324841ab66cSSepherosa Ziehau "%s: chan %d->%d\n", __func__, 325841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 326841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, chan)); 327841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 328841ab66cSSepherosa Ziehau /* 329841ab66cSSepherosa Ziehau * XXX drivers should do this as needed, 330841ab66cSSepherosa Ziehau * XXX for now maintain compatibility 331841ab66cSSepherosa Ziehau */ 332841ab66cSSepherosa Ziehau ic->ic_bss->ni_rates = 333841ab66cSSepherosa Ziehau ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; 334f186073cSJoerg Sonnenberger ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 335841ab66cSSepherosa Ziehau return 1; 336841ab66cSSepherosa Ziehau } 337841ab66cSSepherosa Ziehau } while (chan != ic->ic_curchan); 338841ab66cSSepherosa Ziehau ieee80211_end_scan(ic); 339841ab66cSSepherosa Ziehau return 0; 340841ab66cSSepherosa Ziehau } 341841ab66cSSepherosa Ziehau 342841ab66cSSepherosa Ziehau /* 343841ab66cSSepherosa Ziehau * Probe the curent channel, if allowed, while scanning. 344841ab66cSSepherosa Ziehau * If the channel is not marked passive-only then send 345841ab66cSSepherosa Ziehau * a probe request immediately. Otherwise mark state and 346841ab66cSSepherosa Ziehau * listen for beacons on the channel; if we receive something 347841ab66cSSepherosa Ziehau * then we'll transmit a probe request. 348841ab66cSSepherosa Ziehau */ 349841ab66cSSepherosa Ziehau void 350841ab66cSSepherosa Ziehau ieee80211_probe_curchan(struct ieee80211com *ic, int force) 351841ab66cSSepherosa Ziehau { 352841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 353841ab66cSSepherosa Ziehau 354841ab66cSSepherosa Ziehau if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 || force) { 355841ab66cSSepherosa Ziehau /* 356841ab66cSSepherosa Ziehau * XXX send both broadcast+directed probe request 357841ab66cSSepherosa Ziehau */ 358841ab66cSSepherosa Ziehau ieee80211_send_probereq(ic->ic_bss, 359841ab66cSSepherosa Ziehau ic->ic_myaddr, ifp->if_broadcastaddr, 360841ab66cSSepherosa Ziehau ifp->if_broadcastaddr, 361841ab66cSSepherosa Ziehau ic->ic_des_essid, ic->ic_des_esslen, 362841ab66cSSepherosa Ziehau ic->ic_opt_ie, ic->ic_opt_ie_len); 363841ab66cSSepherosa Ziehau } else 364841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN; 365841ab66cSSepherosa Ziehau } 366841ab66cSSepherosa Ziehau 367841ab66cSSepherosa Ziehau static __inline void 368841ab66cSSepherosa Ziehau copy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss) 369841ab66cSSepherosa Ziehau { 370841ab66cSSepherosa Ziehau /* propagate useful state */ 371841ab66cSSepherosa Ziehau nbss->ni_authmode = obss->ni_authmode; 372841ab66cSSepherosa Ziehau nbss->ni_txpower = obss->ni_txpower; 373841ab66cSSepherosa Ziehau nbss->ni_vlan = obss->ni_vlan; 374841ab66cSSepherosa Ziehau nbss->ni_rsn = obss->ni_rsn; 375b9334f94SSepherosa Ziehau ieee80211_ratectl_data_dup(obss, nbss); 376841ab66cSSepherosa Ziehau /* XXX statistics? */ 377f186073cSJoerg Sonnenberger } 378f186073cSJoerg Sonnenberger 379f186073cSJoerg Sonnenberger void 380f186073cSJoerg Sonnenberger ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) 381f186073cSJoerg Sonnenberger { 382841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 383f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 384f186073cSJoerg Sonnenberger 385841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 386841ab66cSSepherosa Ziehau 387841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 388841ab66cSSepherosa Ziehau "%s: creating ibss\n", __func__); 389841ab66cSSepherosa Ziehau 390841ab66cSSepherosa Ziehau /* 391841ab66cSSepherosa Ziehau * Create the station/neighbor table. Note that for adhoc 392841ab66cSSepherosa Ziehau * mode we make the initial inactivity timer longer since 393841ab66cSSepherosa Ziehau * we create nodes only through discovery and they typically 394841ab66cSSepherosa Ziehau * are long-lived associations. 395841ab66cSSepherosa Ziehau */ 396841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 397841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 398841ab66cSSepherosa Ziehau nt->nt_name = "station"; 399841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_init; 400841ab66cSSepherosa Ziehau } else { 401841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 402841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 403841ab66cSSepherosa Ziehau } 404841ab66cSSepherosa Ziehau 405841ab66cSSepherosa Ziehau ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr); 406841ab66cSSepherosa Ziehau if (ni == NULL) { 407841ab66cSSepherosa Ziehau /* XXX recovery? */ 408841ab66cSSepherosa Ziehau return; 409841ab66cSSepherosa Ziehau } 410f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); 411f186073cSJoerg Sonnenberger ni->ni_esslen = ic->ic_des_esslen; 412f186073cSJoerg Sonnenberger memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); 413841ab66cSSepherosa Ziehau copy_bss(ni, ic->ic_bss); 414841ab66cSSepherosa Ziehau ni->ni_intval = ic->ic_bintval; 415841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) 416f186073cSJoerg Sonnenberger ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; 417f186073cSJoerg Sonnenberger if (ic->ic_phytype == IEEE80211_T_FH) { 418f186073cSJoerg Sonnenberger ni->ni_fhdwell = 200; /* XXX */ 419f186073cSJoerg Sonnenberger ni->ni_fhindex = 1; 420f186073cSJoerg Sonnenberger } 421841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS) { 422841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SIBSS; 423841ab66cSSepherosa Ziehau ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */ 424841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 425841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 426841ab66cSSepherosa Ziehau else 427841ab66cSSepherosa Ziehau ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ 428841ab66cSSepherosa Ziehau } else if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 429841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DESBSSID) 430841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); 431841ab66cSSepherosa Ziehau else 432841ab66cSSepherosa Ziehau memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); 433841ab66cSSepherosa Ziehau } 434841ab66cSSepherosa Ziehau /* 435841ab66cSSepherosa Ziehau * Fix the channel and related attributes. 436841ab66cSSepherosa Ziehau */ 437841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, chan); 438841ab66cSSepherosa Ziehau ic->ic_curchan = chan; 439841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, chan); 440841ab66cSSepherosa Ziehau /* 441841ab66cSSepherosa Ziehau * Do mode-specific rate setup. 442841ab66cSSepherosa Ziehau */ 443841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) { 444841ab66cSSepherosa Ziehau /* 445841ab66cSSepherosa Ziehau * Use a mixed 11b/11g rate set. 446841ab66cSSepherosa Ziehau */ 447841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11G); 448841ab66cSSepherosa Ziehau } else if (ic->ic_curmode == IEEE80211_MODE_11B) { 449841ab66cSSepherosa Ziehau /* 450841ab66cSSepherosa Ziehau * Force pure 11b rate set. 451841ab66cSSepherosa Ziehau */ 452841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11B); 453f186073cSJoerg Sonnenberger } 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 } 475841ab66cSSepherosa Ziehau } 476841ab66cSSepherosa Ziehau 477841ab66cSSepherosa Ziehau /* XXX tunable */ 478841ab66cSSepherosa Ziehau #define STA_FAILS_MAX 2 /* assoc failures before ignored */ 479841ab66cSSepherosa Ziehau 480841ab66cSSepherosa Ziehau static int 481841ab66cSSepherosa Ziehau ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) 482841ab66cSSepherosa Ziehau { 483f186073cSJoerg Sonnenberger uint8_t rate; 484f186073cSJoerg Sonnenberger int fail; 485f186073cSJoerg Sonnenberger 486f186073cSJoerg Sonnenberger fail = 0; 487f186073cSJoerg Sonnenberger if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) 488f186073cSJoerg Sonnenberger fail |= 0x01; 489f186073cSJoerg Sonnenberger if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 490f186073cSJoerg Sonnenberger ni->ni_chan != ic->ic_des_chan) 491f186073cSJoerg Sonnenberger fail |= 0x01; 492f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 493f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) 494f186073cSJoerg Sonnenberger fail |= 0x02; 495f186073cSJoerg Sonnenberger } else { 496f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) 497f186073cSJoerg Sonnenberger fail |= 0x02; 498f186073cSJoerg Sonnenberger } 499841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_PRIVACY) { 500f186073cSJoerg Sonnenberger if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 501f186073cSJoerg Sonnenberger fail |= 0x04; 502f186073cSJoerg Sonnenberger } else { 503f186073cSJoerg Sonnenberger /* XXX does this mean privacy is supported or required? */ 504f186073cSJoerg Sonnenberger if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) 505f186073cSJoerg Sonnenberger fail |= 0x04; 506f186073cSJoerg Sonnenberger } 507841ab66cSSepherosa Ziehau rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); 508f186073cSJoerg Sonnenberger if (rate & IEEE80211_RATE_BASIC) 509f186073cSJoerg Sonnenberger fail |= 0x08; 510f186073cSJoerg Sonnenberger if (ic->ic_des_esslen != 0 && 511f186073cSJoerg Sonnenberger (ni->ni_esslen != ic->ic_des_esslen || 512f186073cSJoerg Sonnenberger memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) 513f186073cSJoerg Sonnenberger fail |= 0x10; 514f186073cSJoerg Sonnenberger if ((ic->ic_flags & IEEE80211_F_DESBSSID) && 515f186073cSJoerg Sonnenberger !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) 516f186073cSJoerg Sonnenberger fail |= 0x20; 517841ab66cSSepherosa Ziehau if (ni->ni_fails >= STA_FAILS_MAX) 518841ab66cSSepherosa Ziehau fail |= 0x40; 519f186073cSJoerg Sonnenberger #ifdef IEEE80211_DEBUG 520841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic)) { 521841ab66cSSepherosa Ziehau printf(" %c %6D", 522841ab66cSSepherosa Ziehau fail & 0x40 ? '=' : fail & 0x80 ? '^' : fail ? '-' : '+', 523841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 524841ab66cSSepherosa Ziehau printf(" %6D%c", ni->ni_bssid, ":", 525841ab66cSSepherosa Ziehau fail & 0x20 ? '!' : ' '); 526f186073cSJoerg Sonnenberger printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), 527f186073cSJoerg Sonnenberger fail & 0x01 ? '!' : ' '); 528f186073cSJoerg Sonnenberger printf(" %+4d", ni->ni_rssi); 529f186073cSJoerg Sonnenberger printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, 530f186073cSJoerg Sonnenberger fail & 0x08 ? '!' : ' '); 531f186073cSJoerg Sonnenberger printf(" %4s%c", 532f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : 533f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : 534f186073cSJoerg Sonnenberger "????", 535f186073cSJoerg Sonnenberger fail & 0x02 ? '!' : ' '); 536f186073cSJoerg Sonnenberger printf(" %3s%c ", 537f186073cSJoerg Sonnenberger (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? 538f186073cSJoerg Sonnenberger "wep" : "no", 539f186073cSJoerg Sonnenberger fail & 0x04 ? '!' : ' '); 540f186073cSJoerg Sonnenberger ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 541f186073cSJoerg Sonnenberger printf("%s\n", fail & 0x10 ? "!" : ""); 542f186073cSJoerg Sonnenberger } 543f186073cSJoerg Sonnenberger #endif 544f186073cSJoerg Sonnenberger return fail; 545f186073cSJoerg Sonnenberger } 546f186073cSJoerg Sonnenberger 547841ab66cSSepherosa Ziehau static __inline uint8_t 548841ab66cSSepherosa Ziehau maxrate(const struct ieee80211_node *ni) 549841ab66cSSepherosa Ziehau { 550841ab66cSSepherosa Ziehau const struct ieee80211_rateset *rs = &ni->ni_rates; 551841ab66cSSepherosa Ziehau /* NB: assumes rate set is sorted (happens on frame receive) */ 552841ab66cSSepherosa Ziehau return rs->rs_rates[rs->rs_nrates-1] & IEEE80211_RATE_VAL; 553841ab66cSSepherosa Ziehau } 554841ab66cSSepherosa Ziehau 555841ab66cSSepherosa Ziehau /* 556841ab66cSSepherosa Ziehau * Compare the capabilities of two nodes and decide which is 557841ab66cSSepherosa Ziehau * more desirable (return >0 if a is considered better). Note 558841ab66cSSepherosa Ziehau * that we assume compatibility/usability has already been checked 559841ab66cSSepherosa Ziehau * so we don't need to (e.g. validate whether privacy is supported). 560841ab66cSSepherosa Ziehau * Used to select the best scan candidate for association in a BSS. 561841ab66cSSepherosa Ziehau */ 562841ab66cSSepherosa Ziehau static int 563841ab66cSSepherosa Ziehau ieee80211_node_compare(struct ieee80211com *ic, 564841ab66cSSepherosa Ziehau const struct ieee80211_node *a, 565841ab66cSSepherosa Ziehau const struct ieee80211_node *b) 566841ab66cSSepherosa Ziehau { 567841ab66cSSepherosa Ziehau #define ABS(a) ((a) < 0 ? -(a) : (a)) 568841ab66cSSepherosa Ziehau uint8_t maxa, maxb; 569841ab66cSSepherosa Ziehau uint8_t rssia, rssib; 570841ab66cSSepherosa Ziehau int weight; 571841ab66cSSepherosa Ziehau 572841ab66cSSepherosa Ziehau /* privacy support preferred */ 573841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) && 574841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) 575841ab66cSSepherosa Ziehau return 1; 576841ab66cSSepherosa Ziehau if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0 && 577841ab66cSSepherosa Ziehau (b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)) 578841ab66cSSepherosa Ziehau return -1; 579841ab66cSSepherosa Ziehau 580841ab66cSSepherosa Ziehau /* compare count of previous failures */ 581841ab66cSSepherosa Ziehau weight = b->ni_fails - a->ni_fails; 582841ab66cSSepherosa Ziehau if (ABS(weight) > 1) 583841ab66cSSepherosa Ziehau return weight; 584841ab66cSSepherosa Ziehau 585841ab66cSSepherosa Ziehau rssia = ic->ic_node_getrssi(a); 586841ab66cSSepherosa Ziehau rssib = ic->ic_node_getrssi(b); 587841ab66cSSepherosa Ziehau if (ABS(rssib - rssia) < 5) { 588841ab66cSSepherosa Ziehau /* best/max rate preferred if signal level close enough XXX */ 589841ab66cSSepherosa Ziehau maxa = maxrate(a); 590841ab66cSSepherosa Ziehau maxb = maxrate(b); 591841ab66cSSepherosa Ziehau if (maxa != maxb) 592841ab66cSSepherosa Ziehau return maxa - maxb; 593841ab66cSSepherosa Ziehau /* XXX use freq for channel preference */ 594841ab66cSSepherosa Ziehau /* for now just prefer 5Ghz band to all other bands */ 595841ab66cSSepherosa Ziehau if (IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 596841ab66cSSepherosa Ziehau !IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 597841ab66cSSepherosa Ziehau return 1; 598841ab66cSSepherosa Ziehau if (!IEEE80211_IS_CHAN_5GHZ(a->ni_chan) && 599841ab66cSSepherosa Ziehau IEEE80211_IS_CHAN_5GHZ(b->ni_chan)) 600841ab66cSSepherosa Ziehau return -1; 601841ab66cSSepherosa Ziehau } 602841ab66cSSepherosa Ziehau /* all things being equal, use signal level */ 603841ab66cSSepherosa Ziehau return rssia - rssib; 604841ab66cSSepherosa Ziehau #undef ABS 605841ab66cSSepherosa Ziehau } 606841ab66cSSepherosa Ziehau 607841ab66cSSepherosa Ziehau /* 608841ab66cSSepherosa Ziehau * Mark an ongoing scan stopped. 609841ab66cSSepherosa Ziehau */ 610841ab66cSSepherosa Ziehau void 611841ab66cSSepherosa Ziehau ieee80211_cancel_scan(struct ieee80211com *ic) 612841ab66cSSepherosa Ziehau { 613841ab66cSSepherosa Ziehau 614841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s: end %s scan\n", 615841ab66cSSepherosa Ziehau __func__, 616841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); 617841ab66cSSepherosa Ziehau 618841ab66cSSepherosa Ziehau ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN); 619841ab66cSSepherosa Ziehau ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 620841ab66cSSepherosa Ziehau } 621841ab66cSSepherosa Ziehau 622f186073cSJoerg Sonnenberger /* 623f186073cSJoerg Sonnenberger * Complete a scan of potential channels. 624f186073cSJoerg Sonnenberger */ 625f186073cSJoerg Sonnenberger void 626841ab66cSSepherosa Ziehau ieee80211_end_scan(struct ieee80211com *ic) 627f186073cSJoerg Sonnenberger { 628841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 629841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *selbs; 630f186073cSJoerg Sonnenberger 631841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 632841ab66cSSepherosa Ziehau 633841ab66cSSepherosa Ziehau ieee80211_cancel_scan(ic); 634841ab66cSSepherosa Ziehau ieee80211_notify_scan_done(ic); 635f186073cSJoerg Sonnenberger 636f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 637841ab66cSSepherosa Ziehau uint8_t maxrssi[IEEE80211_CHAN_MAX]; /* XXX off stack? */ 638841ab66cSSepherosa Ziehau int i, bestchan; 639841ab66cSSepherosa Ziehau uint8_t rssi; 640841ab66cSSepherosa Ziehau 641f186073cSJoerg Sonnenberger /* 642f186073cSJoerg Sonnenberger * The passive scan to look for existing AP's completed, 643f186073cSJoerg Sonnenberger * select a channel to camp on. Identify the channels 644f186073cSJoerg Sonnenberger * that already have one or more AP's and try to locate 645841ab66cSSepherosa Ziehau * an unoccupied one. If that fails, pick a channel that 646841ab66cSSepherosa Ziehau * looks to be quietest. 647f186073cSJoerg Sonnenberger */ 648841ab66cSSepherosa Ziehau memset(maxrssi, 0, sizeof(maxrssi)); 649841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 650841ab66cSSepherosa Ziehau rssi = ic->ic_node_getrssi(ni); 651841ab66cSSepherosa Ziehau i = ieee80211_chan2ieee(ic, ni->ni_chan); 652841ab66cSSepherosa Ziehau if (rssi > maxrssi[i]) 653841ab66cSSepherosa Ziehau maxrssi[i] = rssi; 654f186073cSJoerg Sonnenberger } 655841ab66cSSepherosa Ziehau /* XXX select channel more intelligently */ 656841ab66cSSepherosa Ziehau bestchan = -1; 657f186073cSJoerg Sonnenberger for (i = 0; i < IEEE80211_CHAN_MAX; i++) 658841ab66cSSepherosa Ziehau if (isset(ic->ic_chan_active, i)) { 659841ab66cSSepherosa Ziehau /* 660841ab66cSSepherosa Ziehau * If the channel is unoccupied the max rssi 661841ab66cSSepherosa Ziehau * should be zero; just take it. Otherwise 662841ab66cSSepherosa Ziehau * track the channel with the lowest rssi and 663841ab66cSSepherosa Ziehau * use that when all channels appear occupied. 664841ab66cSSepherosa Ziehau */ 665841ab66cSSepherosa Ziehau if (maxrssi[i] == 0) { 666841ab66cSSepherosa Ziehau bestchan = i; 667f186073cSJoerg Sonnenberger break; 668f186073cSJoerg Sonnenberger } 669841ab66cSSepherosa Ziehau if (bestchan == -1 || 670841ab66cSSepherosa Ziehau maxrssi[i] < maxrssi[bestchan]) 671841ab66cSSepherosa Ziehau bestchan = i; 672841ab66cSSepherosa Ziehau } 673841ab66cSSepherosa Ziehau if (bestchan != -1) { 674841ab66cSSepherosa Ziehau ieee80211_create_ibss(ic, &ic->ic_channels[bestchan]); 675f186073cSJoerg Sonnenberger return; 676f186073cSJoerg Sonnenberger } 677841ab66cSSepherosa Ziehau /* no suitable channel, should not happen */ 678841ab66cSSepherosa Ziehau } 679841ab66cSSepherosa Ziehau 680841ab66cSSepherosa Ziehau /* 681841ab66cSSepherosa Ziehau * When manually sequencing the state machine; scan just once 682841ab66cSSepherosa Ziehau * regardless of whether we have a candidate or not. The 683841ab66cSSepherosa Ziehau * controlling application is expected to setup state and 684841ab66cSSepherosa Ziehau * initiate an association. 685841ab66cSSepherosa Ziehau */ 686841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_MANUAL) 687841ab66cSSepherosa Ziehau return; 688841ab66cSSepherosa Ziehau /* 689841ab66cSSepherosa Ziehau * Automatic sequencing; look for a candidate and 690841ab66cSSepherosa Ziehau * if found join the network. 691841ab66cSSepherosa Ziehau */ 692841ab66cSSepherosa Ziehau /* NB: unlocked read should be ok */ 693841ab66cSSepherosa Ziehau if (TAILQ_FIRST(&nt->nt_node) == NULL) { 694841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 695841ab66cSSepherosa Ziehau "%s: no scan candidate\n", __func__); 696f186073cSJoerg Sonnenberger notfound: 697f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS && 698f186073cSJoerg Sonnenberger (ic->ic_flags & IEEE80211_F_IBSSON) && 699f186073cSJoerg Sonnenberger ic->ic_des_esslen != 0) { 700f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_ibss_chan); 701f186073cSJoerg Sonnenberger return; 702f186073cSJoerg Sonnenberger } 703f186073cSJoerg Sonnenberger /* 704841ab66cSSepherosa Ziehau * Decrement the failure counts so entries will be 705841ab66cSSepherosa Ziehau * reconsidered the next time around. We really want 706841ab66cSSepherosa Ziehau * to do this only for sta's where we've previously 707841ab66cSSepherosa Ziehau * had some success. 708841ab66cSSepherosa Ziehau */ 709841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 710841ab66cSSepherosa Ziehau if (ni->ni_fails) 711841ab66cSSepherosa Ziehau ni->ni_fails--; 712841ab66cSSepherosa Ziehau /* 713f186073cSJoerg Sonnenberger * Reset the list of channels to scan and start again. 714f186073cSJoerg Sonnenberger */ 715841ab66cSSepherosa Ziehau ieee80211_reset_scan(ic); 716841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SCAN; 717841ab66cSSepherosa Ziehau ieee80211_next_scan(ic); 718f186073cSJoerg Sonnenberger return; 719f186073cSJoerg Sonnenberger } 720f186073cSJoerg Sonnenberger selbs = NULL; 721841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "\t%s\n", 722841ab66cSSepherosa Ziehau "macaddr bssid chan rssi rate flag wep essid"); 723841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 724841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) == 0) { 725f186073cSJoerg Sonnenberger if (selbs == NULL) 726f186073cSJoerg Sonnenberger selbs = ni; 727841ab66cSSepherosa Ziehau else if (ieee80211_node_compare(ic, ni, selbs) > 0) 728f186073cSJoerg Sonnenberger selbs = ni; 729f186073cSJoerg Sonnenberger } 730f186073cSJoerg Sonnenberger } 731841ab66cSSepherosa Ziehau if (selbs != NULL) /* NB: grab ref while dropping lock */ 732841ab66cSSepherosa Ziehau ieee80211_ref_node(selbs); 733f186073cSJoerg Sonnenberger if (selbs == NULL) 734f186073cSJoerg Sonnenberger goto notfound; 735841ab66cSSepherosa Ziehau if (!ieee80211_sta_join(ic, selbs)) { 736841ab66cSSepherosa Ziehau ieee80211_free_node(selbs); 737841ab66cSSepherosa Ziehau goto notfound; 738841ab66cSSepherosa Ziehau } 739841ab66cSSepherosa Ziehau } 740841ab66cSSepherosa Ziehau 741841ab66cSSepherosa Ziehau /* 742841ab66cSSepherosa Ziehau * Handle 802.11 ad hoc network merge. The 743841ab66cSSepherosa Ziehau * convention, set by the Wireless Ethernet Compatibility Alliance 744841ab66cSSepherosa Ziehau * (WECA), is that an 802.11 station will change its BSSID to match 745841ab66cSSepherosa Ziehau * the "oldest" 802.11 ad hoc network, on the same channel, that 746841ab66cSSepherosa Ziehau * has the station's desired SSID. The "oldest" 802.11 network 747841ab66cSSepherosa Ziehau * sends beacons with the greatest TSF timestamp. 748841ab66cSSepherosa Ziehau * 749841ab66cSSepherosa Ziehau * The caller is assumed to validate TSF's before attempting a merge. 750841ab66cSSepherosa Ziehau * 751841ab66cSSepherosa Ziehau * Return !0 if the BSSID changed, 0 otherwise. 752841ab66cSSepherosa Ziehau */ 753841ab66cSSepherosa Ziehau int 754841ab66cSSepherosa Ziehau ieee80211_ibss_merge(struct ieee80211_node *ni) 755841ab66cSSepherosa Ziehau { 756841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 757841ab66cSSepherosa Ziehau 758841ab66cSSepherosa Ziehau if (ni == ic->ic_bss || 759841ab66cSSepherosa Ziehau IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { 760841ab66cSSepherosa Ziehau /* unchanged, nothing to do */ 761841ab66cSSepherosa Ziehau return 0; 762841ab66cSSepherosa Ziehau } 763841ab66cSSepherosa Ziehau if (ieee80211_match_bss(ic, ni) != 0) { /* capabilities mismatch */ 764841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 765841ab66cSSepherosa Ziehau "%s: merge failed, capabilities mismatch\n", __func__); 766841ab66cSSepherosa Ziehau ic->ic_stats.is_ibss_capmismatch++; 767841ab66cSSepherosa Ziehau return 0; 768841ab66cSSepherosa Ziehau } 769841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 770841ab66cSSepherosa Ziehau "%6D: new bssid %s: %s preamble, %s slot time%s\n", __func__, 771841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 772841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", 773841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", 774841ab66cSSepherosa Ziehau ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" 775841ab66cSSepherosa Ziehau ); 776841ab66cSSepherosa Ziehau return ieee80211_sta_join(ic, ieee80211_ref_node(ni)); 777841ab66cSSepherosa Ziehau } 778841ab66cSSepherosa Ziehau 779841ab66cSSepherosa Ziehau /* 780841ab66cSSepherosa Ziehau * Join the specified IBSS/BSS network. The node is assumed to 781841ab66cSSepherosa Ziehau * be passed in with a held reference. 782841ab66cSSepherosa Ziehau */ 783841ab66cSSepherosa Ziehau int 784841ab66cSSepherosa Ziehau ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) 785841ab66cSSepherosa Ziehau { 786841ab66cSSepherosa Ziehau struct ieee80211_node *obss; 787841ab66cSSepherosa Ziehau 788841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 789841ab66cSSepherosa Ziehau 790f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_IBSS) { 791841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 792f186073cSJoerg Sonnenberger /* 793841ab66cSSepherosa Ziehau * Delete unusable rates; we've already checked 794841ab66cSSepherosa Ziehau * that the negotiated rate set is acceptable. 795f186073cSJoerg Sonnenberger */ 796841ab66cSSepherosa Ziehau ieee80211_fix_rate(selbs, IEEE80211_F_DODEL); 797841ab66cSSepherosa Ziehau /* 798841ab66cSSepherosa Ziehau * Fillin the neighbor table; it will already 799841ab66cSSepherosa Ziehau * exist if we are simply switching mastership. 800841ab66cSSepherosa Ziehau * XXX ic_sta always setup so this is unnecessary? 801841ab66cSSepherosa Ziehau */ 802841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 803841ab66cSSepherosa Ziehau nt->nt_name = "neighbor"; 804841ab66cSSepherosa Ziehau nt->nt_inact_init = ic->ic_inact_run; 805f186073cSJoerg Sonnenberger } 806841ab66cSSepherosa Ziehau 807841ab66cSSepherosa Ziehau /* 808841ab66cSSepherosa Ziehau * Committed to selbs, setup state. 809841ab66cSSepherosa Ziehau */ 810841ab66cSSepherosa Ziehau obss = ic->ic_bss; 811841ab66cSSepherosa Ziehau ic->ic_bss = selbs; /* NB: caller assumed to bump refcnt */ 812841ab66cSSepherosa Ziehau if (obss != NULL) { 813841ab66cSSepherosa Ziehau copy_bss(selbs, obss); 814841ab66cSSepherosa Ziehau ieee80211_free_node(obss); 815841ab66cSSepherosa Ziehau } 816841ab66cSSepherosa Ziehau /* 817841ab66cSSepherosa Ziehau * Set the erp state (mostly the slot time) to deal with 818841ab66cSSepherosa Ziehau * the auto-select case; this should be redundant if the 819841ab66cSSepherosa Ziehau * mode is locked. 820841ab66cSSepherosa Ziehau */ 821841ab66cSSepherosa Ziehau ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan); 822841ab66cSSepherosa Ziehau ic->ic_curchan = selbs->ni_chan; 823841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 824841ab66cSSepherosa Ziehau ieee80211_wme_initparams(ic); 825841ab66cSSepherosa Ziehau 826841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA) 827841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 828841ab66cSSepherosa Ziehau else 829841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 830841ab66cSSepherosa Ziehau return 1; 831841ab66cSSepherosa Ziehau } 832841ab66cSSepherosa Ziehau 833841ab66cSSepherosa Ziehau /* 834841ab66cSSepherosa Ziehau * Leave the specified IBSS/BSS network. The node is assumed to 835841ab66cSSepherosa Ziehau * be passed in with a held reference. 836841ab66cSSepherosa Ziehau */ 837841ab66cSSepherosa Ziehau void 838841ab66cSSepherosa Ziehau ieee80211_sta_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 839841ab66cSSepherosa Ziehau { 840841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 841841ab66cSSepherosa Ziehau ieee80211_notify_node_leave(ic, ni); 842f186073cSJoerg Sonnenberger } 843f186073cSJoerg Sonnenberger 844f186073cSJoerg Sonnenberger static struct ieee80211_node * 845841ab66cSSepherosa Ziehau node_alloc(struct ieee80211_node_table *nt) 846f186073cSJoerg Sonnenberger { 847f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 848841ab66cSSepherosa Ziehau 849efda3bd0SMatthew Dillon ni = kmalloc(sizeof(struct ieee80211_node), M_80211_NODE, 850841ab66cSSepherosa Ziehau M_NOWAIT | M_ZERO); 851f186073cSJoerg Sonnenberger return ni; 852f186073cSJoerg Sonnenberger } 853f186073cSJoerg Sonnenberger 854841ab66cSSepherosa Ziehau /* 855841ab66cSSepherosa Ziehau * Reclaim any resources in a node and reset any critical 856841ab66cSSepherosa Ziehau * state. Typically nodes are free'd immediately after, 857841ab66cSSepherosa Ziehau * but in some cases the storage may be reused so we need 858841ab66cSSepherosa Ziehau * to insure consistent state (should probably fix that). 859841ab66cSSepherosa Ziehau */ 860f186073cSJoerg Sonnenberger static void 861841ab66cSSepherosa Ziehau node_cleanup(struct ieee80211_node *ni) 862f186073cSJoerg Sonnenberger { 863841ab66cSSepherosa Ziehau #define N(a) (sizeof(a)/sizeof(a[0])) 864841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 865841ab66cSSepherosa Ziehau int i, qlen; 866841ab66cSSepherosa Ziehau 867841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 868841ab66cSSepherosa Ziehau 869841ab66cSSepherosa Ziehau /* NB: preserve ni_table */ 870841ab66cSSepherosa Ziehau if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 871841ab66cSSepherosa Ziehau ic->ic_ps_sta--; 872841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 873841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, 874841ab66cSSepherosa Ziehau "[%6D] power save mode off, %u sta's in ps mode\n", 875841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_ps_sta); 876841ab66cSSepherosa Ziehau } 877841ab66cSSepherosa Ziehau /* 878841ab66cSSepherosa Ziehau * Clear AREF flag that marks the authorization refcnt bump 879841ab66cSSepherosa Ziehau * has happened. This is probably not needed as the node 880841ab66cSSepherosa Ziehau * should always be removed from the table so not found but 881841ab66cSSepherosa Ziehau * do it just in case. 882841ab66cSSepherosa Ziehau */ 883841ab66cSSepherosa Ziehau ni->ni_flags &= ~IEEE80211_NODE_AREF; 884841ab66cSSepherosa Ziehau 885841ab66cSSepherosa Ziehau /* 886841ab66cSSepherosa Ziehau * Drain power save queue and, if needed, clear TIM. 887841ab66cSSepherosa Ziehau */ 888841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DRAIN(ni, qlen); 889841ab66cSSepherosa Ziehau if (qlen != 0 && ic->ic_set_tim != NULL) 890841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 891841ab66cSSepherosa Ziehau 892841ab66cSSepherosa Ziehau ni->ni_associd = 0; 893841ab66cSSepherosa Ziehau if (ni->ni_challenge != NULL) { 894efda3bd0SMatthew Dillon kfree(ni->ni_challenge, M_DEVBUF); 895841ab66cSSepherosa Ziehau ni->ni_challenge = NULL; 896841ab66cSSepherosa Ziehau } 897841ab66cSSepherosa Ziehau /* 898841ab66cSSepherosa Ziehau * Preserve SSID, WPA, and WME ie's so the bss node is 899841ab66cSSepherosa Ziehau * reusable during a re-auth/re-assoc state transition. 900841ab66cSSepherosa Ziehau * If we remove these data they will not be recreated 901841ab66cSSepherosa Ziehau * because they come from a probe-response or beacon frame 902841ab66cSSepherosa Ziehau * which cannot be expected prior to the association-response. 903841ab66cSSepherosa Ziehau * This should not be an issue when operating in other modes 904841ab66cSSepherosa Ziehau * as stations leaving always go through a full state transition 905841ab66cSSepherosa Ziehau * which will rebuild this state. 906841ab66cSSepherosa Ziehau * 907841ab66cSSepherosa Ziehau * XXX does this leave us open to inheriting old state? 908841ab66cSSepherosa Ziehau */ 909841ab66cSSepherosa Ziehau for (i = 0; i < N(ni->ni_rxfrag); i++) 910841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[i] != NULL) { 911841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[i]); 912841ab66cSSepherosa Ziehau ni->ni_rxfrag[i] = NULL; 913841ab66cSSepherosa Ziehau } 914841ab66cSSepherosa Ziehau /* 915841ab66cSSepherosa Ziehau * Must be careful here to remove any key map entry w/o a LOR. 916841ab66cSSepherosa Ziehau */ 917841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(ni); 918841ab66cSSepherosa Ziehau #undef N 919f186073cSJoerg Sonnenberger } 920f186073cSJoerg Sonnenberger 921f186073cSJoerg Sonnenberger static void 922841ab66cSSepherosa Ziehau node_free(struct ieee80211_node *ni) 923f186073cSJoerg Sonnenberger { 924841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 925841ab66cSSepherosa Ziehau 926841ab66cSSepherosa Ziehau ic->ic_node_cleanup(ni); 927841ab66cSSepherosa Ziehau if (ni->ni_wpa_ie != NULL) 928efda3bd0SMatthew Dillon kfree(ni->ni_wpa_ie, M_DEVBUF); 929841ab66cSSepherosa Ziehau if (ni->ni_wme_ie != NULL) 930efda3bd0SMatthew Dillon kfree(ni->ni_wme_ie, M_DEVBUF); 931841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_DESTROY(ni); 932efda3bd0SMatthew Dillon kfree(ni, M_80211_NODE); 933f186073cSJoerg Sonnenberger } 934f186073cSJoerg Sonnenberger 935f186073cSJoerg Sonnenberger static uint8_t 936841ab66cSSepherosa Ziehau node_getrssi(const struct ieee80211_node *ni) 937f186073cSJoerg Sonnenberger { 938f186073cSJoerg Sonnenberger return ni->ni_rssi; 939f186073cSJoerg Sonnenberger } 940f186073cSJoerg Sonnenberger 941f186073cSJoerg Sonnenberger static void 942841ab66cSSepherosa Ziehau ieee80211_setup_node(struct ieee80211_node_table *nt, 943841ab66cSSepherosa Ziehau struct ieee80211_node *ni, const uint8_t *macaddr) 944f186073cSJoerg Sonnenberger { 945841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 946f186073cSJoerg Sonnenberger int hash; 947f186073cSJoerg Sonnenberger 948841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 949841ab66cSSepherosa Ziehau 950841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 951841ab66cSSepherosa Ziehau "%6D %p<%s> in %s table\n", __func__, ni, 952841ab66cSSepherosa Ziehau macaddr, ":", nt->nt_name); 953841ab66cSSepherosa Ziehau 954f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 955f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 956841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 957841ab66cSSepherosa Ziehau ni->ni_chan = IEEE80211_CHAN_ANYC; 958841ab66cSSepherosa Ziehau ni->ni_authmode = IEEE80211_AUTH_OPEN; 959841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_txpowlimit; /* max power */ 960841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); 961841ab66cSSepherosa Ziehau ni->ni_inact_reload = nt->nt_inact_init; 962841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 963841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 964841ab66cSSepherosa Ziehau 965841ab66cSSepherosa Ziehau TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); 966841ab66cSSepherosa Ziehau LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); 967841ab66cSSepherosa Ziehau ni->ni_table = nt; 968841ab66cSSepherosa Ziehau ni->ni_ic = ic; 969b9334f94SSepherosa Ziehau 970b9334f94SSepherosa Ziehau ieee80211_ratectl_data_alloc(ni); 971f186073cSJoerg Sonnenberger } 972f186073cSJoerg Sonnenberger 973f186073cSJoerg Sonnenberger struct ieee80211_node * 974841ab66cSSepherosa Ziehau ieee80211_alloc_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 975f186073cSJoerg Sonnenberger { 976841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 977841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 978841ab66cSSepherosa Ziehau 979841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 980f186073cSJoerg Sonnenberger if (ni != NULL) 981841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 982f186073cSJoerg Sonnenberger else 983f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 984f186073cSJoerg Sonnenberger return ni; 985f186073cSJoerg Sonnenberger } 986f186073cSJoerg Sonnenberger 987841ab66cSSepherosa Ziehau /* 988841ab66cSSepherosa Ziehau * Craft a temporary node suitable for sending a management frame 989841ab66cSSepherosa Ziehau * to the specified station. We craft only as much state as we 990841ab66cSSepherosa Ziehau * need to do the work since the node will be immediately reclaimed 991841ab66cSSepherosa Ziehau * once the send completes. 992841ab66cSSepherosa Ziehau */ 993f186073cSJoerg Sonnenberger struct ieee80211_node * 994841ab66cSSepherosa Ziehau ieee80211_tmp_node(struct ieee80211com *ic, const uint8_t *macaddr) 995f186073cSJoerg Sonnenberger { 996841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 997841ab66cSSepherosa Ziehau 998841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(&ic->ic_sta); 999f186073cSJoerg Sonnenberger if (ni != NULL) { 1000841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1001841ab66cSSepherosa Ziehau "%s %p<%6D>\n", __func__, ni, macaddr, ":"); 1002841ab66cSSepherosa Ziehau 1003841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); 1004841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1005841ab66cSSepherosa Ziehau ieee80211_node_initref(ni); /* mark referenced */ 1006841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1007841ab66cSSepherosa Ziehau /* NB: required by ieee80211_fix_rate */ 1008841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1009841ab66cSSepherosa Ziehau ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, 1010841ab66cSSepherosa Ziehau IEEE80211_KEYIX_NONE); 1011841ab66cSSepherosa Ziehau /* XXX optimize away */ 1012841ab66cSSepherosa Ziehau IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); 1013841ab66cSSepherosa Ziehau 1014841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* NB: pedantic */ 1015841ab66cSSepherosa Ziehau ni->ni_ic = ic; 1016b9334f94SSepherosa Ziehau 1017b9334f94SSepherosa Ziehau ieee80211_ratectl_data_alloc(ni); 1018841ab66cSSepherosa Ziehau } else { 1019841ab66cSSepherosa Ziehau /* XXX msg */ 1020841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1021841ab66cSSepherosa Ziehau } 1022841ab66cSSepherosa Ziehau return ni; 1023841ab66cSSepherosa Ziehau } 1024841ab66cSSepherosa Ziehau 1025841ab66cSSepherosa Ziehau struct ieee80211_node * 1026841ab66cSSepherosa Ziehau ieee80211_dup_bss(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1027841ab66cSSepherosa Ziehau { 1028841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1029841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1030841ab66cSSepherosa Ziehau 1031841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1032841ab66cSSepherosa Ziehau if (ni != NULL) { 1033841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, macaddr); 1034f186073cSJoerg Sonnenberger /* 1035f186073cSJoerg Sonnenberger * Inherit from ic_bss. 1036f186073cSJoerg Sonnenberger */ 1037841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1038841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1039841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1040f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); 1041841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan); 1042841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1043f186073cSJoerg Sonnenberger } else 1044f186073cSJoerg Sonnenberger ic->ic_stats.is_rx_nodealloc++; 1045f186073cSJoerg Sonnenberger return ni; 1046f186073cSJoerg Sonnenberger } 1047f186073cSJoerg Sonnenberger 1048f186073cSJoerg Sonnenberger static struct ieee80211_node * 1049841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1050841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1051841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1052841ab66cSSepherosa Ziehau #else 1053841ab66cSSepherosa Ziehau _ieee80211_find_node(struct ieee80211_node_table *nt, 1054841ab66cSSepherosa Ziehau const uint8_t *macaddr) 1055841ab66cSSepherosa Ziehau #endif 1056f186073cSJoerg Sonnenberger { 1057f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1058f186073cSJoerg Sonnenberger int hash; 1059f186073cSJoerg Sonnenberger 1060f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1061841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1062f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { 1063841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1064841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1065841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1066841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1067841ab66cSSepherosa Ziehau func, line, 1068841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1069841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1070841ab66cSSepherosa Ziehau #endif 1071f186073cSJoerg Sonnenberger return ni; 1072f186073cSJoerg Sonnenberger } 1073f186073cSJoerg Sonnenberger } 1074f186073cSJoerg Sonnenberger return NULL; 1075f186073cSJoerg Sonnenberger } 1076841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1077841ab66cSSepherosa Ziehau #define _ieee80211_find_node(nt, mac) \ 1078841ab66cSSepherosa Ziehau _ieee80211_find_node_debug(nt, mac, func, line) 1079841ab66cSSepherosa Ziehau #endif 1080f186073cSJoerg Sonnenberger 1081f186073cSJoerg Sonnenberger struct ieee80211_node * 1082841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1083841ab66cSSepherosa Ziehau ieee80211_find_node_debug(struct ieee80211_node_table *nt, 1084841ab66cSSepherosa Ziehau const uint8_t *macaddr, const char *func, int line) 1085841ab66cSSepherosa Ziehau #else 1086841ab66cSSepherosa Ziehau ieee80211_find_node(struct ieee80211_node_table *nt, const uint8_t *macaddr) 1087841ab66cSSepherosa Ziehau #endif 1088f186073cSJoerg Sonnenberger { 1089f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1090f186073cSJoerg Sonnenberger 1091841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1092841ab66cSSepherosa Ziehau 1093841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1094f186073cSJoerg Sonnenberger return ni; 1095f186073cSJoerg Sonnenberger } 1096f186073cSJoerg Sonnenberger 1097f186073cSJoerg Sonnenberger /* 1098841ab66cSSepherosa Ziehau * Fake up a node; this handles node discovery in adhoc mode. 1099841ab66cSSepherosa Ziehau * Note that for the driver's benefit we we treat this like 1100841ab66cSSepherosa Ziehau * an association so the driver has an opportunity to setup 1101841ab66cSSepherosa Ziehau * it's private state. 1102841ab66cSSepherosa Ziehau */ 1103841ab66cSSepherosa Ziehau struct ieee80211_node * 1104841ab66cSSepherosa Ziehau ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, 1105841ab66cSSepherosa Ziehau const uint8_t macaddr[IEEE80211_ADDR_LEN]) 1106841ab66cSSepherosa Ziehau { 1107841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1108841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1109841ab66cSSepherosa Ziehau 1110841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1111841ab66cSSepherosa Ziehau "%s: mac<%6D>\n", __func__, macaddr, ":"); 1112841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(nt, macaddr); 1113841ab66cSSepherosa Ziehau if (ni != NULL) { 1114841ab66cSSepherosa Ziehau /* XXX no rate negotiation; just dup */ 1115841ab66cSSepherosa Ziehau ni->ni_rates = ic->ic_bss->ni_rates; 1116b9334f94SSepherosa Ziehau 1117b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, 1); 1118b9334f94SSepherosa Ziehau 1119841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1120841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1121b9334f94SSepherosa Ziehau 1122841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1123841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1124841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 1125841ab66cSSepherosa Ziehau /* 1126841ab66cSSepherosa Ziehau * Blindly propagate capabilities based on the 1127841ab66cSSepherosa Ziehau * local configuration. In particular this permits 1128841ab66cSSepherosa Ziehau * us to use QoS to disable ACK's. 1129841ab66cSSepherosa Ziehau */ 1130841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_WME) 1131841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_QOS; 1132841ab66cSSepherosa Ziehau } 1133841ab66cSSepherosa Ziehau } 1134841ab66cSSepherosa Ziehau return ni; 1135841ab66cSSepherosa Ziehau } 1136841ab66cSSepherosa Ziehau 1137841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1138841ab66cSSepherosa Ziehau static void 1139841ab66cSSepherosa Ziehau dump_probe_beacon(uint8_t subtype, int isnew, 1140841ab66cSSepherosa Ziehau const uint8_t mac[IEEE80211_ADDR_LEN], 1141841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1142841ab66cSSepherosa Ziehau { 1143841ab66cSSepherosa Ziehau 1144841ab66cSSepherosa Ziehau printf("[%6D] %s%s on chan %u (bss chan %u) ", 1145841ab66cSSepherosa Ziehau mac, ":", isnew ? "new " : "", 1146841ab66cSSepherosa Ziehau ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], 1147841ab66cSSepherosa Ziehau sp->chan, sp->bchan); 1148841ab66cSSepherosa Ziehau ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); 1149841ab66cSSepherosa Ziehau printf("\n"); 1150841ab66cSSepherosa Ziehau 1151841ab66cSSepherosa Ziehau if (isnew) { 1152841ab66cSSepherosa Ziehau printf("[%6D] caps 0x%x bintval %u erp 0x%x", 1153841ab66cSSepherosa Ziehau mac, ":", sp->capinfo, sp->bintval, sp->erp); 1154841ab66cSSepherosa Ziehau if (sp->country != NULL) { 1155841ab66cSSepherosa Ziehau #if defined(__FreeBSD__) || defined(__DragonFly__) 1156841ab66cSSepherosa Ziehau printf(" country info %*D", 1157841ab66cSSepherosa Ziehau sp->country[1], sp->country+2, " "); 1158841ab66cSSepherosa Ziehau #else 1159841ab66cSSepherosa Ziehau int i; 1160841ab66cSSepherosa Ziehau printf(" country info"); 1161841ab66cSSepherosa Ziehau for (i = 0; i < sp->country[1]; i++) 1162841ab66cSSepherosa Ziehau printf(" %02x", sp->country[i+2]); 1163841ab66cSSepherosa Ziehau #endif 1164841ab66cSSepherosa Ziehau } 1165841ab66cSSepherosa Ziehau printf("\n"); 1166841ab66cSSepherosa Ziehau } 1167841ab66cSSepherosa Ziehau } 1168841ab66cSSepherosa Ziehau #endif /* IEEE80211_DEBUG */ 1169841ab66cSSepherosa Ziehau 1170841ab66cSSepherosa Ziehau static void 1171841ab66cSSepherosa Ziehau saveie(uint8_t **iep, const uint8_t *ie) 1172841ab66cSSepherosa Ziehau { 1173841ab66cSSepherosa Ziehau 1174841ab66cSSepherosa Ziehau if (ie == NULL) 1175841ab66cSSepherosa Ziehau *iep = NULL; 1176841ab66cSSepherosa Ziehau else 1177841ab66cSSepherosa Ziehau ieee80211_saveie(iep, ie); 1178841ab66cSSepherosa Ziehau } 1179841ab66cSSepherosa Ziehau 1180841ab66cSSepherosa Ziehau /* 1181841ab66cSSepherosa Ziehau * Process a beacon or probe response frame. 1182841ab66cSSepherosa Ziehau */ 1183841ab66cSSepherosa Ziehau void 1184841ab66cSSepherosa Ziehau ieee80211_add_scan(struct ieee80211com *ic, 1185841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp, 1186841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1187841ab66cSSepherosa Ziehau int subtype, int rssi, int rstamp) 1188841ab66cSSepherosa Ziehau { 1189841ab66cSSepherosa Ziehau #define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1190841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_scan; 1191841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1192841ab66cSSepherosa Ziehau int newnode = 0; 1193841ab66cSSepherosa Ziehau 1194841ab66cSSepherosa Ziehau ni = ieee80211_find_node(nt, wh->i_addr2); 1195841ab66cSSepherosa Ziehau if (ni == NULL) { 1196841ab66cSSepherosa Ziehau /* 1197841ab66cSSepherosa Ziehau * Create a new entry. 1198841ab66cSSepherosa Ziehau */ 1199841ab66cSSepherosa Ziehau ni = ic->ic_node_alloc(nt); 1200841ab66cSSepherosa Ziehau if (ni == NULL) { 1201841ab66cSSepherosa Ziehau ic->ic_stats.is_rx_nodealloc++; 1202841ab66cSSepherosa Ziehau return; 1203841ab66cSSepherosa Ziehau } 1204841ab66cSSepherosa Ziehau ieee80211_setup_node(nt, ni, wh->i_addr2); 1205841ab66cSSepherosa Ziehau /* 1206841ab66cSSepherosa Ziehau * XXX inherit from ic_bss. 1207841ab66cSSepherosa Ziehau */ 1208841ab66cSSepherosa Ziehau ni->ni_authmode = ic->ic_bss->ni_authmode; 1209841ab66cSSepherosa Ziehau ni->ni_txpower = ic->ic_bss->ni_txpower; 1210841ab66cSSepherosa Ziehau ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ 1211841ab66cSSepherosa Ziehau ieee80211_set_chan(ic, ni, ic->ic_curchan); 1212841ab66cSSepherosa Ziehau ni->ni_rsn = ic->ic_bss->ni_rsn; 1213841ab66cSSepherosa Ziehau newnode = 1; 1214841ab66cSSepherosa Ziehau } 1215841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1216841ab66cSSepherosa Ziehau if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN)) 1217841ab66cSSepherosa Ziehau dump_probe_beacon(subtype, newnode, wh->i_addr2, sp); 1218841ab66cSSepherosa Ziehau #endif 1219841ab66cSSepherosa Ziehau /* XXX ap beaconing multiple ssid w/ same bssid */ 1220841ab66cSSepherosa Ziehau if (sp->ssid[1] != 0 && 1221841ab66cSSepherosa Ziehau (ISPROBE(subtype) || ni->ni_esslen == 0)) { 1222841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1223841ab66cSSepherosa Ziehau memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); 1224841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1225841ab66cSSepherosa Ziehau } 1226841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1227841ab66cSSepherosa Ziehau ni->ni_rssi = rssi; 1228841ab66cSSepherosa Ziehau ni->ni_rstamp = rstamp; 1229841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1230841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1231841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1232841ab66cSSepherosa Ziehau ni->ni_chan = &ic->ic_channels[sp->chan]; 1233841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1234841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1235841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1236841ab66cSSepherosa Ziehau if (sp->tim != NULL) { 1237841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *ie = 1238841ab66cSSepherosa Ziehau (struct ieee80211_tim_ie *) sp->tim; 1239841ab66cSSepherosa Ziehau 1240841ab66cSSepherosa Ziehau ni->ni_dtim_count = ie->tim_count; 1241841ab66cSSepherosa Ziehau ni->ni_dtim_period = ie->tim_period; 1242841ab66cSSepherosa Ziehau } 1243841ab66cSSepherosa Ziehau /* 1244841ab66cSSepherosa Ziehau * Record the byte offset from the mac header to 1245841ab66cSSepherosa Ziehau * the start of the TIM information element for 1246841ab66cSSepherosa Ziehau * use by hardware and/or to speedup software 1247841ab66cSSepherosa Ziehau * processing of beacon frames. 1248841ab66cSSepherosa Ziehau */ 1249841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1250841ab66cSSepherosa Ziehau /* 1251841ab66cSSepherosa Ziehau * Record optional information elements that might be 1252841ab66cSSepherosa Ziehau * used by applications or drivers. 1253841ab66cSSepherosa Ziehau */ 1254841ab66cSSepherosa Ziehau saveie(&ni->ni_wme_ie, sp->wme); 1255841ab66cSSepherosa Ziehau saveie(&ni->ni_wpa_ie, sp->wpa); 1256841ab66cSSepherosa Ziehau 1257841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1258841ab66cSSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); 1259841ab66cSSepherosa Ziehau 1260841ab66cSSepherosa Ziehau if (!newnode) 1261841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1262841ab66cSSepherosa Ziehau #undef ISPROBE 1263841ab66cSSepherosa Ziehau } 1264841ab66cSSepherosa Ziehau 1265841ab66cSSepherosa Ziehau void 1266841ab66cSSepherosa Ziehau ieee80211_init_neighbor(struct ieee80211_node *ni, 1267841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1268841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1269841ab66cSSepherosa Ziehau { 1270841ab66cSSepherosa Ziehau 1271841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1272841ab66cSSepherosa Ziehau "%s: %p<%s>\n", __func__, ni, ni->ni_macaddr, ":"); 1273841ab66cSSepherosa Ziehau ni->ni_esslen = sp->ssid[1]; 1274841ab66cSSepherosa Ziehau memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); 1275841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); 1276841ab66cSSepherosa Ziehau memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); 1277841ab66cSSepherosa Ziehau ni->ni_intval = sp->bintval; 1278841ab66cSSepherosa Ziehau ni->ni_capinfo = sp->capinfo; 1279841ab66cSSepherosa Ziehau ni->ni_chan = ni->ni_ic->ic_curchan; 1280841ab66cSSepherosa Ziehau ni->ni_fhdwell = sp->fhdwell; 1281841ab66cSSepherosa Ziehau ni->ni_fhindex = sp->fhindex; 1282841ab66cSSepherosa Ziehau ni->ni_erp = sp->erp; 1283841ab66cSSepherosa Ziehau ni->ni_timoff = sp->timoff; 1284841ab66cSSepherosa Ziehau if (sp->wme != NULL) 1285841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wme_ie, sp->wme); 1286841ab66cSSepherosa Ziehau if (sp->wpa != NULL) 1287841ab66cSSepherosa Ziehau ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa); 1288841ab66cSSepherosa Ziehau 1289841ab66cSSepherosa Ziehau /* NB: must be after ni_chan is setup */ 1290841ab66cSSepherosa Ziehau ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); 1291841ab66cSSepherosa Ziehau } 1292841ab66cSSepherosa Ziehau 1293841ab66cSSepherosa Ziehau /* 1294841ab66cSSepherosa Ziehau * Do node discovery in adhoc mode on receipt of a beacon 1295841ab66cSSepherosa Ziehau * or probe response frame. Note that for the driver's 1296841ab66cSSepherosa Ziehau * benefit we we treat this like an association so the 1297841ab66cSSepherosa Ziehau * driver has an opportunity to setup it's private state. 1298841ab66cSSepherosa Ziehau */ 1299841ab66cSSepherosa Ziehau struct ieee80211_node * 1300841ab66cSSepherosa Ziehau ieee80211_add_neighbor(struct ieee80211com *ic, 1301841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh, 1302841ab66cSSepherosa Ziehau const struct ieee80211_scanparams *sp) 1303841ab66cSSepherosa Ziehau { 1304841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1305841ab66cSSepherosa Ziehau 1306841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1307841ab66cSSepherosa Ziehau "%s: mac<%s>\n", __func__, wh->i_addr2, ":"); 1308841ab66cSSepherosa Ziehau ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */ 1309841ab66cSSepherosa Ziehau if (ni != NULL) { 1310841ab66cSSepherosa Ziehau ieee80211_init_neighbor(ni, wh, sp); 1311b9334f94SSepherosa Ziehau 1312b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, 1); 1313b9334f94SSepherosa Ziehau 1314841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 1315841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, 1); 1316b9334f94SSepherosa Ziehau 1317841ab66cSSepherosa Ziehau /* XXX not right for 802.1x/WPA */ 1318841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1319841ab66cSSepherosa Ziehau } 1320841ab66cSSepherosa Ziehau return ni; 1321841ab66cSSepherosa Ziehau } 1322841ab66cSSepherosa Ziehau 1323841ab66cSSepherosa Ziehau #define IS_CTL(wh) \ 1324841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 1325841ab66cSSepherosa Ziehau #define IS_PSPOLL(wh) \ 1326841ab66cSSepherosa Ziehau ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) 1327841ab66cSSepherosa Ziehau /* 1328841ab66cSSepherosa Ziehau * Locate the node for sender, track state, and then pass the 1329841ab66cSSepherosa Ziehau * (referenced) node up to the 802.11 layer for its use. We 1330841ab66cSSepherosa Ziehau * are required to pass some node so we fall back to ic_bss 1331841ab66cSSepherosa Ziehau * when this frame is from an unknown sender. The 802.11 layer 1332841ab66cSSepherosa Ziehau * knows this means the sender wasn't in the node table and 1333841ab66cSSepherosa Ziehau * acts accordingly. 1334841ab66cSSepherosa Ziehau */ 1335841ab66cSSepherosa Ziehau struct ieee80211_node * 1336841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1337841ab66cSSepherosa Ziehau ieee80211_find_rxnode_debug(struct ieee80211com *ic, 1338841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, const char *func, int line) 1339841ab66cSSepherosa Ziehau #else 1340841ab66cSSepherosa Ziehau ieee80211_find_rxnode(struct ieee80211com *ic, 1341841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh) 1342841ab66cSSepherosa Ziehau #endif 1343841ab66cSSepherosa Ziehau { 1344841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1345841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1346841ab66cSSepherosa Ziehau 1347841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1348841ab66cSSepherosa Ziehau 1349841ab66cSSepherosa Ziehau /* XXX may want scanned nodes in the neighbor table for adhoc */ 1350841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1351841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1352841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1353841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1354841ab66cSSepherosa Ziehau else 1355841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1356841ab66cSSepherosa Ziehau /* XXX check ic_bss first in station mode */ 1357841ab66cSSepherosa Ziehau /* XXX 4-address frames? */ 1358841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1359841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1360841ab66cSSepherosa Ziehau else 1361841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1362841ab66cSSepherosa Ziehau if (ni == NULL) 1363841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1364841ab66cSSepherosa Ziehau 1365841ab66cSSepherosa Ziehau return ni; 1366841ab66cSSepherosa Ziehau } 1367841ab66cSSepherosa Ziehau 1368841ab66cSSepherosa Ziehau /* 1369841ab66cSSepherosa Ziehau * Like ieee80211_find_rxnode but use the supplied h/w 1370841ab66cSSepherosa Ziehau * key index as a hint to locate the node in the key 1371841ab66cSSepherosa Ziehau * mapping table. If an entry is present at the key 1372841ab66cSSepherosa Ziehau * index we return it; otherwise do a normal lookup and 1373841ab66cSSepherosa Ziehau * update the mapping table if the station has a unicast 1374841ab66cSSepherosa Ziehau * key assigned to it. 1375841ab66cSSepherosa Ziehau */ 1376841ab66cSSepherosa Ziehau struct ieee80211_node * 1377841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1378841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic, 1379841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix, 1380841ab66cSSepherosa Ziehau const char *func, int line) 1381841ab66cSSepherosa Ziehau #else 1382841ab66cSSepherosa Ziehau ieee80211_find_rxnode_withkey(struct ieee80211com *ic, 1383841ab66cSSepherosa Ziehau const struct ieee80211_frame_min *wh, ieee80211_keyix keyix) 1384841ab66cSSepherosa Ziehau #endif 1385841ab66cSSepherosa Ziehau { 1386841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt; 1387841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1388841ab66cSSepherosa Ziehau 1389841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1390841ab66cSSepherosa Ziehau 1391841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA || 1392841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_MONITOR || 1393841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_SCAN)) 1394841ab66cSSepherosa Ziehau nt = &ic->ic_scan; 1395841ab66cSSepherosa Ziehau else 1396841ab66cSSepherosa Ziehau nt = &ic->ic_sta; 1397841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) 1398841ab66cSSepherosa Ziehau ni = nt->nt_keyixmap[keyix]; 1399841ab66cSSepherosa Ziehau else 1400841ab66cSSepherosa Ziehau ni = NULL; 1401841ab66cSSepherosa Ziehau if (ni == NULL) { 1402841ab66cSSepherosa Ziehau if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) 1403841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr1); 1404841ab66cSSepherosa Ziehau else 1405841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, wh->i_addr2); 1406841ab66cSSepherosa Ziehau if (ni == NULL) 1407841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1408841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 1409841ab66cSSepherosa Ziehau /* 1410841ab66cSSepherosa Ziehau * If the station has a unicast key cache slot 1411841ab66cSSepherosa Ziehau * assigned update the key->node mapping table. 1412841ab66cSSepherosa Ziehau */ 1413841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1414841ab66cSSepherosa Ziehau /* XXX can keyixmap[keyix] != NULL? */ 1415841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1416841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == NULL) { 1417841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1418841ab66cSSepherosa Ziehau "%s: add key map entry %p<%6D> refcnt %d\n", 1419841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1420841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 1421841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni); 1422841ab66cSSepherosa Ziehau } 1423841ab66cSSepherosa Ziehau } 1424841ab66cSSepherosa Ziehau } else { 1425841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1426841ab66cSSepherosa Ziehau } 1427841ab66cSSepherosa Ziehau 1428841ab66cSSepherosa Ziehau return ni; 1429841ab66cSSepherosa Ziehau } 1430841ab66cSSepherosa Ziehau #undef IS_PSPOLL 1431841ab66cSSepherosa Ziehau #undef IS_CTL 1432841ab66cSSepherosa Ziehau 1433841ab66cSSepherosa Ziehau /* 1434f186073cSJoerg Sonnenberger * Return a reference to the appropriate node for sending 1435f186073cSJoerg Sonnenberger * a data frame. This handles node discovery in adhoc networks. 1436f186073cSJoerg Sonnenberger */ 1437f186073cSJoerg Sonnenberger struct ieee80211_node * 1438841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1439841ab66cSSepherosa Ziehau ieee80211_find_txnode_debug(struct ieee80211com *ic, const uint8_t *macaddr, 1440841ab66cSSepherosa Ziehau const char *func, int line) 1441841ab66cSSepherosa Ziehau #else 1442841ab66cSSepherosa Ziehau ieee80211_find_txnode(struct ieee80211com *ic, const uint8_t *macaddr) 1443841ab66cSSepherosa Ziehau #endif 1444f186073cSJoerg Sonnenberger { 1445841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1446f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1447841ab66cSSepherosa Ziehau 1448841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1449f186073cSJoerg Sonnenberger 1450f186073cSJoerg Sonnenberger /* 1451f186073cSJoerg Sonnenberger * The destination address should be in the node table 1452841ab66cSSepherosa Ziehau * unless this is a multicast/broadcast frame. We can 1453841ab66cSSepherosa Ziehau * also optimize station mode operation, all frames go 1454841ab66cSSepherosa Ziehau * to the bss node. 1455f186073cSJoerg Sonnenberger */ 1456f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) 1457841ab66cSSepherosa Ziehau ni = ieee80211_ref_node(ic->ic_bss); 1458841ab66cSSepherosa Ziehau else 1459841ab66cSSepherosa Ziehau ni = _ieee80211_find_node(nt, macaddr); 1460f186073cSJoerg Sonnenberger 1461841ab66cSSepherosa Ziehau if (ni == NULL) { 1462841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_IBSS || 1463841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO) { 1464f186073cSJoerg Sonnenberger /* 1465841ab66cSSepherosa Ziehau * In adhoc mode cons up a node for the destination. 1466841ab66cSSepherosa Ziehau * Note that we need an additional reference for the 1467841ab66cSSepherosa Ziehau * caller to be consistent with _ieee80211_find_node. 1468f186073cSJoerg Sonnenberger */ 1469841ab66cSSepherosa Ziehau ni = ieee80211_fakeup_adhoc_node(nt, macaddr); 1470841ab66cSSepherosa Ziehau if (ni != NULL) 1471841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1472841ab66cSSepherosa Ziehau } else { 1473841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT, 1474841ab66cSSepherosa Ziehau "[%6D] no node, discard frame (%s)\n", 1475841ab66cSSepherosa Ziehau macaddr, ":", __func__); 1476841ab66cSSepherosa Ziehau ic->ic_stats.is_tx_nonode++; 1477f186073cSJoerg Sonnenberger } 1478f186073cSJoerg Sonnenberger } 1479f186073cSJoerg Sonnenberger return ni; 1480f186073cSJoerg Sonnenberger } 1481f186073cSJoerg Sonnenberger 1482f186073cSJoerg Sonnenberger /* 1483f186073cSJoerg Sonnenberger * Like find but search based on the channel too. 1484f186073cSJoerg Sonnenberger */ 1485f186073cSJoerg Sonnenberger struct ieee80211_node * 1486841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1487841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel_debug(struct ieee80211_node_table *nt, 1488841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan, 1489841ab66cSSepherosa Ziehau const char *func, int line) 1490841ab66cSSepherosa Ziehau #else 1491841ab66cSSepherosa Ziehau ieee80211_find_node_with_channel(struct ieee80211_node_table *nt, 1492841ab66cSSepherosa Ziehau const uint8_t *macaddr, struct ieee80211_channel *chan) 1493841ab66cSSepherosa Ziehau #endif 1494f186073cSJoerg Sonnenberger { 1495f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1496f186073cSJoerg Sonnenberger int hash; 1497841ab66cSSepherosa Ziehau 1498841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1499f186073cSJoerg Sonnenberger 1500f186073cSJoerg Sonnenberger hash = IEEE80211_NODE_HASH(macaddr); 1501841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1502f186073cSJoerg Sonnenberger if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1503f186073cSJoerg Sonnenberger ni->ni_chan == chan) { 1504841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1505841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 1506841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1507841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1508841ab66cSSepherosa Ziehau func, line, 1509841ab66cSSepherosa Ziehau #else 1510841ab66cSSepherosa Ziehau "%s %p<%6D> refcnt %d\n", __func__, 1511841ab66cSSepherosa Ziehau #endif 1512841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1513841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1514f186073cSJoerg Sonnenberger break; 1515f186073cSJoerg Sonnenberger } 1516f186073cSJoerg Sonnenberger } 1517f186073cSJoerg Sonnenberger return ni; 1518f186073cSJoerg Sonnenberger } 1519f186073cSJoerg Sonnenberger 1520841ab66cSSepherosa Ziehau /* 1521841ab66cSSepherosa Ziehau * Like find but search based on the ssid too. 1522841ab66cSSepherosa Ziehau */ 1523841ab66cSSepherosa Ziehau struct ieee80211_node * 1524841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1525841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid_debug(struct ieee80211_node_table *nt, 1526841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid, 1527841ab66cSSepherosa Ziehau const char *func, int line) 1528841ab66cSSepherosa Ziehau #else 1529841ab66cSSepherosa Ziehau ieee80211_find_node_with_ssid(struct ieee80211_node_table *nt, 1530841ab66cSSepherosa Ziehau const uint8_t *macaddr, u_int ssidlen, const uint8_t *ssid) 1531841ab66cSSepherosa Ziehau #endif 1532f186073cSJoerg Sonnenberger { 1533841ab66cSSepherosa Ziehau #define MATCH_SSID(ni, ssid, ssidlen) \ 1534841ab66cSSepherosa Ziehau (ni->ni_esslen == ssidlen && memcmp(ni->ni_essid, ssid, ssidlen) == 0) 1535841ab66cSSepherosa Ziehau static const uint8_t zeromac[IEEE80211_ADDR_LEN]; 1536841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1537f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 1538841ab66cSSepherosa Ziehau int hash; 1539f186073cSJoerg Sonnenberger 1540841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1541841ab66cSSepherosa Ziehau 1542841ab66cSSepherosa Ziehau /* 1543841ab66cSSepherosa Ziehau * A mac address that is all zero means match only the ssid; 1544841ab66cSSepherosa Ziehau * otherwise we must match both. 1545841ab66cSSepherosa Ziehau */ 1546841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(macaddr, zeromac)) { 1547841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1548841ab66cSSepherosa Ziehau if (MATCH_SSID(ni, ssid, ssidlen)) 1549841ab66cSSepherosa Ziehau break; 1550841ab66cSSepherosa Ziehau } 1551841ab66cSSepherosa Ziehau } else { 1552841ab66cSSepherosa Ziehau hash = IEEE80211_NODE_HASH(macaddr); 1553841ab66cSSepherosa Ziehau LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { 1554841ab66cSSepherosa Ziehau if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 1555841ab66cSSepherosa Ziehau MATCH_SSID(ni, ssid, ssidlen)) 1556841ab66cSSepherosa Ziehau break; 1557841ab66cSSepherosa Ziehau } 1558841ab66cSSepherosa Ziehau } 1559841ab66cSSepherosa Ziehau if (ni != NULL) { 1560841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); /* mark referenced */ 1561841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1562841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1563841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, 1564841ab66cSSepherosa Ziehau func, line, 1565841ab66cSSepherosa Ziehau #else 1566841ab66cSSepherosa Ziehau "%s %p<%6D> refcnt %d\n", __func__, 1567841ab66cSSepherosa Ziehau #endif 1568841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":", 1569841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1570841ab66cSSepherosa Ziehau } 1571841ab66cSSepherosa Ziehau return ni; 1572841ab66cSSepherosa Ziehau #undef MATCH_SSID 1573841ab66cSSepherosa Ziehau } 1574841ab66cSSepherosa Ziehau 1575841ab66cSSepherosa Ziehau static void 1576841ab66cSSepherosa Ziehau _ieee80211_free_node(struct ieee80211_node *ni) 1577841ab66cSSepherosa Ziehau { 1578841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1579841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1580841ab66cSSepherosa Ziehau 1581841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1582841ab66cSSepherosa Ziehau "%s %p<%6D> in %s table\n", __func__, ni, 1583841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1584841ab66cSSepherosa Ziehau nt != NULL ? nt->nt_name : "<gone>"); 1585841ab66cSSepherosa Ziehau 1586b9334f94SSepherosa Ziehau ieee80211_ratectl_data_free(ni); 1587b9334f94SSepherosa Ziehau 1588841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1589841ab66cSSepherosa Ziehau if (nt != NULL) { 1590841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1591841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1592841ab66cSSepherosa Ziehau } 1593841ab66cSSepherosa Ziehau ic->ic_node_free(ni); 1594841ab66cSSepherosa Ziehau } 1595841ab66cSSepherosa Ziehau 1596841ab66cSSepherosa Ziehau void 1597841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1598841ab66cSSepherosa Ziehau ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) 1599841ab66cSSepherosa Ziehau #else 1600841ab66cSSepherosa Ziehau ieee80211_free_node(struct ieee80211_node *ni) 1601841ab66cSSepherosa Ziehau #endif 1602841ab66cSSepherosa Ziehau { 1603841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 1604841ab66cSSepherosa Ziehau 1605841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ni->ni_ic->ic_ifp->if_serializer); 1606841ab66cSSepherosa Ziehau 1607841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG_REFCNT 1608841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1609841ab66cSSepherosa Ziehau "%s (%s:%u) %p<%6D> refcnt %d\n", __func__, func, line, ni, 1610841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni) - 1); 1611841ab66cSSepherosa Ziehau #endif 1612841ab66cSSepherosa Ziehau if (nt != NULL) { 1613841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) { 1614841ab66cSSepherosa Ziehau /* 1615841ab66cSSepherosa Ziehau * Last reference, reclaim state. 1616841ab66cSSepherosa Ziehau */ 1617841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1618841ab66cSSepherosa Ziehau } else if (ieee80211_node_refcnt(ni) == 1 && 1619841ab66cSSepherosa Ziehau nt->nt_keyixmap != NULL) { 1620841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1621841ab66cSSepherosa Ziehau /* 1622841ab66cSSepherosa Ziehau * Check for a last reference in the key mapping table. 1623841ab66cSSepherosa Ziehau */ 1624841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1625841ab66cSSepherosa Ziehau if (keyix < nt->nt_keyixmax && 1626841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1627841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1628841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry", __func__, 1629841ab66cSSepherosa Ziehau ni, ni->ni_macaddr, ":"); 1630841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1631841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* XXX needed? */ 1632841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1633841ab66cSSepherosa Ziehau } 1634841ab66cSSepherosa Ziehau } 1635841ab66cSSepherosa Ziehau } else { 1636841ab66cSSepherosa Ziehau if (ieee80211_node_dectestref(ni)) 1637841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1638841ab66cSSepherosa Ziehau } 1639f186073cSJoerg Sonnenberger } 1640f186073cSJoerg Sonnenberger 1641f186073cSJoerg Sonnenberger /* 1642841ab66cSSepherosa Ziehau * Reclaim a unicast key and clear any key cache state. 1643841ab66cSSepherosa Ziehau */ 1644841ab66cSSepherosa Ziehau int 1645841ab66cSSepherosa Ziehau ieee80211_node_delucastkey(struct ieee80211_node *ni) 1646841ab66cSSepherosa Ziehau { 1647841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 1648841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 1649841ab66cSSepherosa Ziehau struct ieee80211_node *nikey; 1650841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1651841ab66cSSepherosa Ziehau int status; 1652841ab66cSSepherosa Ziehau 1653841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1654841ab66cSSepherosa Ziehau 1655841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1656841ab66cSSepherosa Ziehau status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey); 1657841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { 1658841ab66cSSepherosa Ziehau nikey = nt->nt_keyixmap[keyix]; 1659fc6d0222SSascha Wildner nt->nt_keyixmap[keyix] = NULL; 1660841ab66cSSepherosa Ziehau } else 1661841ab66cSSepherosa Ziehau nikey = NULL; 1662841ab66cSSepherosa Ziehau 1663841ab66cSSepherosa Ziehau if (nikey != NULL) { 1664841ab66cSSepherosa Ziehau KASSERT(nikey == ni, 1665841ab66cSSepherosa Ziehau ("key map out of sync, ni %p nikey %p", ni, nikey)); 1666841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1667841ab66cSSepherosa Ziehau "%s: delete key map entry %p<%6D> refcnt %d\n", 1668841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1669841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)-1); 1670841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 1671841ab66cSSepherosa Ziehau } 1672841ab66cSSepherosa Ziehau return status; 1673841ab66cSSepherosa Ziehau } 1674841ab66cSSepherosa Ziehau 1675841ab66cSSepherosa Ziehau /* 1676841ab66cSSepherosa Ziehau * Reclaim a node. If this is the last reference count then 1677841ab66cSSepherosa Ziehau * do the normal free work. Otherwise remove it from the node 1678841ab66cSSepherosa Ziehau * table and mark it gone by clearing the back-reference. 1679841ab66cSSepherosa Ziehau */ 1680841ab66cSSepherosa Ziehau static void 1681841ab66cSSepherosa Ziehau node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1682841ab66cSSepherosa Ziehau { 1683841ab66cSSepherosa Ziehau ieee80211_keyix keyix; 1684841ab66cSSepherosa Ziehau 1685841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1686841ab66cSSepherosa Ziehau 1687841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1688841ab66cSSepherosa Ziehau "%s: remove %p<%6D> from %s table, refcnt %d\n", 1689841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":", 1690841ab66cSSepherosa Ziehau nt->nt_name, ieee80211_node_refcnt(ni)-1); 1691b9334f94SSepherosa Ziehau 1692b9334f94SSepherosa Ziehau ieee80211_ratectl_data_free(ni); 1693b9334f94SSepherosa Ziehau 1694841ab66cSSepherosa Ziehau /* 1695841ab66cSSepherosa Ziehau * Clear any entry in the unicast key mapping table. 1696841ab66cSSepherosa Ziehau * We need to do it here so rx lookups don't find it 1697841ab66cSSepherosa Ziehau * in the mapping table even if it's not in the hash 1698841ab66cSSepherosa Ziehau * table. We cannot depend on the mapping table entry 1699841ab66cSSepherosa Ziehau * being cleared because the node may not be free'd. 1700841ab66cSSepherosa Ziehau */ 1701841ab66cSSepherosa Ziehau keyix = ni->ni_ucastkey.wk_rxkeyix; 1702841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax && 1703841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] == ni) { 1704841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE, 1705841ab66cSSepherosa Ziehau "%s: %p<%6D> clear key map entry\n", 1706841ab66cSSepherosa Ziehau __func__, ni, ni->ni_macaddr, ":"); 1707841ab66cSSepherosa Ziehau nt->nt_keyixmap[keyix] = NULL; 1708841ab66cSSepherosa Ziehau ieee80211_node_decref(ni); /* NB: don't need free */ 1709841ab66cSSepherosa Ziehau } 1710841ab66cSSepherosa Ziehau if (!ieee80211_node_dectestref(ni)) { 1711841ab66cSSepherosa Ziehau /* 1712841ab66cSSepherosa Ziehau * Other references are present, just remove the 1713841ab66cSSepherosa Ziehau * node from the table so it cannot be found. When 1714841ab66cSSepherosa Ziehau * the references are dropped storage will be 1715841ab66cSSepherosa Ziehau * reclaimed. 1716841ab66cSSepherosa Ziehau */ 1717841ab66cSSepherosa Ziehau TAILQ_REMOVE(&nt->nt_node, ni, ni_list); 1718841ab66cSSepherosa Ziehau LIST_REMOVE(ni, ni_hash); 1719841ab66cSSepherosa Ziehau ni->ni_table = NULL; /* clear reference */ 1720841ab66cSSepherosa Ziehau } else 1721841ab66cSSepherosa Ziehau _ieee80211_free_node(ni); 1722841ab66cSSepherosa Ziehau } 1723841ab66cSSepherosa Ziehau 1724841ab66cSSepherosa Ziehau static void 1725841ab66cSSepherosa Ziehau ieee80211_free_allnodes(struct ieee80211_node_table *nt) 1726841ab66cSSepherosa Ziehau { 1727841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1728841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 1729841ab66cSSepherosa Ziehau 1730841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1731841ab66cSSepherosa Ziehau "%s: free all nodes in %s table\n", __func__, nt->nt_name); 1732841ab66cSSepherosa Ziehau 1733841ab66cSSepherosa Ziehau while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) { 1734841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1735841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 1736841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 1737841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 1738841ab66cSSepherosa Ziehau } 1739841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1740841ab66cSSepherosa Ziehau } 1741841ab66cSSepherosa Ziehau ieee80211_reset_erp(ic); 1742841ab66cSSepherosa Ziehau } 1743841ab66cSSepherosa Ziehau 1744841ab66cSSepherosa Ziehau /* 1745841ab66cSSepherosa Ziehau * Timeout entries in the scan cache. 1746841ab66cSSepherosa Ziehau */ 1747841ab66cSSepherosa Ziehau static void 1748841ab66cSSepherosa Ziehau ieee80211_timeout_scan_candidates(struct ieee80211_node_table *nt) 1749841ab66cSSepherosa Ziehau { 1750841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1751841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *tni; 1752841ab66cSSepherosa Ziehau 1753841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1754841ab66cSSepherosa Ziehau 1755841ab66cSSepherosa Ziehau ni = ic->ic_bss; 1756841ab66cSSepherosa Ziehau /* XXX belongs elsewhere */ 1757841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && ticks > ni->ni_rxfragstamp + hz) { 1758841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1759841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1760841ab66cSSepherosa Ziehau } 1761841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, tni) { 1762841ab66cSSepherosa Ziehau if (ni->ni_inact && --ni->ni_inact == 0) { 1763841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 1764841ab66cSSepherosa Ziehau "[%6D] scan candidate purged from cache " 1765841ab66cSSepherosa Ziehau "(refcnt %u)\n", ni->ni_macaddr, ":", 1766841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)); 1767841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 1768841ab66cSSepherosa Ziehau } 1769841ab66cSSepherosa Ziehau } 1770841ab66cSSepherosa Ziehau 1771841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1772841ab66cSSepherosa Ziehau } 1773841ab66cSSepherosa Ziehau 1774841ab66cSSepherosa Ziehau /* 1775841ab66cSSepherosa Ziehau * Timeout inactive stations and do related housekeeping. 1776841ab66cSSepherosa Ziehau * Note that we cannot hold the node lock while sending a 1777841ab66cSSepherosa Ziehau * frame as this would lead to a LOR. Instead we use a 1778841ab66cSSepherosa Ziehau * generation number to mark nodes that we've scanned and 1779841ab66cSSepherosa Ziehau * drop the lock and restart a scan if we have to time out 1780841ab66cSSepherosa Ziehau * a node. Since we are single-threaded by virtue of 1781f186073cSJoerg Sonnenberger * controlling the inactivity timer we can be sure this will 1782f186073cSJoerg Sonnenberger * process each node only once. 1783f186073cSJoerg Sonnenberger */ 1784841ab66cSSepherosa Ziehau static void 1785841ab66cSSepherosa Ziehau ieee80211_timeout_stations(struct ieee80211_node_table *nt) 1786f186073cSJoerg Sonnenberger { 1787841ab66cSSepherosa Ziehau struct ieee80211com *ic = nt->nt_ic; 1788841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1789841ab66cSSepherosa Ziehau int isadhoc; 1790f186073cSJoerg Sonnenberger 1791841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 1792841ab66cSSepherosa Ziehau 1793841ab66cSSepherosa Ziehau isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS || 1794841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO); 1795841ab66cSSepherosa Ziehau 1796841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) { 1797f186073cSJoerg Sonnenberger /* 1798841ab66cSSepherosa Ziehau * Ignore entries for which have yet to receive an 1799841ab66cSSepherosa Ziehau * authentication frame. These are transient and 1800841ab66cSSepherosa Ziehau * will be reclaimed when the last reference to them 1801841ab66cSSepherosa Ziehau * goes away (when frame xmits complete). 1802f186073cSJoerg Sonnenberger */ 1803841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1804841ab66cSSepherosa Ziehau (ni->ni_flags & IEEE80211_NODE_AREF) == 0) 1805841ab66cSSepherosa Ziehau continue; 1806841ab66cSSepherosa Ziehau /* 1807841ab66cSSepherosa Ziehau * Free fragment if not needed anymore 1808841ab66cSSepherosa Ziehau * (last fragment older than 1s). 1809841ab66cSSepherosa Ziehau * XXX doesn't belong here 1810841ab66cSSepherosa Ziehau */ 1811841ab66cSSepherosa Ziehau if (ni->ni_rxfrag[0] != NULL && 1812841ab66cSSepherosa Ziehau ticks > ni->ni_rxfragstamp + hz) { 1813841ab66cSSepherosa Ziehau m_freem(ni->ni_rxfrag[0]); 1814841ab66cSSepherosa Ziehau ni->ni_rxfrag[0] = NULL; 1815841ab66cSSepherosa Ziehau } 1816841ab66cSSepherosa Ziehau /* 1817841ab66cSSepherosa Ziehau * Special case ourself; we may be idle for extended periods 1818841ab66cSSepherosa Ziehau * of time and regardless reclaiming our state is wrong. 1819841ab66cSSepherosa Ziehau */ 1820841ab66cSSepherosa Ziehau if (ni == ic->ic_bss) 1821841ab66cSSepherosa Ziehau continue; 1822841ab66cSSepherosa Ziehau ni->ni_inact--; 1823841ab66cSSepherosa Ziehau if (ni->ni_associd != 0 || isadhoc) { 1824841ab66cSSepherosa Ziehau /* 1825841ab66cSSepherosa Ziehau * Age frames on the power save queue. The 1826841ab66cSSepherosa Ziehau * aging interval is 4 times the listen 1827841ab66cSSepherosa Ziehau * interval specified by the station. This 1828841ab66cSSepherosa Ziehau * number is factored into the age calculations 1829841ab66cSSepherosa Ziehau * when the frame is placed on the queue. We 1830841ab66cSSepherosa Ziehau * store ages as time differences we can check 1831841ab66cSSepherosa Ziehau * and/or adjust only the head of the list. 1832841ab66cSSepherosa Ziehau */ 1833841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) { 1834841ab66cSSepherosa Ziehau struct mbuf *m; 1835841ab66cSSepherosa Ziehau int discard = 0; 1836841ab66cSSepherosa Ziehau 1837841ab66cSSepherosa Ziehau while (IF_POLL(&ni->ni_savedq, m) != NULL && 1838841ab66cSSepherosa Ziehau M_AGE_GET(m) < IEEE80211_INACT_WAIT) { 1839841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1840841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1841841ab66cSSepherosa Ziehau "[%6D] discard frame, age %u\n", 1842841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1843841ab66cSSepherosa Ziehau M_AGE_GET(m));/*XXX*/ 1844841ab66cSSepherosa Ziehau _IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m); 1845841ab66cSSepherosa Ziehau m_freem(m); 1846841ab66cSSepherosa Ziehau discard++; 1847841ab66cSSepherosa Ziehau } 1848841ab66cSSepherosa Ziehau if (m != NULL) 1849841ab66cSSepherosa Ziehau M_AGE_SUB(m, IEEE80211_INACT_WAIT); 1850841ab66cSSepherosa Ziehau 1851841ab66cSSepherosa Ziehau if (discard != 0) { 1852841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 1853841ab66cSSepherosa Ziehau IEEE80211_MSG_POWER, 1854841ab66cSSepherosa Ziehau "[%6D] discard %u frames for age\n", 1855841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", 1856841ab66cSSepherosa Ziehau discard); 1857841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_ADD(ni, 1858841ab66cSSepherosa Ziehau ps_discard, discard); 1859841ab66cSSepherosa Ziehau if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) 1860841ab66cSSepherosa Ziehau ic->ic_set_tim(ni, 0); 1861841ab66cSSepherosa Ziehau } 1862841ab66cSSepherosa Ziehau } 1863841ab66cSSepherosa Ziehau /* 1864841ab66cSSepherosa Ziehau * Probe the station before time it out. We 1865841ab66cSSepherosa Ziehau * send a null data frame which may not be 1866841ab66cSSepherosa Ziehau * universally supported by drivers (need it 1867841ab66cSSepherosa Ziehau * for ps-poll support so it should be...). 1868841ab66cSSepherosa Ziehau */ 1869841ab66cSSepherosa Ziehau if (0 < ni->ni_inact && 1870841ab66cSSepherosa Ziehau ni->ni_inact <= ic->ic_inact_probe) { 1871841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1872841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, 1873841ab66cSSepherosa Ziehau ni, "%s", 1874841ab66cSSepherosa Ziehau "probe station due to inactivity"); 1875841ab66cSSepherosa Ziehau /* 1876841ab66cSSepherosa Ziehau * Grab a reference before unlocking the table 1877841ab66cSSepherosa Ziehau * so the node cannot be reclaimed before we 1878841ab66cSSepherosa Ziehau * send the frame. ieee80211_send_nulldata 1879841ab66cSSepherosa Ziehau * understands we've done this and reclaims the 1880841ab66cSSepherosa Ziehau * ref for us as needed. 1881841ab66cSSepherosa Ziehau */ 1882841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 1883841ab66cSSepherosa Ziehau ieee80211_send_nulldata(ni); 1884841ab66cSSepherosa Ziehau /* XXX stat? */ 1885841ab66cSSepherosa Ziehau continue; 1886841ab66cSSepherosa Ziehau } 1887841ab66cSSepherosa Ziehau } 1888841ab66cSSepherosa Ziehau if (ni->ni_inact <= 0) { 1889841ab66cSSepherosa Ziehau IEEE80211_NOTE(ic, 1890841ab66cSSepherosa Ziehau IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, 1891841ab66cSSepherosa Ziehau "station timed out due to inactivity " 1892841ab66cSSepherosa Ziehau "(refcnt %u)", ieee80211_node_refcnt(ni)); 1893841ab66cSSepherosa Ziehau /* 1894841ab66cSSepherosa Ziehau * Send a deauthenticate frame and drop the station. 1895841ab66cSSepherosa Ziehau * This is somewhat complicated due to reference counts 1896841ab66cSSepherosa Ziehau * and locking. At this point a station will typically 1897841ab66cSSepherosa Ziehau * have a reference count of 1. ieee80211_node_leave 1898841ab66cSSepherosa Ziehau * will do a "free" of the node which will drop the 1899841ab66cSSepherosa Ziehau * reference count. But in the meantime a reference 1900841ab66cSSepherosa Ziehau * wil be held by the deauth frame. The actual reclaim 1901841ab66cSSepherosa Ziehau * of the node will happen either after the tx is 1902841ab66cSSepherosa Ziehau * completed or by ieee80211_node_leave. 1903841ab66cSSepherosa Ziehau */ 1904841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 1905f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1906f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 1907f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_EXPIRE); 1908841ab66cSSepherosa Ziehau } 1909841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 1910f186073cSJoerg Sonnenberger ic->ic_stats.is_node_timeout++; 1911841ab66cSSepherosa Ziehau continue; 1912f186073cSJoerg Sonnenberger } 1913f186073cSJoerg Sonnenberger } 1914841ab66cSSepherosa Ziehau 1915841ab66cSSepherosa Ziehau nt->nt_inact_timer = IEEE80211_INACT_WAIT; 1916f186073cSJoerg Sonnenberger } 1917f186073cSJoerg Sonnenberger 1918f186073cSJoerg Sonnenberger void 1919841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg) 1920f186073cSJoerg Sonnenberger { 1921841ab66cSSepherosa Ziehau struct ieee80211_node *ni, *next; 1922f186073cSJoerg Sonnenberger 1923841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 1924841ab66cSSepherosa Ziehau 1925841ab66cSSepherosa Ziehau TAILQ_FOREACH_MUTABLE(ni, &nt->nt_node, ni_list, next) 1926841ab66cSSepherosa Ziehau f(arg, ni); 1927841ab66cSSepherosa Ziehau } 1928841ab66cSSepherosa Ziehau 1929841ab66cSSepherosa Ziehau void 1930841ab66cSSepherosa Ziehau ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) 1931841ab66cSSepherosa Ziehau { 1932841ab66cSSepherosa Ziehau printf("0x%p: mac %6D refcnt %d\n", ni, 1933841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)); 1934841ab66cSSepherosa Ziehau printf("\tauthmode %u flags 0x%x\n", 1935841ab66cSSepherosa Ziehau ni->ni_authmode, ni->ni_flags); 1936841ab66cSSepherosa Ziehau printf("\tassocid 0x%x txpower %u vlan %u\n", 1937841ab66cSSepherosa Ziehau ni->ni_associd, ni->ni_txpower, ni->ni_vlan); 1938841ab66cSSepherosa Ziehau printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n", 1939841ab66cSSepherosa Ziehau ni->ni_txseqs[0], 1940841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] >> IEEE80211_SEQ_SEQ_SHIFT, 1941841ab66cSSepherosa Ziehau ni->ni_rxseqs[0] & IEEE80211_SEQ_FRAG_MASK, 1942841ab66cSSepherosa Ziehau ni->ni_rxfragstamp); 1943841ab66cSSepherosa Ziehau printf("\trstamp %u rssi %u intval %u capinfo 0x%x\n", 1944841ab66cSSepherosa Ziehau ni->ni_rstamp, ni->ni_rssi, ni->ni_intval, ni->ni_capinfo); 1945841ab66cSSepherosa Ziehau printf("\tbssid %6D essid \"%.*s\" channel %u:0x%x\n", 1946841ab66cSSepherosa Ziehau ni->ni_bssid, ":", 1947841ab66cSSepherosa Ziehau ni->ni_esslen, ni->ni_essid, 1948841ab66cSSepherosa Ziehau ni->ni_chan->ic_freq, ni->ni_chan->ic_flags); 1949841ab66cSSepherosa Ziehau printf("\tfails %u inact %u txrate %u\n", 1950841ab66cSSepherosa Ziehau ni->ni_fails, ni->ni_inact, ni->ni_txrate); 1951841ab66cSSepherosa Ziehau } 1952841ab66cSSepherosa Ziehau 1953841ab66cSSepherosa Ziehau void 1954841ab66cSSepherosa Ziehau ieee80211_dump_nodes(struct ieee80211_node_table *nt) 1955841ab66cSSepherosa Ziehau { 1956841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(nt, 1957841ab66cSSepherosa Ziehau (ieee80211_iter_func *) ieee80211_dump_node, nt); 1958841ab66cSSepherosa Ziehau } 1959841ab66cSSepherosa Ziehau 1960841ab66cSSepherosa Ziehau /* 1961841ab66cSSepherosa Ziehau * Handle a station joining an 11g network. 1962841ab66cSSepherosa Ziehau */ 1963841ab66cSSepherosa Ziehau static void 1964841ab66cSSepherosa Ziehau ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 1965841ab66cSSepherosa Ziehau { 1966841ab66cSSepherosa Ziehau 1967841ab66cSSepherosa Ziehau /* 1968841ab66cSSepherosa Ziehau * Station isn't capable of short slot time. Bump 1969841ab66cSSepherosa Ziehau * the count of long slot time stations and disable 1970841ab66cSSepherosa Ziehau * use of short slot time. Note that the actual switch 1971841ab66cSSepherosa Ziehau * over to long slot time use may not occur until the 1972841ab66cSSepherosa Ziehau * next beacon transmission (per sec. 7.3.1.4 of 11g). 1973841ab66cSSepherosa Ziehau */ 1974841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 1975841ab66cSSepherosa Ziehau ic->ic_longslotsta++; 1976841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1977841ab66cSSepherosa Ziehau "[%6D] station needs long slot time, count %d\n", 1978841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 1979841ab66cSSepherosa Ziehau /* XXX vap's w/ conflicting needs won't work */ 1980841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 0); 1981841ab66cSSepherosa Ziehau } 1982841ab66cSSepherosa Ziehau /* 1983841ab66cSSepherosa Ziehau * If the new station is not an ERP station 1984841ab66cSSepherosa Ziehau * then bump the counter and enable protection 1985841ab66cSSepherosa Ziehau * if configured. 1986841ab66cSSepherosa Ziehau */ 1987841ab66cSSepherosa Ziehau if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) { 1988841ab66cSSepherosa Ziehau ic->ic_nonerpsta++; 1989841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1990841ab66cSSepherosa Ziehau "[%6D] station is !ERP, %d non-ERP stations associated\n", 1991841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 1992841ab66cSSepherosa Ziehau /* 1993841ab66cSSepherosa Ziehau * If protection is configured, enable it. 1994841ab66cSSepherosa Ziehau */ 1995841ab66cSSepherosa Ziehau if (ic->ic_protmode != IEEE80211_PROT_NONE) { 1996841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 1997841ab66cSSepherosa Ziehau "%s: enable use of protection\n", __func__); 1998841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEPROT; 1999841ab66cSSepherosa Ziehau } 2000841ab66cSSepherosa Ziehau /* 2001841ab66cSSepherosa Ziehau * If station does not support short preamble 2002841ab66cSSepherosa Ziehau * then we must enable use of Barker preamble. 2003841ab66cSSepherosa Ziehau */ 2004841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { 2005841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2006841ab66cSSepherosa Ziehau "[%6D] station needs long preamble\n", 2007841ab66cSSepherosa Ziehau ni->ni_macaddr, ":"); 2008841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEBARKER; 2009841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 2010841ab66cSSepherosa Ziehau } 2011841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 1) 2012841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2013841ab66cSSepherosa Ziehau } else 2014841ab66cSSepherosa Ziehau ni->ni_flags |= IEEE80211_NODE_ERP; 2015841ab66cSSepherosa Ziehau } 2016841ab66cSSepherosa Ziehau 2017841ab66cSSepherosa Ziehau void 2018841ab66cSSepherosa Ziehau ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) 2019841ab66cSSepherosa Ziehau { 2020841ab66cSSepherosa Ziehau int newassoc; 2021841ab66cSSepherosa Ziehau 2022841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) { 2023841ab66cSSepherosa Ziehau uint16_t aid; 2024841ab66cSSepherosa Ziehau 2025841ab66cSSepherosa Ziehau /* 2026841ab66cSSepherosa Ziehau * It would be good to search the bitmap 2027841ab66cSSepherosa Ziehau * more efficiently, but this will do for now. 2028841ab66cSSepherosa Ziehau */ 2029841ab66cSSepherosa Ziehau for (aid = 1; aid < ic->ic_max_aid; aid++) { 2030841ab66cSSepherosa Ziehau if (!IEEE80211_AID_ISSET(aid, 2031841ab66cSSepherosa Ziehau ic->ic_aid_bitmap)) 2032841ab66cSSepherosa Ziehau break; 2033841ab66cSSepherosa Ziehau } 2034841ab66cSSepherosa Ziehau if (aid >= ic->ic_max_aid) { 2035841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, 2036841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_TOOMANY); 2037841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 2038841ab66cSSepherosa Ziehau return; 2039841ab66cSSepherosa Ziehau } 2040841ab66cSSepherosa Ziehau ni->ni_associd = aid | 0xc000; 2041841ab66cSSepherosa Ziehau IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); 2042841ab66cSSepherosa Ziehau ic->ic_sta_assoc++; 2043841ab66cSSepherosa Ziehau newassoc = 1; 2044841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2045841ab66cSSepherosa Ziehau ieee80211_node_join_11g(ic, ni); 2046841ab66cSSepherosa Ziehau } else 2047841ab66cSSepherosa Ziehau newassoc = 0; 2048841ab66cSSepherosa Ziehau 2049841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2050841ab66cSSepherosa Ziehau "[%6D] station %sassociated at aid %d: %s preamble, %s slot time%s%s\n", 2051841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", newassoc ? "" : "re", 2052841ab66cSSepherosa Ziehau IEEE80211_NODE_AID(ni), 2053841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", 2054841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", 2055841ab66cSSepherosa Ziehau ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "", 2056841ab66cSSepherosa Ziehau ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "" 2057841ab66cSSepherosa Ziehau ); 2058841ab66cSSepherosa Ziehau 2059b9334f94SSepherosa Ziehau ieee80211_ratectl_newassoc(ni, newassoc); 2060b9334f94SSepherosa Ziehau 2061841ab66cSSepherosa Ziehau /* give driver a chance to setup state like ni_txrate */ 2062841ab66cSSepherosa Ziehau if (ic->ic_newassoc != NULL) 2063841ab66cSSepherosa Ziehau ic->ic_newassoc(ni, newassoc); 2064b9334f94SSepherosa Ziehau 2065841ab66cSSepherosa Ziehau ni->ni_inact_reload = ic->ic_inact_auth; 2066841ab66cSSepherosa Ziehau ni->ni_inact = ni->ni_inact_reload; 2067841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); 2068841ab66cSSepherosa Ziehau /* tell the authenticator about new station */ 2069841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_join != NULL) 2070841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_join(ic, ni); 2071841ab66cSSepherosa Ziehau ieee80211_notify_node_join(ic, ni, newassoc); 2072841ab66cSSepherosa Ziehau } 2073841ab66cSSepherosa Ziehau 2074841ab66cSSepherosa Ziehau /* 2075841ab66cSSepherosa Ziehau * Handle a station leaving an 11g network. 2076841ab66cSSepherosa Ziehau */ 2077841ab66cSSepherosa Ziehau static void 2078841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni) 2079841ab66cSSepherosa Ziehau { 2080841ab66cSSepherosa Ziehau 2081841ab66cSSepherosa Ziehau KASSERT(ic->ic_curmode == IEEE80211_MODE_11G, 2082841ab66cSSepherosa Ziehau ("not in 11g, bss %u:0x%x, curmode %u", ni->ni_chan->ic_freq, 2083841ab66cSSepherosa Ziehau ni->ni_chan->ic_flags, ic->ic_curmode)); 2084841ab66cSSepherosa Ziehau 2085841ab66cSSepherosa Ziehau /* 2086841ab66cSSepherosa Ziehau * If a long slot station do the slot time bookkeeping. 2087841ab66cSSepherosa Ziehau */ 2088841ab66cSSepherosa Ziehau if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { 2089841ab66cSSepherosa Ziehau KASSERT(ic->ic_longslotsta > 0, 2090841ab66cSSepherosa Ziehau ("bogus long slot station count %d", ic->ic_longslotsta)); 2091841ab66cSSepherosa Ziehau ic->ic_longslotsta--; 2092841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2093841ab66cSSepherosa Ziehau "[%6D] long slot time station leaves, count now %d\n", 2094841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_longslotsta); 2095841ab66cSSepherosa Ziehau if (ic->ic_longslotsta == 0) { 2096841ab66cSSepherosa Ziehau /* 2097841ab66cSSepherosa Ziehau * Re-enable use of short slot time if supported 2098841ab66cSSepherosa Ziehau * and not operating in IBSS mode (per spec). 2099841ab66cSSepherosa Ziehau */ 2100841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_SHSLOT) && 2101841ab66cSSepherosa Ziehau ic->ic_opmode != IEEE80211_M_IBSS) { 2102841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2103841ab66cSSepherosa Ziehau "%s: re-enable use of short slot time\n", 2104841ab66cSSepherosa Ziehau __func__); 2105841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 1); 2106841ab66cSSepherosa Ziehau } 2107841ab66cSSepherosa Ziehau } 2108841ab66cSSepherosa Ziehau } 2109841ab66cSSepherosa Ziehau /* 2110841ab66cSSepherosa Ziehau * If a non-ERP station do the protection-related bookkeeping. 2111841ab66cSSepherosa Ziehau */ 2112841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { 2113841ab66cSSepherosa Ziehau KASSERT(ic->ic_nonerpsta > 0, 2114841ab66cSSepherosa Ziehau ("bogus non-ERP station count %d", ic->ic_nonerpsta)); 2115841ab66cSSepherosa Ziehau ic->ic_nonerpsta--; 2116841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2117841ab66cSSepherosa Ziehau "[%6D] non-ERP station leaves, count now %d\n", 2118841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", ic->ic_nonerpsta); 2119841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta == 0) { 2120841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2121841ab66cSSepherosa Ziehau "%s: disable use of protection\n", __func__); 2122841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT; 2123841ab66cSSepherosa Ziehau /* XXX verify mode? */ 2124841ab66cSSepherosa Ziehau if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) { 2125841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, 2126841ab66cSSepherosa Ziehau "%s: re-enable use of short preamble\n", 2127841ab66cSSepherosa Ziehau __func__); 2128841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 2129841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEBARKER; 2130841ab66cSSepherosa Ziehau } 2131841ab66cSSepherosa Ziehau ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; 2132841ab66cSSepherosa Ziehau } 2133841ab66cSSepherosa Ziehau } 2134841ab66cSSepherosa Ziehau } 2135841ab66cSSepherosa Ziehau 2136841ab66cSSepherosa Ziehau /* 2137841ab66cSSepherosa Ziehau * Handle bookkeeping for station deauthentication/disassociation 2138841ab66cSSepherosa Ziehau * when operating as an ap. 2139841ab66cSSepherosa Ziehau */ 2140841ab66cSSepherosa Ziehau void 2141841ab66cSSepherosa Ziehau ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 2142841ab66cSSepherosa Ziehau { 2143841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = ni->ni_table; 2144841ab66cSSepherosa Ziehau 2145841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2146841ab66cSSepherosa Ziehau 2147841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, 2148841ab66cSSepherosa Ziehau "[%6D] station with aid %d leaves\n", 2149841ab66cSSepherosa Ziehau ni->ni_macaddr, ":", IEEE80211_NODE_AID(ni)); 2150841ab66cSSepherosa Ziehau 2151841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2152841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS || 2153841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO, 2154841ab66cSSepherosa Ziehau ("unexpected operating mode %u", ic->ic_opmode)); 2155841ab66cSSepherosa Ziehau /* 2156841ab66cSSepherosa Ziehau * If node wasn't previously associated all 2157841ab66cSSepherosa Ziehau * we need to do is reclaim the reference. 2158841ab66cSSepherosa Ziehau */ 2159841ab66cSSepherosa Ziehau /* XXX ibss mode bypasses 11g and notification */ 2160841ab66cSSepherosa Ziehau if (ni->ni_associd == 0) 2161841ab66cSSepherosa Ziehau goto done; 2162841ab66cSSepherosa Ziehau /* 2163841ab66cSSepherosa Ziehau * Tell the authenticator the station is leaving. 2164841ab66cSSepherosa Ziehau * Note that we must do this before yanking the 2165841ab66cSSepherosa Ziehau * association id as the authenticator uses the 2166841ab66cSSepherosa Ziehau * associd to locate it's state block. 2167841ab66cSSepherosa Ziehau */ 2168841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_node_leave != NULL) 2169841ab66cSSepherosa Ziehau ic->ic_auth->ia_node_leave(ic, ni); 2170841ab66cSSepherosa Ziehau IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); 2171841ab66cSSepherosa Ziehau ni->ni_associd = 0; 2172841ab66cSSepherosa Ziehau ic->ic_sta_assoc--; 2173841ab66cSSepherosa Ziehau 2174841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11G) 2175841ab66cSSepherosa Ziehau ieee80211_node_leave_11g(ic, ni); 2176841ab66cSSepherosa Ziehau /* 2177841ab66cSSepherosa Ziehau * Cleanup station state. In particular clear various 2178841ab66cSSepherosa Ziehau * state that might otherwise be reused if the node 2179841ab66cSSepherosa Ziehau * is reused before the reference count goes to zero 2180841ab66cSSepherosa Ziehau * (and memory is reclaimed). 2181841ab66cSSepherosa Ziehau */ 2182841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 2183841ab66cSSepherosa Ziehau done: 2184841ab66cSSepherosa Ziehau /* 2185841ab66cSSepherosa Ziehau * Remove the node from any table it's recorded in and 2186841ab66cSSepherosa Ziehau * drop the caller's reference. Removal from the table 2187841ab66cSSepherosa Ziehau * is important to insure the node is not reprocessed 2188841ab66cSSepherosa Ziehau * for inactivity. 2189841ab66cSSepherosa Ziehau */ 2190841ab66cSSepherosa Ziehau if (nt != NULL) 2191841ab66cSSepherosa Ziehau node_reclaim(nt, ni); 2192841ab66cSSepherosa Ziehau else 2193841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2194841ab66cSSepherosa Ziehau } 2195841ab66cSSepherosa Ziehau 2196841ab66cSSepherosa Ziehau uint8_t 2197841ab66cSSepherosa Ziehau ieee80211_getrssi(struct ieee80211com *ic) 2198841ab66cSSepherosa Ziehau { 2199841ab66cSSepherosa Ziehau #define NZ(x) ((x) == 0 ? 1 : (x)) 2200841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt = &ic->ic_sta; 2201841ab66cSSepherosa Ziehau uint32_t rssi_samples, rssi_total; 2202841ab66cSSepherosa Ziehau struct ieee80211_node *ni; 2203841ab66cSSepherosa Ziehau 2204841ab66cSSepherosa Ziehau rssi_total = 0; 2205841ab66cSSepherosa Ziehau rssi_samples = 0; 2206841ab66cSSepherosa Ziehau switch (ic->ic_opmode) { 2207841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: /* average of all ibss neighbors */ 2208841ab66cSSepherosa Ziehau /* XXX locking */ 2209841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2210841ab66cSSepherosa Ziehau if (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) { 2211841ab66cSSepherosa Ziehau rssi_samples++; 2212841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2213841ab66cSSepherosa Ziehau } 2214841ab66cSSepherosa Ziehau break; 2215841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: /* average of all neighbors */ 2216841ab66cSSepherosa Ziehau /* XXX locking */ 2217841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 2218841ab66cSSepherosa Ziehau rssi_samples++; 2219841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2220841ab66cSSepherosa Ziehau } 2221841ab66cSSepherosa Ziehau break; 2222841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: /* average of all associated stations */ 2223841ab66cSSepherosa Ziehau /* XXX locking */ 2224841ab66cSSepherosa Ziehau TAILQ_FOREACH(ni, &nt->nt_node, ni_list) 2225841ab66cSSepherosa Ziehau if (IEEE80211_AID(ni->ni_associd) != 0) { 2226841ab66cSSepherosa Ziehau rssi_samples++; 2227841ab66cSSepherosa Ziehau rssi_total += ic->ic_node_getrssi(ni); 2228841ab66cSSepherosa Ziehau } 2229841ab66cSSepherosa Ziehau break; 2230841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* XXX */ 2231841ab66cSSepherosa Ziehau case IEEE80211_M_STA: /* use stats from associated ap */ 2232841ab66cSSepherosa Ziehau default: 2233841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) 2234841ab66cSSepherosa Ziehau rssi_total = ic->ic_node_getrssi(ic->ic_bss); 2235841ab66cSSepherosa Ziehau rssi_samples = 1; 2236841ab66cSSepherosa Ziehau break; 2237841ab66cSSepherosa Ziehau } 2238841ab66cSSepherosa Ziehau return rssi_total / NZ(rssi_samples); 2239841ab66cSSepherosa Ziehau #undef NZ 2240841ab66cSSepherosa Ziehau } 2241841ab66cSSepherosa Ziehau 2242841ab66cSSepherosa Ziehau /* 2243841ab66cSSepherosa Ziehau * Indicate whether there are frames queued for a station in power-save mode. 2244841ab66cSSepherosa Ziehau */ 2245841ab66cSSepherosa Ziehau static void 2246841ab66cSSepherosa Ziehau ieee80211_set_tim(struct ieee80211_node *ni, int set) 2247841ab66cSSepherosa Ziehau { 2248841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 2249841ab66cSSepherosa Ziehau uint16_t aid; 2250841ab66cSSepherosa Ziehau 2251841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 2252841ab66cSSepherosa Ziehau 2253841ab66cSSepherosa Ziehau KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || 2254841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS, 2255841ab66cSSepherosa Ziehau ("operating mode %u", ic->ic_opmode)); 2256841ab66cSSepherosa Ziehau 2257841ab66cSSepherosa Ziehau aid = IEEE80211_AID(ni->ni_associd); 2258841ab66cSSepherosa Ziehau KASSERT(aid < ic->ic_max_aid, 2259841ab66cSSepherosa Ziehau ("bogus aid %u, max %u", aid, ic->ic_max_aid)); 2260841ab66cSSepherosa Ziehau 2261841ab66cSSepherosa Ziehau if (set != (isset(ic->ic_tim_bitmap, aid) != 0)) { 2262841ab66cSSepherosa Ziehau if (set) { 2263841ab66cSSepherosa Ziehau setbit(ic->ic_tim_bitmap, aid); 2264841ab66cSSepherosa Ziehau ic->ic_ps_pending++; 2265841ab66cSSepherosa Ziehau } else { 2266841ab66cSSepherosa Ziehau clrbit(ic->ic_tim_bitmap, aid); 2267841ab66cSSepherosa Ziehau ic->ic_ps_pending--; 2268841ab66cSSepherosa Ziehau } 2269841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_TIMUPDATE; 2270841ab66cSSepherosa Ziehau } 2271841ab66cSSepherosa Ziehau } 2272841ab66cSSepherosa Ziehau 2273841ab66cSSepherosa Ziehau /* 2274841ab66cSSepherosa Ziehau * Node table support. 2275841ab66cSSepherosa Ziehau */ 2276841ab66cSSepherosa Ziehau 2277841ab66cSSepherosa Ziehau static void 2278841ab66cSSepherosa Ziehau ieee80211_node_table_init(struct ieee80211com *ic, 2279841ab66cSSepherosa Ziehau struct ieee80211_node_table *nt, 2280841ab66cSSepherosa Ziehau const char *name, int inact, int keyixmax, 2281841ab66cSSepherosa Ziehau void (*timeout)(struct ieee80211_node_table *)) 2282841ab66cSSepherosa Ziehau { 2283841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, 2284841ab66cSSepherosa Ziehau "%s %s table, inact %u\n", __func__, name, inact); 2285841ab66cSSepherosa Ziehau 2286841ab66cSSepherosa Ziehau nt->nt_ic = ic; 2287841ab66cSSepherosa Ziehau TAILQ_INIT(&nt->nt_node); 2288841ab66cSSepherosa Ziehau nt->nt_name = name; 2289841ab66cSSepherosa Ziehau nt->nt_inact_init = inact; 2290841ab66cSSepherosa Ziehau nt->nt_timeout = timeout; 2291841ab66cSSepherosa Ziehau nt->nt_keyixmax = keyixmax; 2292841ab66cSSepherosa Ziehau if (nt->nt_keyixmax > 0) { 2293841ab66cSSepherosa Ziehau nt->nt_keyixmap = 2294*77652cadSMatthew Dillon kmalloc(keyixmax * sizeof(struct ieee80211_node *), 2295841ab66cSSepherosa Ziehau M_80211_NODE, M_WAITOK | M_ZERO); 2296841ab66cSSepherosa Ziehau } else { 2297841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2298841ab66cSSepherosa Ziehau } 2299841ab66cSSepherosa Ziehau } 2300841ab66cSSepherosa Ziehau 2301841ab66cSSepherosa Ziehau void 2302841ab66cSSepherosa Ziehau ieee80211_node_table_reset(struct ieee80211_node_table *nt) 2303841ab66cSSepherosa Ziehau { 2304841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2305841ab66cSSepherosa Ziehau 2306841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2307841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2308841ab66cSSepherosa Ziehau 2309841ab66cSSepherosa Ziehau nt->nt_inact_timer = 0; 2310841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2311841ab66cSSepherosa Ziehau } 2312841ab66cSSepherosa Ziehau 2313841ab66cSSepherosa Ziehau static void 2314841ab66cSSepherosa Ziehau ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) 2315841ab66cSSepherosa Ziehau { 2316841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(nt->nt_ic->ic_ifp->if_serializer); 2317841ab66cSSepherosa Ziehau 2318841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE, 2319841ab66cSSepherosa Ziehau "%s %s table\n", __func__, nt->nt_name); 2320841ab66cSSepherosa Ziehau 2321841ab66cSSepherosa Ziehau ieee80211_free_allnodes(nt); 2322841ab66cSSepherosa Ziehau if (nt->nt_keyixmap != NULL) { 2323841ab66cSSepherosa Ziehau /* XXX verify all entries are NULL */ 2324841ab66cSSepherosa Ziehau int i; 2325841ab66cSSepherosa Ziehau for (i = 0; i < nt->nt_keyixmax; i++) 2326841ab66cSSepherosa Ziehau if (nt->nt_keyixmap[i] != NULL) { 2327841ab66cSSepherosa Ziehau printf("%s: %s[%u] still active\n", __func__, 2328841ab66cSSepherosa Ziehau nt->nt_name, i); 2329841ab66cSSepherosa Ziehau } 2330efda3bd0SMatthew Dillon kfree(nt->nt_keyixmap, M_80211_NODE); 2331841ab66cSSepherosa Ziehau nt->nt_keyixmap = NULL; 2332841ab66cSSepherosa Ziehau } 2333f186073cSJoerg Sonnenberger } 2334