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_proto.c,v 1.17.2.9 2006/03/13 03:10:31 sam Exp $ 33*a6ec04bcSSascha Wildner * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_proto.c,v 1.6 2006/12/22 23:57:53 swildner Exp $ 34f186073cSJoerg Sonnenberger */ 35f186073cSJoerg Sonnenberger 36f186073cSJoerg Sonnenberger /* 37f186073cSJoerg Sonnenberger * IEEE 802.11 protocol support. 38f186073cSJoerg Sonnenberger */ 39f186073cSJoerg Sonnenberger 40f186073cSJoerg Sonnenberger #include "opt_inet.h" 41f186073cSJoerg Sonnenberger 42f186073cSJoerg Sonnenberger #include <sys/param.h> 43f186073cSJoerg Sonnenberger #include <sys/kernel.h> 44841ab66cSSepherosa Ziehau #include <sys/systm.h> 45841ab66cSSepherosa Ziehau #include <sys/serialize.h> 46f186073cSJoerg Sonnenberger 47841ab66cSSepherosa Ziehau #include <sys/socket.h> 48f186073cSJoerg Sonnenberger 49f186073cSJoerg Sonnenberger #include <net/if.h> 50f186073cSJoerg Sonnenberger #include <net/if_arp.h> 51841ab66cSSepherosa Ziehau #include <net/if_media.h> 52841ab66cSSepherosa Ziehau #include <net/ethernet.h> /* XXX for ether_sprintf */ 53f186073cSJoerg Sonnenberger 54f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h> 55f186073cSJoerg Sonnenberger 56841ab66cSSepherosa Ziehau /* XXX tunables */ 57841ab66cSSepherosa Ziehau #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */ 58841ab66cSSepherosa Ziehau #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */ 59f186073cSJoerg Sonnenberger 60f186073cSJoerg Sonnenberger #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 61f186073cSJoerg Sonnenberger 62f186073cSJoerg Sonnenberger const char *ieee80211_mgt_subtype_name[] = { 63f186073cSJoerg Sonnenberger "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 64f186073cSJoerg Sonnenberger "probe_req", "probe_resp", "reserved#6", "reserved#7", 65f186073cSJoerg Sonnenberger "beacon", "atim", "disassoc", "auth", 66f186073cSJoerg Sonnenberger "deauth", "reserved#13", "reserved#14", "reserved#15" 67f186073cSJoerg Sonnenberger }; 68841ab66cSSepherosa Ziehau const char *ieee80211_ctl_subtype_name[] = { 69841ab66cSSepherosa Ziehau "reserved#0", "reserved#1", "reserved#2", "reserved#3", 70841ab66cSSepherosa Ziehau "reserved#3", "reserved#5", "reserved#6", "reserved#7", 71841ab66cSSepherosa Ziehau "reserved#8", "reserved#9", "ps_poll", "rts", 72841ab66cSSepherosa Ziehau "cts", "ack", "cf_end", "cf_end_ack" 73841ab66cSSepherosa Ziehau }; 74f186073cSJoerg Sonnenberger const char *ieee80211_state_name[IEEE80211_S_MAX] = { 75f186073cSJoerg Sonnenberger "INIT", /* IEEE80211_S_INIT */ 76f186073cSJoerg Sonnenberger "SCAN", /* IEEE80211_S_SCAN */ 77f186073cSJoerg Sonnenberger "AUTH", /* IEEE80211_S_AUTH */ 78f186073cSJoerg Sonnenberger "ASSOC", /* IEEE80211_S_ASSOC */ 79f186073cSJoerg Sonnenberger "RUN" /* IEEE80211_S_RUN */ 80f186073cSJoerg Sonnenberger }; 81841ab66cSSepherosa Ziehau const char *ieee80211_wme_acnames[] = { 82841ab66cSSepherosa Ziehau "WME_AC_BE", 83841ab66cSSepherosa Ziehau "WME_AC_BK", 84841ab66cSSepherosa Ziehau "WME_AC_VI", 85841ab66cSSepherosa Ziehau "WME_AC_VO", 86841ab66cSSepherosa Ziehau "WME_UPSD", 87841ab66cSSepherosa Ziehau }; 88f186073cSJoerg Sonnenberger 89f186073cSJoerg Sonnenberger static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 90f186073cSJoerg Sonnenberger 91f186073cSJoerg Sonnenberger void 92841ab66cSSepherosa Ziehau ieee80211_proto_attach(struct ieee80211com *ic) 93f186073cSJoerg Sonnenberger { 94841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 95f186073cSJoerg Sonnenberger 96841ab66cSSepherosa Ziehau /* XXX room for crypto */ 97841ab66cSSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4); 98f186073cSJoerg Sonnenberger 99f186073cSJoerg Sonnenberger ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 100841ab66cSSepherosa Ziehau ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT; 101841ab66cSSepherosa Ziehau ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 102841ab66cSSepherosa Ziehau ic->ic_bmiss_max = IEEE80211_BMISS_MAX; 103841ab66cSSepherosa Ziehau callout_init(&ic->ic_swbmiss); 104841ab66cSSepherosa Ziehau ic->ic_mcast_rate = IEEE80211_MCAST_RATE_DEFAULT; 105f186073cSJoerg Sonnenberger ic->ic_protmode = IEEE80211_PROT_CTSONLY; 106841ab66cSSepherosa Ziehau ic->ic_roaming = IEEE80211_ROAMING_AUTO; 107841ab66cSSepherosa Ziehau 108841ab66cSSepherosa Ziehau ic->ic_wme.wme_hipri_switch_hysteresis = 109841ab66cSSepherosa Ziehau AGGRESSIVE_MODE_SWITCH_HYSTERESIS; 110f186073cSJoerg Sonnenberger 111f186073cSJoerg Sonnenberger /* protocol state change handler */ 112f186073cSJoerg Sonnenberger ic->ic_newstate = ieee80211_newstate; 113f186073cSJoerg Sonnenberger 114f186073cSJoerg Sonnenberger /* initialize management frame handlers */ 115f186073cSJoerg Sonnenberger ic->ic_recv_mgmt = ieee80211_recv_mgmt; 116f186073cSJoerg Sonnenberger ic->ic_send_mgmt = ieee80211_send_mgmt; 117f186073cSJoerg Sonnenberger } 118f186073cSJoerg Sonnenberger 119f186073cSJoerg Sonnenberger void 120841ab66cSSepherosa Ziehau ieee80211_proto_detach(struct ieee80211com *ic) 121f186073cSJoerg Sonnenberger { 122841ab66cSSepherosa Ziehau 123841ab66cSSepherosa Ziehau /* 124841ab66cSSepherosa Ziehau * This should not be needed as we detach when reseting 125841ab66cSSepherosa Ziehau * the state but be conservative here since the 126841ab66cSSepherosa Ziehau * authenticator may do things like spawn kernel threads. 127841ab66cSSepherosa Ziehau */ 128841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_detach) 129841ab66cSSepherosa Ziehau ic->ic_auth->ia_detach(ic); 130f186073cSJoerg Sonnenberger 131f186073cSJoerg Sonnenberger IF_DRAIN(&ic->ic_mgtq); 132841ab66cSSepherosa Ziehau 133841ab66cSSepherosa Ziehau /* 134841ab66cSSepherosa Ziehau * Detach any ACL'ator. 135841ab66cSSepherosa Ziehau */ 136841ab66cSSepherosa Ziehau if (ic->ic_acl != NULL) 137841ab66cSSepherosa Ziehau ic->ic_acl->iac_detach(ic); 138841ab66cSSepherosa Ziehau } 139841ab66cSSepherosa Ziehau 140841ab66cSSepherosa Ziehau /* 141841ab66cSSepherosa Ziehau * Simple-minded authenticator module support. 142841ab66cSSepherosa Ziehau */ 143841ab66cSSepherosa Ziehau 144841ab66cSSepherosa Ziehau #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1) 145841ab66cSSepherosa Ziehau /* XXX well-known names */ 146841ab66cSSepherosa Ziehau static const char *auth_modnames[IEEE80211_AUTH_MAX] = { 147841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_NONE */ 148841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_OPEN */ 149841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_SHARED */ 150841ab66cSSepherosa Ziehau "wlan_xauth", /* IEEE80211_AUTH_8021X */ 151841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_AUTO */ 152841ab66cSSepherosa Ziehau "wlan_xauth", /* IEEE80211_AUTH_WPA */ 153841ab66cSSepherosa Ziehau }; 154841ab66cSSepherosa Ziehau static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX]; 155841ab66cSSepherosa Ziehau 156841ab66cSSepherosa Ziehau static const struct ieee80211_authenticator auth_internal = { 157841ab66cSSepherosa Ziehau .ia_name = "wlan_internal", 158841ab66cSSepherosa Ziehau .ia_attach = NULL, 159841ab66cSSepherosa Ziehau .ia_detach = NULL, 160841ab66cSSepherosa Ziehau .ia_node_join = NULL, 161841ab66cSSepherosa Ziehau .ia_node_leave = NULL, 162841ab66cSSepherosa Ziehau }; 163841ab66cSSepherosa Ziehau 164841ab66cSSepherosa Ziehau /* 165841ab66cSSepherosa Ziehau * Setup internal authenticators once; they are never unregistered. 166841ab66cSSepherosa Ziehau */ 167841ab66cSSepherosa Ziehau static void 168841ab66cSSepherosa Ziehau ieee80211_auth_setup(void) 169841ab66cSSepherosa Ziehau { 170841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal); 171841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal); 172841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal); 173841ab66cSSepherosa Ziehau } 174841ab66cSSepherosa Ziehau SYSINIT(wlan_auth, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_auth_setup, NULL); 175841ab66cSSepherosa Ziehau 176841ab66cSSepherosa Ziehau const struct ieee80211_authenticator * 177841ab66cSSepherosa Ziehau ieee80211_authenticator_get(int auth) 178841ab66cSSepherosa Ziehau { 179841ab66cSSepherosa Ziehau if (auth >= IEEE80211_AUTH_MAX) 180841ab66cSSepherosa Ziehau return NULL; 181841ab66cSSepherosa Ziehau if (authenticators[auth] == NULL) 182841ab66cSSepherosa Ziehau ieee80211_load_module(auth_modnames[auth]); 183841ab66cSSepherosa Ziehau return authenticators[auth]; 184f186073cSJoerg Sonnenberger } 185f186073cSJoerg Sonnenberger 186f186073cSJoerg Sonnenberger void 187841ab66cSSepherosa Ziehau ieee80211_authenticator_register(int type, 188841ab66cSSepherosa Ziehau const struct ieee80211_authenticator *auth) 189f186073cSJoerg Sonnenberger { 190841ab66cSSepherosa Ziehau if (type >= IEEE80211_AUTH_MAX) 191841ab66cSSepherosa Ziehau return; 192841ab66cSSepherosa Ziehau authenticators[type] = auth; 193841ab66cSSepherosa Ziehau } 194841ab66cSSepherosa Ziehau 195841ab66cSSepherosa Ziehau void 196841ab66cSSepherosa Ziehau ieee80211_authenticator_unregister(int type) 197841ab66cSSepherosa Ziehau { 198841ab66cSSepherosa Ziehau 199841ab66cSSepherosa Ziehau if (type >= IEEE80211_AUTH_MAX) 200841ab66cSSepherosa Ziehau return; 201841ab66cSSepherosa Ziehau authenticators[type] = NULL; 202841ab66cSSepherosa Ziehau } 203841ab66cSSepherosa Ziehau 204841ab66cSSepherosa Ziehau /* 205841ab66cSSepherosa Ziehau * Very simple-minded ACL module support. 206841ab66cSSepherosa Ziehau */ 207841ab66cSSepherosa Ziehau /* XXX just one for now */ 208841ab66cSSepherosa Ziehau static const struct ieee80211_aclator *acl = NULL; 209841ab66cSSepherosa Ziehau 210841ab66cSSepherosa Ziehau void 211841ab66cSSepherosa Ziehau ieee80211_aclator_register(const struct ieee80211_aclator *iac) 212841ab66cSSepherosa Ziehau { 213*a6ec04bcSSascha Wildner kprintf("wlan: %s acl policy registered\n", iac->iac_name); 214841ab66cSSepherosa Ziehau acl = iac; 215841ab66cSSepherosa Ziehau } 216841ab66cSSepherosa Ziehau 217841ab66cSSepherosa Ziehau void 218841ab66cSSepherosa Ziehau ieee80211_aclator_unregister(const struct ieee80211_aclator *iac) 219841ab66cSSepherosa Ziehau { 220841ab66cSSepherosa Ziehau if (acl == iac) 221841ab66cSSepherosa Ziehau acl = NULL; 222*a6ec04bcSSascha Wildner kprintf("wlan: %s acl policy unregistered\n", iac->iac_name); 223841ab66cSSepherosa Ziehau } 224841ab66cSSepherosa Ziehau 225841ab66cSSepherosa Ziehau const struct ieee80211_aclator * 226841ab66cSSepherosa Ziehau ieee80211_aclator_get(const char *name) 227841ab66cSSepherosa Ziehau { 228841ab66cSSepherosa Ziehau if (acl == NULL) 229841ab66cSSepherosa Ziehau ieee80211_load_module("wlan_acl"); 230841ab66cSSepherosa Ziehau return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL; 231841ab66cSSepherosa Ziehau } 232841ab66cSSepherosa Ziehau 233841ab66cSSepherosa Ziehau void 234841ab66cSSepherosa Ziehau ieee80211_print_essid(const uint8_t *essid, int len) 235841ab66cSSepherosa Ziehau { 236841ab66cSSepherosa Ziehau const uint8_t *p; 237f186073cSJoerg Sonnenberger int i; 238f186073cSJoerg Sonnenberger 239f186073cSJoerg Sonnenberger if (len > IEEE80211_NWID_LEN) 240f186073cSJoerg Sonnenberger len = IEEE80211_NWID_LEN; 241f186073cSJoerg Sonnenberger /* determine printable or not */ 242f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) { 243f186073cSJoerg Sonnenberger if (*p < ' ' || *p > 0x7e) 244f186073cSJoerg Sonnenberger break; 245f186073cSJoerg Sonnenberger } 246f186073cSJoerg Sonnenberger if (i == len) { 247*a6ec04bcSSascha Wildner kprintf("\""); 248f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) 249*a6ec04bcSSascha Wildner kprintf("%c", *p); 250*a6ec04bcSSascha Wildner kprintf("\""); 251f186073cSJoerg Sonnenberger } else { 252*a6ec04bcSSascha Wildner kprintf("0x"); 253f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) 254*a6ec04bcSSascha Wildner kprintf("%02x", *p); 255f186073cSJoerg Sonnenberger } 256f186073cSJoerg Sonnenberger } 257f186073cSJoerg Sonnenberger 258f186073cSJoerg Sonnenberger void 259476d885dSSepherosa Ziehau ieee80211_print_rateset(const struct ieee80211_rateset *rs) 260476d885dSSepherosa Ziehau { 261476d885dSSepherosa Ziehau int i; 262476d885dSSepherosa Ziehau 263476d885dSSepherosa Ziehau for (i = 0; i < rs->rs_nrates; ++i) { 264*a6ec04bcSSascha Wildner kprintf("%d%s ", IEEE80211_RS_RATE(rs, i), 265476d885dSSepherosa Ziehau (rs->rs_rates[i] & IEEE80211_RATE_BASIC) ? "*" : ""); 266476d885dSSepherosa Ziehau } 267476d885dSSepherosa Ziehau } 268476d885dSSepherosa Ziehau 269476d885dSSepherosa Ziehau void 270841ab66cSSepherosa Ziehau ieee80211_dump_pkt(const uint8_t *buf, int len, int rate, int rssi) 271f186073cSJoerg Sonnenberger { 272841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh; 273f186073cSJoerg Sonnenberger int i; 274f186073cSJoerg Sonnenberger 275841ab66cSSepherosa Ziehau wh = (const struct ieee80211_frame *)buf; 276f186073cSJoerg Sonnenberger switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 277f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_NODS: 278*a6ec04bcSSascha Wildner kprintf("NODS %6D", wh->i_addr2, ":"); 279*a6ec04bcSSascha Wildner kprintf("->%6D", wh->i_addr1, ":"); 280*a6ec04bcSSascha Wildner kprintf("(%6D)", wh->i_addr3, ":"); 281f186073cSJoerg Sonnenberger break; 282f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_TODS: 283*a6ec04bcSSascha Wildner kprintf("TODS %6D", wh->i_addr2, ":"); 284*a6ec04bcSSascha Wildner kprintf("->%6D", wh->i_addr3, ":"); 285*a6ec04bcSSascha Wildner kprintf("(%6D)", wh->i_addr1, ":"); 286f186073cSJoerg Sonnenberger break; 287f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_FROMDS: 288*a6ec04bcSSascha Wildner kprintf("FRDS %6D", wh->i_addr3, ":"); 289*a6ec04bcSSascha Wildner kprintf("->%6D", wh->i_addr1, ":"); 290*a6ec04bcSSascha Wildner kprintf("(%6D)", wh->i_addr2, ":"); 291f186073cSJoerg Sonnenberger break; 292f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_DSTODS: 293*a6ec04bcSSascha Wildner kprintf("DSDS %6D", (const uint8_t *)&wh[1], ":"); 294*a6ec04bcSSascha Wildner kprintf("->%6D", wh->i_addr3, ":"); 295*a6ec04bcSSascha Wildner kprintf("(%6D", wh->i_addr2, ":"); 296*a6ec04bcSSascha Wildner kprintf("->%6D)", wh->i_addr1, ":"); 297f186073cSJoerg Sonnenberger break; 298f186073cSJoerg Sonnenberger } 299f186073cSJoerg Sonnenberger switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 300f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_DATA: 301*a6ec04bcSSascha Wildner kprintf(" data"); 302f186073cSJoerg Sonnenberger break; 303f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_MGT: 304*a6ec04bcSSascha Wildner kprintf(" %s", ieee80211_mgt_subtype_name[ 305f186073cSJoerg Sonnenberger (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 306f186073cSJoerg Sonnenberger >> IEEE80211_FC0_SUBTYPE_SHIFT]); 307f186073cSJoerg Sonnenberger break; 308f186073cSJoerg Sonnenberger default: 309*a6ec04bcSSascha Wildner kprintf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 310f186073cSJoerg Sonnenberger break; 311f186073cSJoerg Sonnenberger } 312841ab66cSSepherosa Ziehau if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 313841ab66cSSepherosa Ziehau int i; 314*a6ec04bcSSascha Wildner kprintf(" WEP [IV"); 315841ab66cSSepherosa Ziehau for (i = 0; i < IEEE80211_WEP_IVLEN; i++) 316*a6ec04bcSSascha Wildner kprintf(" %.02x", buf[sizeof(*wh)+i]); 317*a6ec04bcSSascha Wildner kprintf(" KID %u]", buf[sizeof(*wh)+i] >> 6); 318841ab66cSSepherosa Ziehau } 319f186073cSJoerg Sonnenberger if (rate >= 0) 320*a6ec04bcSSascha Wildner kprintf(" %dM", rate / 2); 321f186073cSJoerg Sonnenberger if (rssi >= 0) 322*a6ec04bcSSascha Wildner kprintf(" +%d", rssi); 323*a6ec04bcSSascha Wildner kprintf("\n"); 324f186073cSJoerg Sonnenberger if (len > 0) { 325f186073cSJoerg Sonnenberger for (i = 0; i < len; i++) { 326f186073cSJoerg Sonnenberger if ((i & 1) == 0) 327*a6ec04bcSSascha Wildner kprintf(" "); 328*a6ec04bcSSascha Wildner kprintf("%02x", buf[i]); 329f186073cSJoerg Sonnenberger } 330*a6ec04bcSSascha Wildner kprintf("\n"); 331f186073cSJoerg Sonnenberger } 332f186073cSJoerg Sonnenberger } 333f186073cSJoerg Sonnenberger 334f186073cSJoerg Sonnenberger int 335841ab66cSSepherosa Ziehau ieee80211_fix_rate(struct ieee80211_node *ni, int flags) 336f186073cSJoerg Sonnenberger { 337f186073cSJoerg Sonnenberger #define RV(v) ((v) & IEEE80211_RATE_VAL) 338841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 339f186073cSJoerg Sonnenberger int i, j, ignore, error; 340841ab66cSSepherosa Ziehau int okrate, badrate, fixedrate; 341f186073cSJoerg Sonnenberger struct ieee80211_rateset *srs, *nrs; 342f186073cSJoerg Sonnenberger uint8_t r; 343f186073cSJoerg Sonnenberger 344841ab66cSSepherosa Ziehau /* 345841ab66cSSepherosa Ziehau * If the fixed rate check was requested but no 346841ab66cSSepherosa Ziehau * fixed has been defined then just remove it. 347841ab66cSSepherosa Ziehau */ 348841ab66cSSepherosa Ziehau if ((flags & IEEE80211_F_DOFRATE) && 349841ab66cSSepherosa Ziehau ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) 350841ab66cSSepherosa Ziehau flags &= ~IEEE80211_F_DOFRATE; 351f186073cSJoerg Sonnenberger error = 0; 352841ab66cSSepherosa Ziehau okrate = badrate = fixedrate = 0; 353f186073cSJoerg Sonnenberger srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 354f186073cSJoerg Sonnenberger nrs = &ni->ni_rates; 355f186073cSJoerg Sonnenberger for (i = 0; i < nrs->rs_nrates; ) { 356f186073cSJoerg Sonnenberger ignore = 0; 357f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOSORT) { 358f186073cSJoerg Sonnenberger /* 359f186073cSJoerg Sonnenberger * Sort rates. 360f186073cSJoerg Sonnenberger */ 361f186073cSJoerg Sonnenberger for (j = i + 1; j < nrs->rs_nrates; j++) { 362f186073cSJoerg Sonnenberger if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 363f186073cSJoerg Sonnenberger r = nrs->rs_rates[i]; 364f186073cSJoerg Sonnenberger nrs->rs_rates[i] = nrs->rs_rates[j]; 365f186073cSJoerg Sonnenberger nrs->rs_rates[j] = r; 366f186073cSJoerg Sonnenberger } 367f186073cSJoerg Sonnenberger } 368f186073cSJoerg Sonnenberger } 369f186073cSJoerg Sonnenberger r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 370f186073cSJoerg Sonnenberger badrate = r; 371f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOFRATE) { 372f186073cSJoerg Sonnenberger /* 373841ab66cSSepherosa Ziehau * Check any fixed rate is included. 374f186073cSJoerg Sonnenberger */ 375841ab66cSSepherosa Ziehau if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) 376841ab66cSSepherosa Ziehau fixedrate = r; 377f186073cSJoerg Sonnenberger } 378f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DONEGO) { 379f186073cSJoerg Sonnenberger /* 380f186073cSJoerg Sonnenberger * Check against supported rates. 381f186073cSJoerg Sonnenberger */ 382f186073cSJoerg Sonnenberger for (j = 0; j < srs->rs_nrates; j++) { 383f186073cSJoerg Sonnenberger if (r == RV(srs->rs_rates[j])) { 384f186073cSJoerg Sonnenberger /* 385f186073cSJoerg Sonnenberger * Overwrite with the supported rate 386f186073cSJoerg Sonnenberger * value so any basic rate bit is set. 387f186073cSJoerg Sonnenberger * This insures that response we send 388f186073cSJoerg Sonnenberger * to stations have the necessary basic 389f186073cSJoerg Sonnenberger * rate bit set. 390f186073cSJoerg Sonnenberger */ 391f186073cSJoerg Sonnenberger nrs->rs_rates[i] = srs->rs_rates[j]; 392f186073cSJoerg Sonnenberger break; 393f186073cSJoerg Sonnenberger } 394f186073cSJoerg Sonnenberger } 395f186073cSJoerg Sonnenberger if (j == srs->rs_nrates) { 396f186073cSJoerg Sonnenberger /* 397f186073cSJoerg Sonnenberger * A rate in the node's rate set is not 398f186073cSJoerg Sonnenberger * supported. If this is a basic rate and we 399f186073cSJoerg Sonnenberger * are operating as an AP then this is an error. 400f186073cSJoerg Sonnenberger * Otherwise we just discard/ignore the rate. 401f186073cSJoerg Sonnenberger * Note that this is important for 11b stations 402f186073cSJoerg Sonnenberger * when they want to associate with an 11g AP. 403f186073cSJoerg Sonnenberger */ 404f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP && 405f186073cSJoerg Sonnenberger (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 406f186073cSJoerg Sonnenberger error++; 407f186073cSJoerg Sonnenberger ignore++; 408f186073cSJoerg Sonnenberger } 409f186073cSJoerg Sonnenberger } 410f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DODEL) { 411f186073cSJoerg Sonnenberger /* 412f186073cSJoerg Sonnenberger * Delete unacceptable rates. 413f186073cSJoerg Sonnenberger */ 414f186073cSJoerg Sonnenberger if (ignore) { 415f186073cSJoerg Sonnenberger nrs->rs_nrates--; 416f186073cSJoerg Sonnenberger for (j = i; j < nrs->rs_nrates; j++) 417f186073cSJoerg Sonnenberger nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 418f186073cSJoerg Sonnenberger nrs->rs_rates[j] = 0; 419f186073cSJoerg Sonnenberger continue; 420f186073cSJoerg Sonnenberger } 421f186073cSJoerg Sonnenberger } 422f186073cSJoerg Sonnenberger if (!ignore) 423f186073cSJoerg Sonnenberger okrate = nrs->rs_rates[i]; 424f186073cSJoerg Sonnenberger i++; 425f186073cSJoerg Sonnenberger } 426841ab66cSSepherosa Ziehau if (okrate == 0 || error != 0 || 427841ab66cSSepherosa Ziehau ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) 428f186073cSJoerg Sonnenberger return badrate | IEEE80211_RATE_BASIC; 429f186073cSJoerg Sonnenberger else 430f186073cSJoerg Sonnenberger return RV(okrate); 431f186073cSJoerg Sonnenberger #undef RV 432f186073cSJoerg Sonnenberger } 433f186073cSJoerg Sonnenberger 434841ab66cSSepherosa Ziehau /* 435841ab66cSSepherosa Ziehau * Reset 11g-related state. 436841ab66cSSepherosa Ziehau */ 437841ab66cSSepherosa Ziehau void 438841ab66cSSepherosa Ziehau ieee80211_reset_erp(struct ieee80211com *ic) 439f186073cSJoerg Sonnenberger { 440841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT; 441841ab66cSSepherosa Ziehau ic->ic_nonerpsta = 0; 442841ab66cSSepherosa Ziehau ic->ic_longslotsta = 0; 443841ab66cSSepherosa Ziehau /* 444841ab66cSSepherosa Ziehau * Short slot time is enabled only when operating in 11g 445841ab66cSSepherosa Ziehau * and not in an IBSS. We must also honor whether or not 446841ab66cSSepherosa Ziehau * the driver is capable of doing it. 447841ab66cSSepherosa Ziehau */ 448841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 449841ab66cSSepherosa Ziehau ic->ic_curmode == IEEE80211_MODE_11A || 450841ab66cSSepherosa Ziehau (ic->ic_curmode == IEEE80211_MODE_11G && 451841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_HOSTAP && 452841ab66cSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHSLOT))); 453841ab66cSSepherosa Ziehau /* 454841ab66cSSepherosa Ziehau * Set short preamble and ERP barker-preamble flags. 455841ab66cSSepherosa Ziehau */ 456ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(ic, 457ab0665aaSSepherosa Ziehau ic->ic_curmode == IEEE80211_MODE_11A || 458ab0665aaSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHPREAMBLE)); 459841ab66cSSepherosa Ziehau } 460841ab66cSSepherosa Ziehau 461841ab66cSSepherosa Ziehau /* 462841ab66cSSepherosa Ziehau * Set the short slot time state and notify the driver. 463841ab66cSSepherosa Ziehau */ 464841ab66cSSepherosa Ziehau void 465841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff) 466841ab66cSSepherosa Ziehau { 467841ab66cSSepherosa Ziehau if (onoff) 468841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHSLOT; 469841ab66cSSepherosa Ziehau else 470841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHSLOT; 471da9c2b36SSepherosa Ziehau 472da9c2b36SSepherosa Ziehau /* Notify driver */ 473841ab66cSSepherosa Ziehau if (ic->ic_updateslot != NULL) 474841ab66cSSepherosa Ziehau ic->ic_updateslot(ic->ic_ifp); 475841ab66cSSepherosa Ziehau } 476841ab66cSSepherosa Ziehau 477841ab66cSSepherosa Ziehau /* 478da9c2b36SSepherosa Ziehau * Set the short preamble state and notify driver. 479da9c2b36SSepherosa Ziehau */ 480da9c2b36SSepherosa Ziehau void 481ab0665aaSSepherosa Ziehau ieee80211_set_shortpreamble(struct ieee80211com *ic, int onoff) 482da9c2b36SSepherosa Ziehau { 483ab0665aaSSepherosa Ziehau if (onoff) { 484da9c2b36SSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 485da9c2b36SSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEBARKER; 486da9c2b36SSepherosa Ziehau } else { 487da9c2b36SSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 488da9c2b36SSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEBARKER; 489da9c2b36SSepherosa Ziehau } 490da9c2b36SSepherosa Ziehau 491da9c2b36SSepherosa Ziehau /* Notify driver */ 492da9c2b36SSepherosa Ziehau if (ic->ic_update_preamble != NULL) 493da9c2b36SSepherosa Ziehau ic->ic_update_preamble(ic->ic_ifp); 494da9c2b36SSepherosa Ziehau } 495da9c2b36SSepherosa Ziehau 496da9c2b36SSepherosa Ziehau /* 497841ab66cSSepherosa Ziehau * Check if the specified rate set supports ERP. 498841ab66cSSepherosa Ziehau * NB: the rate set is assumed to be sorted. 499841ab66cSSepherosa Ziehau */ 500841ab66cSSepherosa Ziehau int 501841ab66cSSepherosa Ziehau ieee80211_iserp_rateset(struct ieee80211com *ic, struct ieee80211_rateset *rs) 502841ab66cSSepherosa Ziehau { 503841ab66cSSepherosa Ziehau #define N(a) (sizeof(a) / sizeof(a[0])) 504841ab66cSSepherosa Ziehau static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; 505841ab66cSSepherosa Ziehau int i, j; 506841ab66cSSepherosa Ziehau 507841ab66cSSepherosa Ziehau if (rs->rs_nrates < N(rates)) 508841ab66cSSepherosa Ziehau return 0; 509841ab66cSSepherosa Ziehau for (i = 0; i < N(rates); i++) { 510841ab66cSSepherosa Ziehau for (j = 0; j < rs->rs_nrates; j++) { 511841ab66cSSepherosa Ziehau int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; 512841ab66cSSepherosa Ziehau if (rates[i] == r) 513841ab66cSSepherosa Ziehau goto next; 514841ab66cSSepherosa Ziehau if (r > rates[i]) 515841ab66cSSepherosa Ziehau return 0; 516841ab66cSSepherosa Ziehau } 517841ab66cSSepherosa Ziehau return 0; 518841ab66cSSepherosa Ziehau next: 519841ab66cSSepherosa Ziehau ; 520841ab66cSSepherosa Ziehau } 521841ab66cSSepherosa Ziehau return 1; 522841ab66cSSepherosa Ziehau #undef N 523841ab66cSSepherosa Ziehau } 524841ab66cSSepherosa Ziehau 525841ab66cSSepherosa Ziehau /* 526841ab66cSSepherosa Ziehau * Mark the basic rates for the 11g rate table based on the 527841ab66cSSepherosa Ziehau * operating mode. For real 11g we mark all the 11b rates 528841ab66cSSepherosa Ziehau * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 529841ab66cSSepherosa Ziehau * 11b rates. There's also a pseudo 11a-mode used to mark only 530841ab66cSSepherosa Ziehau * the basic OFDM rates. 531841ab66cSSepherosa Ziehau */ 532841ab66cSSepherosa Ziehau void 533841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) 534841ab66cSSepherosa Ziehau { 535841ab66cSSepherosa Ziehau static const struct ieee80211_rateset basic[] = { 536841ab66cSSepherosa Ziehau { 0 }, /* IEEE80211_MODE_AUTO */ 537841ab66cSSepherosa Ziehau { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 538841ab66cSSepherosa Ziehau { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ 539841ab66cSSepherosa Ziehau { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */ 540841ab66cSSepherosa Ziehau { 0 }, /* IEEE80211_MODE_FH */ 541841ab66cSSepherosa Ziehau /* IEEE80211_MODE_PUREG (not yet) */ 542841ab66cSSepherosa Ziehau { 7, { 2, 4, 11, 22, 12, 24, 48 } }, 543841ab66cSSepherosa Ziehau }; 544841ab66cSSepherosa Ziehau int i, j; 545841ab66cSSepherosa Ziehau 546841ab66cSSepherosa Ziehau for (i = 0; i < rs->rs_nrates; i++) { 547841ab66cSSepherosa Ziehau rs->rs_rates[i] &= IEEE80211_RATE_VAL; 548841ab66cSSepherosa Ziehau for (j = 0; j < basic[mode].rs_nrates; j++) 549841ab66cSSepherosa Ziehau if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 550841ab66cSSepherosa Ziehau rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 551841ab66cSSepherosa Ziehau break; 552841ab66cSSepherosa Ziehau } 553841ab66cSSepherosa Ziehau } 554841ab66cSSepherosa Ziehau } 555841ab66cSSepherosa Ziehau 556841ab66cSSepherosa Ziehau /* 557841ab66cSSepherosa Ziehau * WME protocol support. The following parameters come from the spec. 558841ab66cSSepherosa Ziehau */ 559841ab66cSSepherosa Ziehau typedef struct phyParamType { 560841ab66cSSepherosa Ziehau uint8_t aifsn; 561841ab66cSSepherosa Ziehau uint8_t logcwmin; 562841ab66cSSepherosa Ziehau uint8_t logcwmax; 563841ab66cSSepherosa Ziehau uint16_t txopLimit; 564841ab66cSSepherosa Ziehau uint8_t acm; 565841ab66cSSepherosa Ziehau } paramType; 566841ab66cSSepherosa Ziehau 567841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = { 568841ab66cSSepherosa Ziehau { 3, 4, 6 }, /* IEEE80211_MODE_AUTO */ 569841ab66cSSepherosa Ziehau { 3, 4, 6 }, /* IEEE80211_MODE_11A */ 570841ab66cSSepherosa Ziehau { 3, 5, 7 }, /* IEEE80211_MODE_11B */ 571841ab66cSSepherosa Ziehau { 3, 4, 6 }, /* IEEE80211_MODE_11G */ 572841ab66cSSepherosa Ziehau { 3, 5, 7 }, /* IEEE80211_MODE_FH */ 573841ab66cSSepherosa Ziehau { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_A */ 574841ab66cSSepherosa Ziehau { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_G */ 575841ab66cSSepherosa Ziehau }; 576841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = { 577841ab66cSSepherosa Ziehau { 7, 4, 10 }, /* IEEE80211_MODE_AUTO */ 578841ab66cSSepherosa Ziehau { 7, 4, 10 }, /* IEEE80211_MODE_11A */ 579841ab66cSSepherosa Ziehau { 7, 5, 10 }, /* IEEE80211_MODE_11B */ 580841ab66cSSepherosa Ziehau { 7, 4, 10 }, /* IEEE80211_MODE_11G */ 581841ab66cSSepherosa Ziehau { 7, 5, 10 }, /* IEEE80211_MODE_FH */ 582841ab66cSSepherosa Ziehau { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 583841ab66cSSepherosa Ziehau { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 584841ab66cSSepherosa Ziehau }; 585841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = { 586841ab66cSSepherosa Ziehau { 1, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 587841ab66cSSepherosa Ziehau { 1, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 588841ab66cSSepherosa Ziehau { 1, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 589841ab66cSSepherosa Ziehau { 1, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 590841ab66cSSepherosa Ziehau { 1, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 591841ab66cSSepherosa Ziehau { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 592841ab66cSSepherosa Ziehau { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 593841ab66cSSepherosa Ziehau }; 594841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = { 595841ab66cSSepherosa Ziehau { 1, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 596841ab66cSSepherosa Ziehau { 1, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 597841ab66cSSepherosa Ziehau { 1, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 598841ab66cSSepherosa Ziehau { 1, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 599841ab66cSSepherosa Ziehau { 1, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 600841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 601841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 602841ab66cSSepherosa Ziehau }; 603841ab66cSSepherosa Ziehau 604841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = { 605841ab66cSSepherosa Ziehau { 3, 4, 10 }, /* IEEE80211_MODE_AUTO */ 606841ab66cSSepherosa Ziehau { 3, 4, 10 }, /* IEEE80211_MODE_11A */ 607841ab66cSSepherosa Ziehau { 3, 5, 10 }, /* IEEE80211_MODE_11B */ 608841ab66cSSepherosa Ziehau { 3, 4, 10 }, /* IEEE80211_MODE_11G */ 609841ab66cSSepherosa Ziehau { 3, 5, 10 }, /* IEEE80211_MODE_FH */ 610841ab66cSSepherosa Ziehau { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 611841ab66cSSepherosa Ziehau { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 612841ab66cSSepherosa Ziehau }; 613841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = { 614841ab66cSSepherosa Ziehau { 2, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 615841ab66cSSepherosa Ziehau { 2, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 616841ab66cSSepherosa Ziehau { 2, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 617841ab66cSSepherosa Ziehau { 2, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 618841ab66cSSepherosa Ziehau { 2, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 619841ab66cSSepherosa Ziehau { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 620841ab66cSSepherosa Ziehau { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 621841ab66cSSepherosa Ziehau }; 622841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = { 623841ab66cSSepherosa Ziehau { 2, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 624841ab66cSSepherosa Ziehau { 2, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 625841ab66cSSepherosa Ziehau { 2, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 626841ab66cSSepherosa Ziehau { 2, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 627841ab66cSSepherosa Ziehau { 2, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 628841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 629841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 630841ab66cSSepherosa Ziehau }; 631841ab66cSSepherosa Ziehau 632841ab66cSSepherosa Ziehau void 633841ab66cSSepherosa Ziehau ieee80211_wme_initparams(struct ieee80211com *ic) 634841ab66cSSepherosa Ziehau { 635841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme; 636841ab66cSSepherosa Ziehau const paramType *pPhyParam, *pBssPhyParam; 637841ab66cSSepherosa Ziehau struct wmeParams *wmep; 638841ab66cSSepherosa Ziehau int i; 639841ab66cSSepherosa Ziehau 640841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_WME) == 0) 641841ab66cSSepherosa Ziehau return; 642841ab66cSSepherosa Ziehau 643841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) { 644841ab66cSSepherosa Ziehau switch (i) { 645841ab66cSSepherosa Ziehau case WME_AC_BK: 646841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 647841ab66cSSepherosa Ziehau pBssPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 648841ab66cSSepherosa Ziehau break; 649841ab66cSSepherosa Ziehau case WME_AC_VI: 650841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_VI[ic->ic_curmode]; 651841ab66cSSepherosa Ziehau pBssPhyParam = &bssPhyParamForAC_VI[ic->ic_curmode]; 652841ab66cSSepherosa Ziehau break; 653841ab66cSSepherosa Ziehau case WME_AC_VO: 654841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_VO[ic->ic_curmode]; 655841ab66cSSepherosa Ziehau pBssPhyParam = &bssPhyParamForAC_VO[ic->ic_curmode]; 656841ab66cSSepherosa Ziehau break; 657841ab66cSSepherosa Ziehau case WME_AC_BE: 658841ab66cSSepherosa Ziehau default: 659841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_BE[ic->ic_curmode]; 660841ab66cSSepherosa Ziehau pBssPhyParam = &bssPhyParamForAC_BE[ic->ic_curmode]; 661841ab66cSSepherosa Ziehau break; 662841ab66cSSepherosa Ziehau } 663841ab66cSSepherosa Ziehau 664841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 665841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 666841ab66cSSepherosa Ziehau wmep->wmep_acm = pPhyParam->acm; 667841ab66cSSepherosa Ziehau wmep->wmep_aifsn = pPhyParam->aifsn; 668841ab66cSSepherosa Ziehau wmep->wmep_logcwmin = pPhyParam->logcwmin; 669841ab66cSSepherosa Ziehau wmep->wmep_logcwmax = pPhyParam->logcwmax; 670841ab66cSSepherosa Ziehau wmep->wmep_txopLimit = pPhyParam->txopLimit; 671841ab66cSSepherosa Ziehau } else { 672841ab66cSSepherosa Ziehau wmep->wmep_acm = pBssPhyParam->acm; 673841ab66cSSepherosa Ziehau wmep->wmep_aifsn = pBssPhyParam->aifsn; 674841ab66cSSepherosa Ziehau wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 675841ab66cSSepherosa Ziehau wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 676841ab66cSSepherosa Ziehau wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 677841ab66cSSepherosa Ziehau 678841ab66cSSepherosa Ziehau } 679841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 680841ab66cSSepherosa Ziehau "%s: %s chan [acm %u aifsn %u log2(cwmin) %u " 681841ab66cSSepherosa Ziehau "log2(cwmax) %u txpoLimit %u]\n", __func__ 682841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[i] 683841ab66cSSepherosa Ziehau , wmep->wmep_acm 684841ab66cSSepherosa Ziehau , wmep->wmep_aifsn 685841ab66cSSepherosa Ziehau , wmep->wmep_logcwmin 686841ab66cSSepherosa Ziehau , wmep->wmep_logcwmax 687841ab66cSSepherosa Ziehau , wmep->wmep_txopLimit 688841ab66cSSepherosa Ziehau ); 689841ab66cSSepherosa Ziehau 690841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 691841ab66cSSepherosa Ziehau wmep->wmep_acm = pBssPhyParam->acm; 692841ab66cSSepherosa Ziehau wmep->wmep_aifsn = pBssPhyParam->aifsn; 693841ab66cSSepherosa Ziehau wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 694841ab66cSSepherosa Ziehau wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 695841ab66cSSepherosa Ziehau wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 696841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 697841ab66cSSepherosa Ziehau "%s: %s bss [acm %u aifsn %u log2(cwmin) %u " 698841ab66cSSepherosa Ziehau "log2(cwmax) %u txpoLimit %u]\n", __func__ 699841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[i] 700841ab66cSSepherosa Ziehau , wmep->wmep_acm 701841ab66cSSepherosa Ziehau , wmep->wmep_aifsn 702841ab66cSSepherosa Ziehau , wmep->wmep_logcwmin 703841ab66cSSepherosa Ziehau , wmep->wmep_logcwmax 704841ab66cSSepherosa Ziehau , wmep->wmep_txopLimit 705841ab66cSSepherosa Ziehau ); 706841ab66cSSepherosa Ziehau } 707841ab66cSSepherosa Ziehau /* NB: check ic_bss to avoid NULL deref on initial attach */ 708841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) { 709841ab66cSSepherosa Ziehau /* 710841ab66cSSepherosa Ziehau * Calculate agressive mode switching threshold based 711841ab66cSSepherosa Ziehau * on beacon interval. This doesn't need locking since 712841ab66cSSepherosa Ziehau * we're only called before entering the RUN state at 713841ab66cSSepherosa Ziehau * which point we start sending beacon frames. 714841ab66cSSepherosa Ziehau */ 715841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh = 716841ab66cSSepherosa Ziehau (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->ni_intval) / 100; 717841ab66cSSepherosa Ziehau ieee80211_wme_updateparams(ic); 718841ab66cSSepherosa Ziehau } 719841ab66cSSepherosa Ziehau } 720841ab66cSSepherosa Ziehau 721841ab66cSSepherosa Ziehau /* 722841ab66cSSepherosa Ziehau * Update WME parameters for ourself and the BSS. 723841ab66cSSepherosa Ziehau */ 724841ab66cSSepherosa Ziehau void 725841ab66cSSepherosa Ziehau ieee80211_wme_updateparams(struct ieee80211com *ic) 726841ab66cSSepherosa Ziehau { 727841ab66cSSepherosa Ziehau static const paramType phyParam[IEEE80211_MODE_MAX] = { 728841ab66cSSepherosa Ziehau { 2, 4, 10, 64 }, /* IEEE80211_MODE_AUTO */ 729841ab66cSSepherosa Ziehau { 2, 4, 10, 64 }, /* IEEE80211_MODE_11A */ 730841ab66cSSepherosa Ziehau { 2, 5, 10, 64 }, /* IEEE80211_MODE_11B */ 731841ab66cSSepherosa Ziehau { 2, 4, 10, 64 }, /* IEEE80211_MODE_11G */ 732841ab66cSSepherosa Ziehau { 2, 5, 10, 64 }, /* IEEE80211_MODE_FH */ 733841ab66cSSepherosa Ziehau { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_A */ 734841ab66cSSepherosa Ziehau { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_G */ 735841ab66cSSepherosa Ziehau }; 736841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme; 737841ab66cSSepherosa Ziehau const struct wmeParams *wmep; 738841ab66cSSepherosa Ziehau struct wmeParams *chanp, *bssp; 739841ab66cSSepherosa Ziehau int i; 740841ab66cSSepherosa Ziehau 741841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 742841ab66cSSepherosa Ziehau 743841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_WME) == 0) 744841ab66cSSepherosa Ziehau return; 745841ab66cSSepherosa Ziehau 746841ab66cSSepherosa Ziehau /* set up the channel access parameters for the physical device */ 747841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) { 748841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[i]; 749841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 750841ab66cSSepherosa Ziehau chanp->wmep_aifsn = wmep->wmep_aifsn; 751841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = wmep->wmep_logcwmin; 752841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = wmep->wmep_logcwmax; 753841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = wmep->wmep_txopLimit; 754841ab66cSSepherosa Ziehau 755841ab66cSSepherosa Ziehau chanp = &wme->wme_bssChanParams.cap_wmeParams[i]; 756841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 757841ab66cSSepherosa Ziehau chanp->wmep_aifsn = wmep->wmep_aifsn; 758841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = wmep->wmep_logcwmin; 759841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = wmep->wmep_logcwmax; 760841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = wmep->wmep_txopLimit; 761841ab66cSSepherosa Ziehau } 762841ab66cSSepherosa Ziehau 763841ab66cSSepherosa Ziehau /* 764841ab66cSSepherosa Ziehau * This implements agressive mode as found in certain 765841ab66cSSepherosa Ziehau * vendors' AP's. When there is significant high 766841ab66cSSepherosa Ziehau * priority (VI/VO) traffic in the BSS throttle back BE 767841ab66cSSepherosa Ziehau * traffic by using conservative parameters. Otherwise 768841ab66cSSepherosa Ziehau * BE uses agressive params to optimize performance of 769841ab66cSSepherosa Ziehau * legacy/non-QoS traffic. 770841ab66cSSepherosa Ziehau */ 771841ab66cSSepherosa Ziehau if ((ic->ic_opmode == IEEE80211_M_HOSTAP && 772841ab66cSSepherosa Ziehau (wme->wme_flags & WME_F_AGGRMODE) != 0) || 773841ab66cSSepherosa Ziehau (ic->ic_opmode == IEEE80211_M_STA && 774841ab66cSSepherosa Ziehau (ic->ic_bss->ni_flags & IEEE80211_NODE_QOS) == 0) || 775841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_WME) == 0) { 776841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 777841ab66cSSepherosa Ziehau bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 778841ab66cSSepherosa Ziehau 779841ab66cSSepherosa Ziehau chanp->wmep_aifsn = bssp->wmep_aifsn = 780841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].aifsn; 781841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = bssp->wmep_logcwmin = 782841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].logcwmin; 783841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = bssp->wmep_logcwmax = 784841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].logcwmax; 785841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = bssp->wmep_txopLimit = 786841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_BURST) ? 787841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].txopLimit : 0; 788841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 789841ab66cSSepherosa Ziehau "%s: %s [acm %u aifsn %u log2(cwmin) %u " 790841ab66cSSepherosa Ziehau "log2(cwmax) %u txpoLimit %u]\n", __func__ 791841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[WME_AC_BE] 792841ab66cSSepherosa Ziehau , chanp->wmep_acm 793841ab66cSSepherosa Ziehau , chanp->wmep_aifsn 794841ab66cSSepherosa Ziehau , chanp->wmep_logcwmin 795841ab66cSSepherosa Ziehau , chanp->wmep_logcwmax 796841ab66cSSepherosa Ziehau , chanp->wmep_txopLimit 797841ab66cSSepherosa Ziehau ); 798841ab66cSSepherosa Ziehau } 799841ab66cSSepherosa Ziehau 800841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 801841ab66cSSepherosa Ziehau ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) { 802841ab66cSSepherosa Ziehau static const uint8_t logCwMin[IEEE80211_MODE_MAX] = { 803841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_AUTO */ 804841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_11A */ 805841ab66cSSepherosa Ziehau 4, /* IEEE80211_MODE_11B */ 806841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_11G */ 807841ab66cSSepherosa Ziehau 4, /* IEEE80211_MODE_FH */ 808841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_TURBO_A */ 809841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_TURBO_G */ 810841ab66cSSepherosa Ziehau }; 811841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 812841ab66cSSepherosa Ziehau bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 813841ab66cSSepherosa Ziehau 814841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = bssp->wmep_logcwmin = 815841ab66cSSepherosa Ziehau logCwMin[ic->ic_curmode]; 816841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 817841ab66cSSepherosa Ziehau "%s: %s log2(cwmin) %u\n", __func__ 818841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[WME_AC_BE] 819841ab66cSSepherosa Ziehau , chanp->wmep_logcwmin 820841ab66cSSepherosa Ziehau ); 821841ab66cSSepherosa Ziehau } 822841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */ 823841ab66cSSepherosa Ziehau /* 824841ab66cSSepherosa Ziehau * Arrange for a beacon update and bump the parameter 825841ab66cSSepherosa Ziehau * set number so associated stations load the new values. 826841ab66cSSepherosa Ziehau */ 827841ab66cSSepherosa Ziehau wme->wme_bssChanParams.cap_info = 828841ab66cSSepherosa Ziehau (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT; 829841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_WMEUPDATE; 830841ab66cSSepherosa Ziehau } 831841ab66cSSepherosa Ziehau 832841ab66cSSepherosa Ziehau wme->wme_update(ic); 833841ab66cSSepherosa Ziehau 834841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 835841ab66cSSepherosa Ziehau "%s: WME params updated, cap_info 0x%x\n", __func__, 836841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_STA ? 837841ab66cSSepherosa Ziehau wme->wme_wmeChanParams.cap_info : 838841ab66cSSepherosa Ziehau wme->wme_bssChanParams.cap_info); 839841ab66cSSepherosa Ziehau } 840841ab66cSSepherosa Ziehau 841841ab66cSSepherosa Ziehau void 842841ab66cSSepherosa Ziehau ieee80211_beacon_miss(struct ieee80211com *ic) 843841ab66cSSepherosa Ziehau { 844841ab66cSSepherosa Ziehau 845841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_SCAN) { 846841ab66cSSepherosa Ziehau /* XXX check ic_curchan != ic_bsschan? */ 847841ab66cSSepherosa Ziehau return; 848841ab66cSSepherosa Ziehau } 849841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 850841ab66cSSepherosa Ziehau IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 851841ab66cSSepherosa Ziehau "%s\n", "beacon miss"); 852841ab66cSSepherosa Ziehau 853841ab66cSSepherosa Ziehau /* 854841ab66cSSepherosa Ziehau * Our handling is only meaningful for stations that are 855841ab66cSSepherosa Ziehau * associated; any other conditions else will be handled 856841ab66cSSepherosa Ziehau * through different means (e.g. the tx timeout on mgt frames). 857841ab66cSSepherosa Ziehau */ 858841ab66cSSepherosa Ziehau if (ic->ic_opmode != IEEE80211_M_STA || ic->ic_state != IEEE80211_S_RUN) 859841ab66cSSepherosa Ziehau return; 860841ab66cSSepherosa Ziehau 861841ab66cSSepherosa Ziehau if (++ic->ic_bmiss_count < ic->ic_bmiss_max) { 862841ab66cSSepherosa Ziehau /* 863841ab66cSSepherosa Ziehau * Send a directed probe req before falling back to a scan; 864841ab66cSSepherosa Ziehau * if we receive a response ic_bmiss_count will be reset. 865841ab66cSSepherosa Ziehau * Some cards mistakenly report beacon miss so this avoids 866841ab66cSSepherosa Ziehau * the expensive scan if the ap is still there. 867841ab66cSSepherosa Ziehau */ 868841ab66cSSepherosa Ziehau ieee80211_send_probereq(ic->ic_bss, ic->ic_myaddr, 869841ab66cSSepherosa Ziehau ic->ic_bss->ni_bssid, ic->ic_bss->ni_bssid, 870841ab66cSSepherosa Ziehau ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen, 871841ab66cSSepherosa Ziehau ic->ic_opt_ie, ic->ic_opt_ie_len); 872841ab66cSSepherosa Ziehau return; 873841ab66cSSepherosa Ziehau } 874841ab66cSSepherosa Ziehau ic->ic_bmiss_count = 0; 875841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); 876841ab66cSSepherosa Ziehau } 877841ab66cSSepherosa Ziehau 878841ab66cSSepherosa Ziehau /* 879841ab66cSSepherosa Ziehau * Software beacon miss handling. Check if any beacons 880841ab66cSSepherosa Ziehau * were received in the last period. If not post a 881841ab66cSSepherosa Ziehau * beacon miss; otherwise reset the counter. 882841ab66cSSepherosa Ziehau */ 883841ab66cSSepherosa Ziehau static void 884841ab66cSSepherosa Ziehau ieee80211_swbmiss(void *arg) 885841ab66cSSepherosa Ziehau { 886841ab66cSSepherosa Ziehau struct ieee80211com *ic = arg; 887841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 888841ab66cSSepherosa Ziehau 889841ab66cSSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 890841ab66cSSepherosa Ziehau 891841ab66cSSepherosa Ziehau if (ic->ic_swbmiss_count == 0) { 892841ab66cSSepherosa Ziehau ieee80211_beacon_miss(ic); 893841ab66cSSepherosa Ziehau if (ic->ic_bmiss_count == 0) /* don't re-arm timer */ 894841ab66cSSepherosa Ziehau goto back; 895841ab66cSSepherosa Ziehau } else 896841ab66cSSepherosa Ziehau ic->ic_swbmiss_count = 0; 897841ab66cSSepherosa Ziehau callout_reset(&ic->ic_swbmiss, ic->ic_swbmiss_period, 898841ab66cSSepherosa Ziehau ieee80211_swbmiss, ic); 899841ab66cSSepherosa Ziehau 900841ab66cSSepherosa Ziehau back: 901841ab66cSSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 902841ab66cSSepherosa Ziehau } 903841ab66cSSepherosa Ziehau 904841ab66cSSepherosa Ziehau static void 905841ab66cSSepherosa Ziehau sta_disassoc(void *arg, struct ieee80211_node *ni) 906841ab66cSSepherosa Ziehau { 907841ab66cSSepherosa Ziehau struct ieee80211com *ic = arg; 908841ab66cSSepherosa Ziehau 909841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 910841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, 911841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_LEAVE); 912841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 913841ab66cSSepherosa Ziehau } 914841ab66cSSepherosa Ziehau } 915841ab66cSSepherosa Ziehau 916841ab66cSSepherosa Ziehau static void 917841ab66cSSepherosa Ziehau sta_deauth(void *arg, struct ieee80211_node *ni) 918841ab66cSSepherosa Ziehau { 919841ab66cSSepherosa Ziehau struct ieee80211com *ic = arg; 920841ab66cSSepherosa Ziehau 921841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, 922841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_LEAVE); 923841ab66cSSepherosa Ziehau } 924841ab66cSSepherosa Ziehau 925841ab66cSSepherosa Ziehau static int 926841ab66cSSepherosa Ziehau ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 927841ab66cSSepherosa Ziehau { 928841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 929f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 930f186073cSJoerg Sonnenberger enum ieee80211_state ostate; 931f186073cSJoerg Sonnenberger 932f186073cSJoerg Sonnenberger ostate = ic->ic_state; 933841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__, 934841ab66cSSepherosa Ziehau ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 935f186073cSJoerg Sonnenberger ic->ic_state = nstate; /* state transition */ 936f186073cSJoerg Sonnenberger ni = ic->ic_bss; /* NB: no reference held */ 937841ab66cSSepherosa Ziehau if (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS) 938841ab66cSSepherosa Ziehau callout_stop(&ic->ic_swbmiss); 939f186073cSJoerg Sonnenberger switch (nstate) { 940f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 941f186073cSJoerg Sonnenberger switch (ostate) { 942f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 943f186073cSJoerg Sonnenberger break; 944f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 945f186073cSJoerg Sonnenberger switch (ic->ic_opmode) { 946f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 947f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 948f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DISASSOC, 949f186073cSJoerg Sonnenberger IEEE80211_REASON_ASSOC_LEAVE); 950841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 951f186073cSJoerg Sonnenberger break; 952f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 953841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(&ic->ic_sta, 954841ab66cSSepherosa Ziehau sta_disassoc, ic); 955f186073cSJoerg Sonnenberger break; 956f186073cSJoerg Sonnenberger default: 957f186073cSJoerg Sonnenberger break; 958f186073cSJoerg Sonnenberger } 959841ab66cSSepherosa Ziehau goto reset; 960f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 961f186073cSJoerg Sonnenberger switch (ic->ic_opmode) { 962f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 963f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 964f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 965f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_LEAVE); 966f186073cSJoerg Sonnenberger break; 967f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 968841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(&ic->ic_sta, 969841ab66cSSepherosa Ziehau sta_deauth, ic); 970f186073cSJoerg Sonnenberger break; 971f186073cSJoerg Sonnenberger default: 972f186073cSJoerg Sonnenberger break; 973f186073cSJoerg Sonnenberger } 974841ab66cSSepherosa Ziehau goto reset; 975f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 976841ab66cSSepherosa Ziehau ieee80211_cancel_scan(ic); 977841ab66cSSepherosa Ziehau goto reset; 978841ab66cSSepherosa Ziehau case IEEE80211_S_AUTH: 979841ab66cSSepherosa Ziehau reset: 980f186073cSJoerg Sonnenberger ic->ic_mgt_timer = 0; 981f186073cSJoerg Sonnenberger IF_DRAIN(&ic->ic_mgtq); 982841ab66cSSepherosa Ziehau ieee80211_reset_bss(ic); 983f186073cSJoerg Sonnenberger break; 984f186073cSJoerg Sonnenberger } 985841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_detach != NULL) 986841ab66cSSepherosa Ziehau ic->ic_auth->ia_detach(ic); 987f186073cSJoerg Sonnenberger break; 988f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 989f186073cSJoerg Sonnenberger switch (ostate) { 990f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 991841ab66cSSepherosa Ziehau if ((ic->ic_opmode == IEEE80211_M_HOSTAP || 992841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS || 993841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO) && 994f186073cSJoerg Sonnenberger ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 995f186073cSJoerg Sonnenberger /* 996f186073cSJoerg Sonnenberger * AP operation and we already have a channel; 997f186073cSJoerg Sonnenberger * bypass the scan and startup immediately. 998f186073cSJoerg Sonnenberger */ 999f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_des_chan); 1000f186073cSJoerg Sonnenberger } else { 1001841ab66cSSepherosa Ziehau ieee80211_begin_scan(ic, arg); 1002f186073cSJoerg Sonnenberger } 1003f186073cSJoerg Sonnenberger break; 1004f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 1005841ab66cSSepherosa Ziehau /* 1006841ab66cSSepherosa Ziehau * Scan next. If doing an active scan probe 1007841ab66cSSepherosa Ziehau * for the requested ap (if any). 1008841ab66cSSepherosa Ziehau */ 1009841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_ASCAN) 1010841ab66cSSepherosa Ziehau ieee80211_probe_curchan(ic, 0); 1011f186073cSJoerg Sonnenberger break; 1012f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1013f186073cSJoerg Sonnenberger /* beacon miss */ 1014841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, 1015841ab66cSSepherosa Ziehau "no recent beacons from %6D; rescanning\n", 1016f186073cSJoerg Sonnenberger ic->ic_bss->ni_bssid, ":"); 1017841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 1018841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */ 1019f186073cSJoerg Sonnenberger /* FALLTHRU */ 1020f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1021f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1022f186073cSJoerg Sonnenberger /* timeout restart scan */ 1023841ab66cSSepherosa Ziehau ni = ieee80211_find_node(&ic->ic_scan, 1024841ab66cSSepherosa Ziehau ic->ic_bss->ni_macaddr); 1025f186073cSJoerg Sonnenberger if (ni != NULL) { 1026f186073cSJoerg Sonnenberger ni->ni_fails++; 1027f186073cSJoerg Sonnenberger ieee80211_unref_node(&ni); 1028f186073cSJoerg Sonnenberger } 1029841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) 1030841ab66cSSepherosa Ziehau ieee80211_begin_scan(ic, arg); 1031f186073cSJoerg Sonnenberger break; 1032f186073cSJoerg Sonnenberger } 1033f186073cSJoerg Sonnenberger break; 1034f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1035f186073cSJoerg Sonnenberger switch (ostate) { 1036f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 1037f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 1038f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1039f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 1); 1040f186073cSJoerg Sonnenberger break; 1041f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1042f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1043841ab66cSSepherosa Ziehau switch (arg) { 1044f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 1045f186073cSJoerg Sonnenberger /* ??? */ 1046f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1047f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 2); 1048f186073cSJoerg Sonnenberger break; 1049f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 1050f186073cSJoerg Sonnenberger /* ignore and retry scan on timeout */ 1051f186073cSJoerg Sonnenberger break; 1052f186073cSJoerg Sonnenberger } 1053f186073cSJoerg Sonnenberger break; 1054f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1055841ab66cSSepherosa Ziehau switch (arg) { 1056f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 1057f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1058f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 2); 1059f186073cSJoerg Sonnenberger ic->ic_state = ostate; /* stay RUN */ 1060f186073cSJoerg Sonnenberger break; 1061f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 1062841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 1063841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 1064f186073cSJoerg Sonnenberger /* try to reauth */ 1065f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1066f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 1); 1067841ab66cSSepherosa Ziehau } 1068f186073cSJoerg Sonnenberger break; 1069f186073cSJoerg Sonnenberger } 1070f186073cSJoerg Sonnenberger break; 1071f186073cSJoerg Sonnenberger } 1072f186073cSJoerg Sonnenberger break; 1073f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1074f186073cSJoerg Sonnenberger switch (ostate) { 1075f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 1076f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 1077f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1078841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 1079841ab66cSSepherosa Ziehau "%s: invalid transition\n", __func__); 1080f186073cSJoerg Sonnenberger break; 1081f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1082f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1083f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 1084f186073cSJoerg Sonnenberger break; 1085f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1086841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 1087841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 1088f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1089f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 1090841ab66cSSepherosa Ziehau } 1091f186073cSJoerg Sonnenberger break; 1092f186073cSJoerg Sonnenberger } 1093f186073cSJoerg Sonnenberger break; 1094f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1095841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_WPA) { 1096841ab66cSSepherosa Ziehau /* XXX validate prerequisites */ 1097841ab66cSSepherosa Ziehau } 1098f186073cSJoerg Sonnenberger switch (ostate) { 1099f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 1100841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_MONITOR) 1101841ab66cSSepherosa Ziehau break; 1102841ab66cSSepherosa Ziehau /* fall thru... */ 1103f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1104841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 1105841ab66cSSepherosa Ziehau "%s: invalid transition\n", __func__); 1106841ab66cSSepherosa Ziehau /* fall thru... */ 1107f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1108f186073cSJoerg Sonnenberger break; 1109f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 1110f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: /* infra mode */ 1111f186073cSJoerg Sonnenberger KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 1112f186073cSJoerg Sonnenberger ("%s: bogus xmit rate %u setup\n", __func__, 1113f186073cSJoerg Sonnenberger ni->ni_txrate)); 1114841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1115841ab66cSSepherosa Ziehau if (ieee80211_msg_debug(ic)) { 1116f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_STA) 1117841ab66cSSepherosa Ziehau if_printf(ifp, "associated "); 1118f186073cSJoerg Sonnenberger else 1119841ab66cSSepherosa Ziehau if_printf(ifp, "synchronized "); 1120*a6ec04bcSSascha Wildner kprintf("with %6D ssid ", ni->ni_bssid, ":"); 1121f186073cSJoerg Sonnenberger ieee80211_print_essid(ic->ic_bss->ni_essid, 1122f186073cSJoerg Sonnenberger ni->ni_esslen); 1123*a6ec04bcSSascha Wildner kprintf(" channel %d start %uMb\n", 1124841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 1125f186073cSJoerg Sonnenberger IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 1126f186073cSJoerg Sonnenberger } 1127841ab66cSSepherosa Ziehau #endif 1128f186073cSJoerg Sonnenberger ic->ic_mgt_timer = 0; 1129841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA) 1130841ab66cSSepherosa Ziehau ieee80211_notify_node_join(ic, ni, 1131841ab66cSSepherosa Ziehau arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 1132841ab66cSSepherosa Ziehau ifp->if_start(ifp); /* XXX not authorized yet */ 1133f186073cSJoerg Sonnenberger break; 1134f186073cSJoerg Sonnenberger } 1135841ab66cSSepherosa Ziehau if (ostate != IEEE80211_S_RUN && 1136841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_STA && 1137841ab66cSSepherosa Ziehau (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS)) { 1138841ab66cSSepherosa Ziehau /* 1139841ab66cSSepherosa Ziehau * Start s/w beacon miss timer for devices w/o 1140841ab66cSSepherosa Ziehau * hardware support. We fudge a bit here since 1141841ab66cSSepherosa Ziehau * we're doing this in software. 1142841ab66cSSepherosa Ziehau */ 1143841ab66cSSepherosa Ziehau ic->ic_swbmiss_period = IEEE80211_TU_TO_TICKS( 1144841ab66cSSepherosa Ziehau 2 * ic->ic_bmissthreshold * ni->ni_intval); 1145841ab66cSSepherosa Ziehau ic->ic_swbmiss_count = 0; 1146841ab66cSSepherosa Ziehau callout_reset(&ic->ic_swbmiss, ic->ic_swbmiss_period, 1147841ab66cSSepherosa Ziehau ieee80211_swbmiss, ic); 1148841ab66cSSepherosa Ziehau } 1149841ab66cSSepherosa Ziehau /* 1150841ab66cSSepherosa Ziehau * Start/stop the authenticator when operating as an 1151841ab66cSSepherosa Ziehau * AP. We delay until here to allow configuration to 1152841ab66cSSepherosa Ziehau * happen out of order. 1153841ab66cSSepherosa Ziehau */ 1154841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */ 1155841ab66cSSepherosa Ziehau ic->ic_auth->ia_attach != NULL) { 1156841ab66cSSepherosa Ziehau /* XXX check failure */ 1157841ab66cSSepherosa Ziehau ic->ic_auth->ia_attach(ic); 1158841ab66cSSepherosa Ziehau } else if (ic->ic_auth->ia_detach != NULL) { 1159841ab66cSSepherosa Ziehau ic->ic_auth->ia_detach(ic); 1160841ab66cSSepherosa Ziehau } 1161841ab66cSSepherosa Ziehau /* 1162841ab66cSSepherosa Ziehau * When 802.1x is not in use mark the port authorized 1163841ab66cSSepherosa Ziehau * at this point so traffic can flow. 1164841ab66cSSepherosa Ziehau */ 1165841ab66cSSepherosa Ziehau if (ni->ni_authmode != IEEE80211_AUTH_8021X) 1166841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1167841ab66cSSepherosa Ziehau /* 1168841ab66cSSepherosa Ziehau * Enable inactivity processing. 1169841ab66cSSepherosa Ziehau * XXX 1170841ab66cSSepherosa Ziehau */ 1171841ab66cSSepherosa Ziehau ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT; 1172841ab66cSSepherosa Ziehau ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT; 1173f186073cSJoerg Sonnenberger break; 1174f186073cSJoerg Sonnenberger } 1175f186073cSJoerg Sonnenberger return 0; 1176f186073cSJoerg Sonnenberger } 1177