1f186073cSJoerg Sonnenberger /* 2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 3*841ab66cSSepherosa Ziehau * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 4f186073cSJoerg Sonnenberger * All rights reserved. 5f186073cSJoerg Sonnenberger * 6f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 7f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions 8f186073cSJoerg Sonnenberger * are met: 9f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 10f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 11f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 12f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 13f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 14f186073cSJoerg Sonnenberger * 3. The name of the author may not be used to endorse or promote products 15f186073cSJoerg Sonnenberger * derived from this software without specific prior written permission. 16f186073cSJoerg Sonnenberger * 17f186073cSJoerg Sonnenberger * Alternatively, this software may be distributed under the terms of the 18f186073cSJoerg Sonnenberger * GNU General Public License ("GPL") version 2 as published by the Free 19f186073cSJoerg Sonnenberger * Software Foundation. 20f186073cSJoerg Sonnenberger * 21f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31f186073cSJoerg Sonnenberger * 32*841ab66cSSepherosa Ziehau * $FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.17.2.9 2006/03/13 03:10:31 sam Exp $ 33*841ab66cSSepherosa Ziehau * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_proto.c,v 1.2 2006/05/18 13:51:46 sephe 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> 44*841ab66cSSepherosa Ziehau #include <sys/systm.h> 45*841ab66cSSepherosa Ziehau #include <sys/serialize.h> 46f186073cSJoerg Sonnenberger 47*841ab66cSSepherosa Ziehau #include <sys/socket.h> 48f186073cSJoerg Sonnenberger 49f186073cSJoerg Sonnenberger #include <net/if.h> 50f186073cSJoerg Sonnenberger #include <net/if_arp.h> 51*841ab66cSSepherosa Ziehau #include <net/if_media.h> 52*841ab66cSSepherosa Ziehau #include <net/ethernet.h> /* XXX for ether_sprintf */ 53f186073cSJoerg Sonnenberger 54f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h> 55f186073cSJoerg Sonnenberger 56*841ab66cSSepherosa Ziehau /* XXX tunables */ 57*841ab66cSSepherosa Ziehau #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */ 58*841ab66cSSepherosa 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 }; 68*841ab66cSSepherosa Ziehau const char *ieee80211_ctl_subtype_name[] = { 69*841ab66cSSepherosa Ziehau "reserved#0", "reserved#1", "reserved#2", "reserved#3", 70*841ab66cSSepherosa Ziehau "reserved#3", "reserved#5", "reserved#6", "reserved#7", 71*841ab66cSSepherosa Ziehau "reserved#8", "reserved#9", "ps_poll", "rts", 72*841ab66cSSepherosa Ziehau "cts", "ack", "cf_end", "cf_end_ack" 73*841ab66cSSepherosa 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 }; 81*841ab66cSSepherosa Ziehau const char *ieee80211_wme_acnames[] = { 82*841ab66cSSepherosa Ziehau "WME_AC_BE", 83*841ab66cSSepherosa Ziehau "WME_AC_BK", 84*841ab66cSSepherosa Ziehau "WME_AC_VI", 85*841ab66cSSepherosa Ziehau "WME_AC_VO", 86*841ab66cSSepherosa Ziehau "WME_UPSD", 87*841ab66cSSepherosa Ziehau }; 88f186073cSJoerg Sonnenberger 89f186073cSJoerg Sonnenberger static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 90f186073cSJoerg Sonnenberger 91f186073cSJoerg Sonnenberger void 92*841ab66cSSepherosa Ziehau ieee80211_proto_attach(struct ieee80211com *ic) 93f186073cSJoerg Sonnenberger { 94*841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 95f186073cSJoerg Sonnenberger 96*841ab66cSSepherosa Ziehau /* XXX room for crypto */ 97*841ab66cSSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4); 98f186073cSJoerg Sonnenberger 99f186073cSJoerg Sonnenberger ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 100*841ab66cSSepherosa Ziehau ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT; 101*841ab66cSSepherosa Ziehau ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 102*841ab66cSSepherosa Ziehau ic->ic_bmiss_max = IEEE80211_BMISS_MAX; 103*841ab66cSSepherosa Ziehau callout_init(&ic->ic_swbmiss); 104*841ab66cSSepherosa Ziehau ic->ic_mcast_rate = IEEE80211_MCAST_RATE_DEFAULT; 105f186073cSJoerg Sonnenberger ic->ic_protmode = IEEE80211_PROT_CTSONLY; 106*841ab66cSSepherosa Ziehau ic->ic_roaming = IEEE80211_ROAMING_AUTO; 107*841ab66cSSepherosa Ziehau 108*841ab66cSSepherosa Ziehau ic->ic_wme.wme_hipri_switch_hysteresis = 109*841ab66cSSepherosa 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 120*841ab66cSSepherosa Ziehau ieee80211_proto_detach(struct ieee80211com *ic) 121f186073cSJoerg Sonnenberger { 122*841ab66cSSepherosa Ziehau 123*841ab66cSSepherosa Ziehau /* 124*841ab66cSSepherosa Ziehau * This should not be needed as we detach when reseting 125*841ab66cSSepherosa Ziehau * the state but be conservative here since the 126*841ab66cSSepherosa Ziehau * authenticator may do things like spawn kernel threads. 127*841ab66cSSepherosa Ziehau */ 128*841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_detach) 129*841ab66cSSepherosa Ziehau ic->ic_auth->ia_detach(ic); 130f186073cSJoerg Sonnenberger 131f186073cSJoerg Sonnenberger IF_DRAIN(&ic->ic_mgtq); 132*841ab66cSSepherosa Ziehau 133*841ab66cSSepherosa Ziehau /* 134*841ab66cSSepherosa Ziehau * Detach any ACL'ator. 135*841ab66cSSepherosa Ziehau */ 136*841ab66cSSepherosa Ziehau if (ic->ic_acl != NULL) 137*841ab66cSSepherosa Ziehau ic->ic_acl->iac_detach(ic); 138*841ab66cSSepherosa Ziehau } 139*841ab66cSSepherosa Ziehau 140*841ab66cSSepherosa Ziehau /* 141*841ab66cSSepherosa Ziehau * Simple-minded authenticator module support. 142*841ab66cSSepherosa Ziehau */ 143*841ab66cSSepherosa Ziehau 144*841ab66cSSepherosa Ziehau #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1) 145*841ab66cSSepherosa Ziehau /* XXX well-known names */ 146*841ab66cSSepherosa Ziehau static const char *auth_modnames[IEEE80211_AUTH_MAX] = { 147*841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_NONE */ 148*841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_OPEN */ 149*841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_SHARED */ 150*841ab66cSSepherosa Ziehau "wlan_xauth", /* IEEE80211_AUTH_8021X */ 151*841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_AUTO */ 152*841ab66cSSepherosa Ziehau "wlan_xauth", /* IEEE80211_AUTH_WPA */ 153*841ab66cSSepherosa Ziehau }; 154*841ab66cSSepherosa Ziehau static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX]; 155*841ab66cSSepherosa Ziehau 156*841ab66cSSepherosa Ziehau static const struct ieee80211_authenticator auth_internal = { 157*841ab66cSSepherosa Ziehau .ia_name = "wlan_internal", 158*841ab66cSSepherosa Ziehau .ia_attach = NULL, 159*841ab66cSSepherosa Ziehau .ia_detach = NULL, 160*841ab66cSSepherosa Ziehau .ia_node_join = NULL, 161*841ab66cSSepherosa Ziehau .ia_node_leave = NULL, 162*841ab66cSSepherosa Ziehau }; 163*841ab66cSSepherosa Ziehau 164*841ab66cSSepherosa Ziehau /* 165*841ab66cSSepherosa Ziehau * Setup internal authenticators once; they are never unregistered. 166*841ab66cSSepherosa Ziehau */ 167*841ab66cSSepherosa Ziehau static void 168*841ab66cSSepherosa Ziehau ieee80211_auth_setup(void) 169*841ab66cSSepherosa Ziehau { 170*841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal); 171*841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal); 172*841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal); 173*841ab66cSSepherosa Ziehau } 174*841ab66cSSepherosa Ziehau SYSINIT(wlan_auth, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_auth_setup, NULL); 175*841ab66cSSepherosa Ziehau 176*841ab66cSSepherosa Ziehau const struct ieee80211_authenticator * 177*841ab66cSSepherosa Ziehau ieee80211_authenticator_get(int auth) 178*841ab66cSSepherosa Ziehau { 179*841ab66cSSepherosa Ziehau if (auth >= IEEE80211_AUTH_MAX) 180*841ab66cSSepherosa Ziehau return NULL; 181*841ab66cSSepherosa Ziehau if (authenticators[auth] == NULL) 182*841ab66cSSepherosa Ziehau ieee80211_load_module(auth_modnames[auth]); 183*841ab66cSSepherosa Ziehau return authenticators[auth]; 184f186073cSJoerg Sonnenberger } 185f186073cSJoerg Sonnenberger 186f186073cSJoerg Sonnenberger void 187*841ab66cSSepherosa Ziehau ieee80211_authenticator_register(int type, 188*841ab66cSSepherosa Ziehau const struct ieee80211_authenticator *auth) 189f186073cSJoerg Sonnenberger { 190*841ab66cSSepherosa Ziehau if (type >= IEEE80211_AUTH_MAX) 191*841ab66cSSepherosa Ziehau return; 192*841ab66cSSepherosa Ziehau authenticators[type] = auth; 193*841ab66cSSepherosa Ziehau } 194*841ab66cSSepherosa Ziehau 195*841ab66cSSepherosa Ziehau void 196*841ab66cSSepherosa Ziehau ieee80211_authenticator_unregister(int type) 197*841ab66cSSepherosa Ziehau { 198*841ab66cSSepherosa Ziehau 199*841ab66cSSepherosa Ziehau if (type >= IEEE80211_AUTH_MAX) 200*841ab66cSSepherosa Ziehau return; 201*841ab66cSSepherosa Ziehau authenticators[type] = NULL; 202*841ab66cSSepherosa Ziehau } 203*841ab66cSSepherosa Ziehau 204*841ab66cSSepherosa Ziehau /* 205*841ab66cSSepherosa Ziehau * Very simple-minded ACL module support. 206*841ab66cSSepherosa Ziehau */ 207*841ab66cSSepherosa Ziehau /* XXX just one for now */ 208*841ab66cSSepherosa Ziehau static const struct ieee80211_aclator *acl = NULL; 209*841ab66cSSepherosa Ziehau 210*841ab66cSSepherosa Ziehau void 211*841ab66cSSepherosa Ziehau ieee80211_aclator_register(const struct ieee80211_aclator *iac) 212*841ab66cSSepherosa Ziehau { 213*841ab66cSSepherosa Ziehau printf("wlan: %s acl policy registered\n", iac->iac_name); 214*841ab66cSSepherosa Ziehau acl = iac; 215*841ab66cSSepherosa Ziehau } 216*841ab66cSSepherosa Ziehau 217*841ab66cSSepherosa Ziehau void 218*841ab66cSSepherosa Ziehau ieee80211_aclator_unregister(const struct ieee80211_aclator *iac) 219*841ab66cSSepherosa Ziehau { 220*841ab66cSSepherosa Ziehau if (acl == iac) 221*841ab66cSSepherosa Ziehau acl = NULL; 222*841ab66cSSepherosa Ziehau printf("wlan: %s acl policy unregistered\n", iac->iac_name); 223*841ab66cSSepherosa Ziehau } 224*841ab66cSSepherosa Ziehau 225*841ab66cSSepherosa Ziehau const struct ieee80211_aclator * 226*841ab66cSSepherosa Ziehau ieee80211_aclator_get(const char *name) 227*841ab66cSSepherosa Ziehau { 228*841ab66cSSepherosa Ziehau if (acl == NULL) 229*841ab66cSSepherosa Ziehau ieee80211_load_module("wlan_acl"); 230*841ab66cSSepherosa Ziehau return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL; 231*841ab66cSSepherosa Ziehau } 232*841ab66cSSepherosa Ziehau 233*841ab66cSSepherosa Ziehau void 234*841ab66cSSepherosa Ziehau ieee80211_print_essid(const uint8_t *essid, int len) 235*841ab66cSSepherosa Ziehau { 236*841ab66cSSepherosa 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) { 247f186073cSJoerg Sonnenberger printf("\""); 248f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) 249f186073cSJoerg Sonnenberger printf("%c", *p); 250f186073cSJoerg Sonnenberger printf("\""); 251f186073cSJoerg Sonnenberger } else { 252f186073cSJoerg Sonnenberger printf("0x"); 253f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) 254f186073cSJoerg Sonnenberger printf("%02x", *p); 255f186073cSJoerg Sonnenberger } 256f186073cSJoerg Sonnenberger } 257f186073cSJoerg Sonnenberger 258f186073cSJoerg Sonnenberger void 259*841ab66cSSepherosa Ziehau ieee80211_dump_pkt(const uint8_t *buf, int len, int rate, int rssi) 260f186073cSJoerg Sonnenberger { 261*841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh; 262f186073cSJoerg Sonnenberger int i; 263f186073cSJoerg Sonnenberger 264*841ab66cSSepherosa Ziehau wh = (const struct ieee80211_frame *)buf; 265f186073cSJoerg Sonnenberger switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 266f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_NODS: 267*841ab66cSSepherosa Ziehau printf("NODS %6D", wh->i_addr2, ":"); 268*841ab66cSSepherosa Ziehau printf("->%6D", wh->i_addr1, ":"); 269*841ab66cSSepherosa Ziehau printf("(%6D)", wh->i_addr3, ":"); 270f186073cSJoerg Sonnenberger break; 271f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_TODS: 272*841ab66cSSepherosa Ziehau printf("TODS %6D", wh->i_addr2, ":"); 273*841ab66cSSepherosa Ziehau printf("->%6D", wh->i_addr3, ":"); 274*841ab66cSSepherosa Ziehau printf("(%6D)", wh->i_addr1, ":"); 275f186073cSJoerg Sonnenberger break; 276f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_FROMDS: 277*841ab66cSSepherosa Ziehau printf("FRDS %6D", wh->i_addr3, ":"); 278*841ab66cSSepherosa Ziehau printf("->%6D", wh->i_addr1, ":"); 279*841ab66cSSepherosa Ziehau printf("(%6D)", wh->i_addr2, ":"); 280f186073cSJoerg Sonnenberger break; 281f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_DSTODS: 282*841ab66cSSepherosa Ziehau printf("DSDS %6D", (const uint8_t *)&wh[1], ":"); 283*841ab66cSSepherosa Ziehau printf("->%6D", wh->i_addr3, ":"); 284*841ab66cSSepherosa Ziehau printf("(%6D", wh->i_addr2, ":"); 285*841ab66cSSepherosa Ziehau printf("->%6D)", wh->i_addr1, ":"); 286f186073cSJoerg Sonnenberger break; 287f186073cSJoerg Sonnenberger } 288f186073cSJoerg Sonnenberger switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 289f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_DATA: 290f186073cSJoerg Sonnenberger printf(" data"); 291f186073cSJoerg Sonnenberger break; 292f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_MGT: 293f186073cSJoerg Sonnenberger printf(" %s", ieee80211_mgt_subtype_name[ 294f186073cSJoerg Sonnenberger (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 295f186073cSJoerg Sonnenberger >> IEEE80211_FC0_SUBTYPE_SHIFT]); 296f186073cSJoerg Sonnenberger break; 297f186073cSJoerg Sonnenberger default: 298f186073cSJoerg Sonnenberger printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 299f186073cSJoerg Sonnenberger break; 300f186073cSJoerg Sonnenberger } 301*841ab66cSSepherosa Ziehau if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 302*841ab66cSSepherosa Ziehau int i; 303*841ab66cSSepherosa Ziehau printf(" WEP [IV"); 304*841ab66cSSepherosa Ziehau for (i = 0; i < IEEE80211_WEP_IVLEN; i++) 305*841ab66cSSepherosa Ziehau printf(" %.02x", buf[sizeof(*wh)+i]); 306*841ab66cSSepherosa Ziehau printf(" KID %u]", buf[sizeof(*wh)+i] >> 6); 307*841ab66cSSepherosa Ziehau } 308f186073cSJoerg Sonnenberger if (rate >= 0) 309f186073cSJoerg Sonnenberger printf(" %dM", rate / 2); 310f186073cSJoerg Sonnenberger if (rssi >= 0) 311f186073cSJoerg Sonnenberger printf(" +%d", rssi); 312f186073cSJoerg Sonnenberger printf("\n"); 313f186073cSJoerg Sonnenberger if (len > 0) { 314f186073cSJoerg Sonnenberger for (i = 0; i < len; i++) { 315f186073cSJoerg Sonnenberger if ((i & 1) == 0) 316f186073cSJoerg Sonnenberger printf(" "); 317f186073cSJoerg Sonnenberger printf("%02x", buf[i]); 318f186073cSJoerg Sonnenberger } 319f186073cSJoerg Sonnenberger printf("\n"); 320f186073cSJoerg Sonnenberger } 321f186073cSJoerg Sonnenberger } 322f186073cSJoerg Sonnenberger 323f186073cSJoerg Sonnenberger int 324*841ab66cSSepherosa Ziehau ieee80211_fix_rate(struct ieee80211_node *ni, int flags) 325f186073cSJoerg Sonnenberger { 326f186073cSJoerg Sonnenberger #define RV(v) ((v) & IEEE80211_RATE_VAL) 327*841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 328f186073cSJoerg Sonnenberger int i, j, ignore, error; 329*841ab66cSSepherosa Ziehau int okrate, badrate, fixedrate; 330f186073cSJoerg Sonnenberger struct ieee80211_rateset *srs, *nrs; 331f186073cSJoerg Sonnenberger uint8_t r; 332f186073cSJoerg Sonnenberger 333*841ab66cSSepherosa Ziehau /* 334*841ab66cSSepherosa Ziehau * If the fixed rate check was requested but no 335*841ab66cSSepherosa Ziehau * fixed has been defined then just remove it. 336*841ab66cSSepherosa Ziehau */ 337*841ab66cSSepherosa Ziehau if ((flags & IEEE80211_F_DOFRATE) && 338*841ab66cSSepherosa Ziehau ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) 339*841ab66cSSepherosa Ziehau flags &= ~IEEE80211_F_DOFRATE; 340f186073cSJoerg Sonnenberger error = 0; 341*841ab66cSSepherosa Ziehau okrate = badrate = fixedrate = 0; 342f186073cSJoerg Sonnenberger srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 343f186073cSJoerg Sonnenberger nrs = &ni->ni_rates; 344f186073cSJoerg Sonnenberger for (i = 0; i < nrs->rs_nrates; ) { 345f186073cSJoerg Sonnenberger ignore = 0; 346f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOSORT) { 347f186073cSJoerg Sonnenberger /* 348f186073cSJoerg Sonnenberger * Sort rates. 349f186073cSJoerg Sonnenberger */ 350f186073cSJoerg Sonnenberger for (j = i + 1; j < nrs->rs_nrates; j++) { 351f186073cSJoerg Sonnenberger if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 352f186073cSJoerg Sonnenberger r = nrs->rs_rates[i]; 353f186073cSJoerg Sonnenberger nrs->rs_rates[i] = nrs->rs_rates[j]; 354f186073cSJoerg Sonnenberger nrs->rs_rates[j] = r; 355f186073cSJoerg Sonnenberger } 356f186073cSJoerg Sonnenberger } 357f186073cSJoerg Sonnenberger } 358f186073cSJoerg Sonnenberger r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 359f186073cSJoerg Sonnenberger badrate = r; 360f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOFRATE) { 361f186073cSJoerg Sonnenberger /* 362*841ab66cSSepherosa Ziehau * Check any fixed rate is included. 363f186073cSJoerg Sonnenberger */ 364*841ab66cSSepherosa Ziehau if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) 365*841ab66cSSepherosa Ziehau fixedrate = r; 366f186073cSJoerg Sonnenberger } 367f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DONEGO) { 368f186073cSJoerg Sonnenberger /* 369f186073cSJoerg Sonnenberger * Check against supported rates. 370f186073cSJoerg Sonnenberger */ 371f186073cSJoerg Sonnenberger for (j = 0; j < srs->rs_nrates; j++) { 372f186073cSJoerg Sonnenberger if (r == RV(srs->rs_rates[j])) { 373f186073cSJoerg Sonnenberger /* 374f186073cSJoerg Sonnenberger * Overwrite with the supported rate 375f186073cSJoerg Sonnenberger * value so any basic rate bit is set. 376f186073cSJoerg Sonnenberger * This insures that response we send 377f186073cSJoerg Sonnenberger * to stations have the necessary basic 378f186073cSJoerg Sonnenberger * rate bit set. 379f186073cSJoerg Sonnenberger */ 380f186073cSJoerg Sonnenberger nrs->rs_rates[i] = srs->rs_rates[j]; 381f186073cSJoerg Sonnenberger break; 382f186073cSJoerg Sonnenberger } 383f186073cSJoerg Sonnenberger } 384f186073cSJoerg Sonnenberger if (j == srs->rs_nrates) { 385f186073cSJoerg Sonnenberger /* 386f186073cSJoerg Sonnenberger * A rate in the node's rate set is not 387f186073cSJoerg Sonnenberger * supported. If this is a basic rate and we 388f186073cSJoerg Sonnenberger * are operating as an AP then this is an error. 389f186073cSJoerg Sonnenberger * Otherwise we just discard/ignore the rate. 390f186073cSJoerg Sonnenberger * Note that this is important for 11b stations 391f186073cSJoerg Sonnenberger * when they want to associate with an 11g AP. 392f186073cSJoerg Sonnenberger */ 393f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP && 394f186073cSJoerg Sonnenberger (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 395f186073cSJoerg Sonnenberger error++; 396f186073cSJoerg Sonnenberger ignore++; 397f186073cSJoerg Sonnenberger } 398f186073cSJoerg Sonnenberger } 399f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DODEL) { 400f186073cSJoerg Sonnenberger /* 401f186073cSJoerg Sonnenberger * Delete unacceptable rates. 402f186073cSJoerg Sonnenberger */ 403f186073cSJoerg Sonnenberger if (ignore) { 404f186073cSJoerg Sonnenberger nrs->rs_nrates--; 405f186073cSJoerg Sonnenberger for (j = i; j < nrs->rs_nrates; j++) 406f186073cSJoerg Sonnenberger nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 407f186073cSJoerg Sonnenberger nrs->rs_rates[j] = 0; 408f186073cSJoerg Sonnenberger continue; 409f186073cSJoerg Sonnenberger } 410f186073cSJoerg Sonnenberger } 411f186073cSJoerg Sonnenberger if (!ignore) 412f186073cSJoerg Sonnenberger okrate = nrs->rs_rates[i]; 413f186073cSJoerg Sonnenberger i++; 414f186073cSJoerg Sonnenberger } 415*841ab66cSSepherosa Ziehau if (okrate == 0 || error != 0 || 416*841ab66cSSepherosa Ziehau ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) 417f186073cSJoerg Sonnenberger return badrate | IEEE80211_RATE_BASIC; 418f186073cSJoerg Sonnenberger else 419f186073cSJoerg Sonnenberger return RV(okrate); 420f186073cSJoerg Sonnenberger #undef RV 421f186073cSJoerg Sonnenberger } 422f186073cSJoerg Sonnenberger 423*841ab66cSSepherosa Ziehau /* 424*841ab66cSSepherosa Ziehau * Reset 11g-related state. 425*841ab66cSSepherosa Ziehau */ 426*841ab66cSSepherosa Ziehau void 427*841ab66cSSepherosa Ziehau ieee80211_reset_erp(struct ieee80211com *ic) 428f186073cSJoerg Sonnenberger { 429*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT; 430*841ab66cSSepherosa Ziehau ic->ic_nonerpsta = 0; 431*841ab66cSSepherosa Ziehau ic->ic_longslotsta = 0; 432*841ab66cSSepherosa Ziehau /* 433*841ab66cSSepherosa Ziehau * Short slot time is enabled only when operating in 11g 434*841ab66cSSepherosa Ziehau * and not in an IBSS. We must also honor whether or not 435*841ab66cSSepherosa Ziehau * the driver is capable of doing it. 436*841ab66cSSepherosa Ziehau */ 437*841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic, 438*841ab66cSSepherosa Ziehau ic->ic_curmode == IEEE80211_MODE_11A || 439*841ab66cSSepherosa Ziehau (ic->ic_curmode == IEEE80211_MODE_11G && 440*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_HOSTAP && 441*841ab66cSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHSLOT))); 442*841ab66cSSepherosa Ziehau /* 443*841ab66cSSepherosa Ziehau * Set short preamble and ERP barker-preamble flags. 444*841ab66cSSepherosa Ziehau */ 445*841ab66cSSepherosa Ziehau if (ic->ic_curmode == IEEE80211_MODE_11A || 446*841ab66cSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 447*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 448*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEBARKER; 449*841ab66cSSepherosa Ziehau } else { 450*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 451*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_USEBARKER; 452*841ab66cSSepherosa Ziehau } 453*841ab66cSSepherosa Ziehau } 454*841ab66cSSepherosa Ziehau 455*841ab66cSSepherosa Ziehau /* 456*841ab66cSSepherosa Ziehau * Set the short slot time state and notify the driver. 457*841ab66cSSepherosa Ziehau */ 458*841ab66cSSepherosa Ziehau void 459*841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff) 460*841ab66cSSepherosa Ziehau { 461*841ab66cSSepherosa Ziehau if (onoff) 462*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHSLOT; 463*841ab66cSSepherosa Ziehau else 464*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHSLOT; 465*841ab66cSSepherosa Ziehau /* notify driver */ 466*841ab66cSSepherosa Ziehau if (ic->ic_updateslot != NULL) 467*841ab66cSSepherosa Ziehau ic->ic_updateslot(ic->ic_ifp); 468*841ab66cSSepherosa Ziehau } 469*841ab66cSSepherosa Ziehau 470*841ab66cSSepherosa Ziehau /* 471*841ab66cSSepherosa Ziehau * Check if the specified rate set supports ERP. 472*841ab66cSSepherosa Ziehau * NB: the rate set is assumed to be sorted. 473*841ab66cSSepherosa Ziehau */ 474*841ab66cSSepherosa Ziehau int 475*841ab66cSSepherosa Ziehau ieee80211_iserp_rateset(struct ieee80211com *ic, struct ieee80211_rateset *rs) 476*841ab66cSSepherosa Ziehau { 477*841ab66cSSepherosa Ziehau #define N(a) (sizeof(a) / sizeof(a[0])) 478*841ab66cSSepherosa Ziehau static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; 479*841ab66cSSepherosa Ziehau int i, j; 480*841ab66cSSepherosa Ziehau 481*841ab66cSSepherosa Ziehau if (rs->rs_nrates < N(rates)) 482*841ab66cSSepherosa Ziehau return 0; 483*841ab66cSSepherosa Ziehau for (i = 0; i < N(rates); i++) { 484*841ab66cSSepherosa Ziehau for (j = 0; j < rs->rs_nrates; j++) { 485*841ab66cSSepherosa Ziehau int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; 486*841ab66cSSepherosa Ziehau if (rates[i] == r) 487*841ab66cSSepherosa Ziehau goto next; 488*841ab66cSSepherosa Ziehau if (r > rates[i]) 489*841ab66cSSepherosa Ziehau return 0; 490*841ab66cSSepherosa Ziehau } 491*841ab66cSSepherosa Ziehau return 0; 492*841ab66cSSepherosa Ziehau next: 493*841ab66cSSepherosa Ziehau ; 494*841ab66cSSepherosa Ziehau } 495*841ab66cSSepherosa Ziehau return 1; 496*841ab66cSSepherosa Ziehau #undef N 497*841ab66cSSepherosa Ziehau } 498*841ab66cSSepherosa Ziehau 499*841ab66cSSepherosa Ziehau /* 500*841ab66cSSepherosa Ziehau * Mark the basic rates for the 11g rate table based on the 501*841ab66cSSepherosa Ziehau * operating mode. For real 11g we mark all the 11b rates 502*841ab66cSSepherosa Ziehau * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 503*841ab66cSSepherosa Ziehau * 11b rates. There's also a pseudo 11a-mode used to mark only 504*841ab66cSSepherosa Ziehau * the basic OFDM rates. 505*841ab66cSSepherosa Ziehau */ 506*841ab66cSSepherosa Ziehau void 507*841ab66cSSepherosa Ziehau ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) 508*841ab66cSSepherosa Ziehau { 509*841ab66cSSepherosa Ziehau static const struct ieee80211_rateset basic[] = { 510*841ab66cSSepherosa Ziehau { 0 }, /* IEEE80211_MODE_AUTO */ 511*841ab66cSSepherosa Ziehau { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 512*841ab66cSSepherosa Ziehau { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ 513*841ab66cSSepherosa Ziehau { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */ 514*841ab66cSSepherosa Ziehau { 0 }, /* IEEE80211_MODE_FH */ 515*841ab66cSSepherosa Ziehau /* IEEE80211_MODE_PUREG (not yet) */ 516*841ab66cSSepherosa Ziehau { 7, { 2, 4, 11, 22, 12, 24, 48 } }, 517*841ab66cSSepherosa Ziehau }; 518*841ab66cSSepherosa Ziehau int i, j; 519*841ab66cSSepherosa Ziehau 520*841ab66cSSepherosa Ziehau for (i = 0; i < rs->rs_nrates; i++) { 521*841ab66cSSepherosa Ziehau rs->rs_rates[i] &= IEEE80211_RATE_VAL; 522*841ab66cSSepherosa Ziehau for (j = 0; j < basic[mode].rs_nrates; j++) 523*841ab66cSSepherosa Ziehau if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 524*841ab66cSSepherosa Ziehau rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 525*841ab66cSSepherosa Ziehau break; 526*841ab66cSSepherosa Ziehau } 527*841ab66cSSepherosa Ziehau } 528*841ab66cSSepherosa Ziehau } 529*841ab66cSSepherosa Ziehau 530*841ab66cSSepherosa Ziehau /* 531*841ab66cSSepherosa Ziehau * WME protocol support. The following parameters come from the spec. 532*841ab66cSSepherosa Ziehau */ 533*841ab66cSSepherosa Ziehau typedef struct phyParamType { 534*841ab66cSSepherosa Ziehau uint8_t aifsn; 535*841ab66cSSepherosa Ziehau uint8_t logcwmin; 536*841ab66cSSepherosa Ziehau uint8_t logcwmax; 537*841ab66cSSepherosa Ziehau uint16_t txopLimit; 538*841ab66cSSepherosa Ziehau uint8_t acm; 539*841ab66cSSepherosa Ziehau } paramType; 540*841ab66cSSepherosa Ziehau 541*841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = { 542*841ab66cSSepherosa Ziehau { 3, 4, 6 }, /* IEEE80211_MODE_AUTO */ 543*841ab66cSSepherosa Ziehau { 3, 4, 6 }, /* IEEE80211_MODE_11A */ 544*841ab66cSSepherosa Ziehau { 3, 5, 7 }, /* IEEE80211_MODE_11B */ 545*841ab66cSSepherosa Ziehau { 3, 4, 6 }, /* IEEE80211_MODE_11G */ 546*841ab66cSSepherosa Ziehau { 3, 5, 7 }, /* IEEE80211_MODE_FH */ 547*841ab66cSSepherosa Ziehau { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_A */ 548*841ab66cSSepherosa Ziehau { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_G */ 549*841ab66cSSepherosa Ziehau }; 550*841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = { 551*841ab66cSSepherosa Ziehau { 7, 4, 10 }, /* IEEE80211_MODE_AUTO */ 552*841ab66cSSepherosa Ziehau { 7, 4, 10 }, /* IEEE80211_MODE_11A */ 553*841ab66cSSepherosa Ziehau { 7, 5, 10 }, /* IEEE80211_MODE_11B */ 554*841ab66cSSepherosa Ziehau { 7, 4, 10 }, /* IEEE80211_MODE_11G */ 555*841ab66cSSepherosa Ziehau { 7, 5, 10 }, /* IEEE80211_MODE_FH */ 556*841ab66cSSepherosa Ziehau { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 557*841ab66cSSepherosa Ziehau { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 558*841ab66cSSepherosa Ziehau }; 559*841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = { 560*841ab66cSSepherosa Ziehau { 1, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 561*841ab66cSSepherosa Ziehau { 1, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 562*841ab66cSSepherosa Ziehau { 1, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 563*841ab66cSSepherosa Ziehau { 1, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 564*841ab66cSSepherosa Ziehau { 1, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 565*841ab66cSSepherosa Ziehau { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 566*841ab66cSSepherosa Ziehau { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 567*841ab66cSSepherosa Ziehau }; 568*841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = { 569*841ab66cSSepherosa Ziehau { 1, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 570*841ab66cSSepherosa Ziehau { 1, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 571*841ab66cSSepherosa Ziehau { 1, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 572*841ab66cSSepherosa Ziehau { 1, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 573*841ab66cSSepherosa Ziehau { 1, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 574*841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 575*841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 576*841ab66cSSepherosa Ziehau }; 577*841ab66cSSepherosa Ziehau 578*841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = { 579*841ab66cSSepherosa Ziehau { 3, 4, 10 }, /* IEEE80211_MODE_AUTO */ 580*841ab66cSSepherosa Ziehau { 3, 4, 10 }, /* IEEE80211_MODE_11A */ 581*841ab66cSSepherosa Ziehau { 3, 5, 10 }, /* IEEE80211_MODE_11B */ 582*841ab66cSSepherosa Ziehau { 3, 4, 10 }, /* IEEE80211_MODE_11G */ 583*841ab66cSSepherosa Ziehau { 3, 5, 10 }, /* IEEE80211_MODE_FH */ 584*841ab66cSSepherosa Ziehau { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 585*841ab66cSSepherosa Ziehau { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 586*841ab66cSSepherosa Ziehau }; 587*841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = { 588*841ab66cSSepherosa Ziehau { 2, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 589*841ab66cSSepherosa Ziehau { 2, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 590*841ab66cSSepherosa Ziehau { 2, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 591*841ab66cSSepherosa Ziehau { 2, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 592*841ab66cSSepherosa Ziehau { 2, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 593*841ab66cSSepherosa Ziehau { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 594*841ab66cSSepherosa Ziehau { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 595*841ab66cSSepherosa Ziehau }; 596*841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = { 597*841ab66cSSepherosa Ziehau { 2, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 598*841ab66cSSepherosa Ziehau { 2, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 599*841ab66cSSepherosa Ziehau { 2, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 600*841ab66cSSepherosa Ziehau { 2, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 601*841ab66cSSepherosa Ziehau { 2, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 602*841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 603*841ab66cSSepherosa Ziehau { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 604*841ab66cSSepherosa Ziehau }; 605*841ab66cSSepherosa Ziehau 606*841ab66cSSepherosa Ziehau void 607*841ab66cSSepherosa Ziehau ieee80211_wme_initparams(struct ieee80211com *ic) 608*841ab66cSSepherosa Ziehau { 609*841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme; 610*841ab66cSSepherosa Ziehau const paramType *pPhyParam, *pBssPhyParam; 611*841ab66cSSepherosa Ziehau struct wmeParams *wmep; 612*841ab66cSSepherosa Ziehau int i; 613*841ab66cSSepherosa Ziehau 614*841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_WME) == 0) 615*841ab66cSSepherosa Ziehau return; 616*841ab66cSSepherosa Ziehau 617*841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) { 618*841ab66cSSepherosa Ziehau switch (i) { 619*841ab66cSSepherosa Ziehau case WME_AC_BK: 620*841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 621*841ab66cSSepherosa Ziehau pBssPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 622*841ab66cSSepherosa Ziehau break; 623*841ab66cSSepherosa Ziehau case WME_AC_VI: 624*841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_VI[ic->ic_curmode]; 625*841ab66cSSepherosa Ziehau pBssPhyParam = &bssPhyParamForAC_VI[ic->ic_curmode]; 626*841ab66cSSepherosa Ziehau break; 627*841ab66cSSepherosa Ziehau case WME_AC_VO: 628*841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_VO[ic->ic_curmode]; 629*841ab66cSSepherosa Ziehau pBssPhyParam = &bssPhyParamForAC_VO[ic->ic_curmode]; 630*841ab66cSSepherosa Ziehau break; 631*841ab66cSSepherosa Ziehau case WME_AC_BE: 632*841ab66cSSepherosa Ziehau default: 633*841ab66cSSepherosa Ziehau pPhyParam = &phyParamForAC_BE[ic->ic_curmode]; 634*841ab66cSSepherosa Ziehau pBssPhyParam = &bssPhyParamForAC_BE[ic->ic_curmode]; 635*841ab66cSSepherosa Ziehau break; 636*841ab66cSSepherosa Ziehau } 637*841ab66cSSepherosa Ziehau 638*841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 639*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 640*841ab66cSSepherosa Ziehau wmep->wmep_acm = pPhyParam->acm; 641*841ab66cSSepherosa Ziehau wmep->wmep_aifsn = pPhyParam->aifsn; 642*841ab66cSSepherosa Ziehau wmep->wmep_logcwmin = pPhyParam->logcwmin; 643*841ab66cSSepherosa Ziehau wmep->wmep_logcwmax = pPhyParam->logcwmax; 644*841ab66cSSepherosa Ziehau wmep->wmep_txopLimit = pPhyParam->txopLimit; 645*841ab66cSSepherosa Ziehau } else { 646*841ab66cSSepherosa Ziehau wmep->wmep_acm = pBssPhyParam->acm; 647*841ab66cSSepherosa Ziehau wmep->wmep_aifsn = pBssPhyParam->aifsn; 648*841ab66cSSepherosa Ziehau wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 649*841ab66cSSepherosa Ziehau wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 650*841ab66cSSepherosa Ziehau wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 651*841ab66cSSepherosa Ziehau 652*841ab66cSSepherosa Ziehau } 653*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 654*841ab66cSSepherosa Ziehau "%s: %s chan [acm %u aifsn %u log2(cwmin) %u " 655*841ab66cSSepherosa Ziehau "log2(cwmax) %u txpoLimit %u]\n", __func__ 656*841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[i] 657*841ab66cSSepherosa Ziehau , wmep->wmep_acm 658*841ab66cSSepherosa Ziehau , wmep->wmep_aifsn 659*841ab66cSSepherosa Ziehau , wmep->wmep_logcwmin 660*841ab66cSSepherosa Ziehau , wmep->wmep_logcwmax 661*841ab66cSSepherosa Ziehau , wmep->wmep_txopLimit 662*841ab66cSSepherosa Ziehau ); 663*841ab66cSSepherosa Ziehau 664*841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 665*841ab66cSSepherosa Ziehau wmep->wmep_acm = pBssPhyParam->acm; 666*841ab66cSSepherosa Ziehau wmep->wmep_aifsn = pBssPhyParam->aifsn; 667*841ab66cSSepherosa Ziehau wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 668*841ab66cSSepherosa Ziehau wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 669*841ab66cSSepherosa Ziehau wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 670*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 671*841ab66cSSepherosa Ziehau "%s: %s bss [acm %u aifsn %u log2(cwmin) %u " 672*841ab66cSSepherosa Ziehau "log2(cwmax) %u txpoLimit %u]\n", __func__ 673*841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[i] 674*841ab66cSSepherosa Ziehau , wmep->wmep_acm 675*841ab66cSSepherosa Ziehau , wmep->wmep_aifsn 676*841ab66cSSepherosa Ziehau , wmep->wmep_logcwmin 677*841ab66cSSepherosa Ziehau , wmep->wmep_logcwmax 678*841ab66cSSepherosa Ziehau , wmep->wmep_txopLimit 679*841ab66cSSepherosa Ziehau ); 680*841ab66cSSepherosa Ziehau } 681*841ab66cSSepherosa Ziehau /* NB: check ic_bss to avoid NULL deref on initial attach */ 682*841ab66cSSepherosa Ziehau if (ic->ic_bss != NULL) { 683*841ab66cSSepherosa Ziehau /* 684*841ab66cSSepherosa Ziehau * Calculate agressive mode switching threshold based 685*841ab66cSSepherosa Ziehau * on beacon interval. This doesn't need locking since 686*841ab66cSSepherosa Ziehau * we're only called before entering the RUN state at 687*841ab66cSSepherosa Ziehau * which point we start sending beacon frames. 688*841ab66cSSepherosa Ziehau */ 689*841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh = 690*841ab66cSSepherosa Ziehau (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->ni_intval) / 100; 691*841ab66cSSepherosa Ziehau ieee80211_wme_updateparams(ic); 692*841ab66cSSepherosa Ziehau } 693*841ab66cSSepherosa Ziehau } 694*841ab66cSSepherosa Ziehau 695*841ab66cSSepherosa Ziehau /* 696*841ab66cSSepherosa Ziehau * Update WME parameters for ourself and the BSS. 697*841ab66cSSepherosa Ziehau */ 698*841ab66cSSepherosa Ziehau void 699*841ab66cSSepherosa Ziehau ieee80211_wme_updateparams(struct ieee80211com *ic) 700*841ab66cSSepherosa Ziehau { 701*841ab66cSSepherosa Ziehau static const paramType phyParam[IEEE80211_MODE_MAX] = { 702*841ab66cSSepherosa Ziehau { 2, 4, 10, 64 }, /* IEEE80211_MODE_AUTO */ 703*841ab66cSSepherosa Ziehau { 2, 4, 10, 64 }, /* IEEE80211_MODE_11A */ 704*841ab66cSSepherosa Ziehau { 2, 5, 10, 64 }, /* IEEE80211_MODE_11B */ 705*841ab66cSSepherosa Ziehau { 2, 4, 10, 64 }, /* IEEE80211_MODE_11G */ 706*841ab66cSSepherosa Ziehau { 2, 5, 10, 64 }, /* IEEE80211_MODE_FH */ 707*841ab66cSSepherosa Ziehau { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_A */ 708*841ab66cSSepherosa Ziehau { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_G */ 709*841ab66cSSepherosa Ziehau }; 710*841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme; 711*841ab66cSSepherosa Ziehau const struct wmeParams *wmep; 712*841ab66cSSepherosa Ziehau struct wmeParams *chanp, *bssp; 713*841ab66cSSepherosa Ziehau int i; 714*841ab66cSSepherosa Ziehau 715*841ab66cSSepherosa Ziehau ASSERT_SERIALIZED(ic->ic_ifp->if_serializer); 716*841ab66cSSepherosa Ziehau 717*841ab66cSSepherosa Ziehau if ((ic->ic_caps & IEEE80211_C_WME) == 0) 718*841ab66cSSepherosa Ziehau return; 719*841ab66cSSepherosa Ziehau 720*841ab66cSSepherosa Ziehau /* set up the channel access parameters for the physical device */ 721*841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) { 722*841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[i]; 723*841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 724*841ab66cSSepherosa Ziehau chanp->wmep_aifsn = wmep->wmep_aifsn; 725*841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = wmep->wmep_logcwmin; 726*841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = wmep->wmep_logcwmax; 727*841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = wmep->wmep_txopLimit; 728*841ab66cSSepherosa Ziehau 729*841ab66cSSepherosa Ziehau chanp = &wme->wme_bssChanParams.cap_wmeParams[i]; 730*841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 731*841ab66cSSepherosa Ziehau chanp->wmep_aifsn = wmep->wmep_aifsn; 732*841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = wmep->wmep_logcwmin; 733*841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = wmep->wmep_logcwmax; 734*841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = wmep->wmep_txopLimit; 735*841ab66cSSepherosa Ziehau } 736*841ab66cSSepherosa Ziehau 737*841ab66cSSepherosa Ziehau /* 738*841ab66cSSepherosa Ziehau * This implements agressive mode as found in certain 739*841ab66cSSepherosa Ziehau * vendors' AP's. When there is significant high 740*841ab66cSSepherosa Ziehau * priority (VI/VO) traffic in the BSS throttle back BE 741*841ab66cSSepherosa Ziehau * traffic by using conservative parameters. Otherwise 742*841ab66cSSepherosa Ziehau * BE uses agressive params to optimize performance of 743*841ab66cSSepherosa Ziehau * legacy/non-QoS traffic. 744*841ab66cSSepherosa Ziehau */ 745*841ab66cSSepherosa Ziehau if ((ic->ic_opmode == IEEE80211_M_HOSTAP && 746*841ab66cSSepherosa Ziehau (wme->wme_flags & WME_F_AGGRMODE) != 0) || 747*841ab66cSSepherosa Ziehau (ic->ic_opmode == IEEE80211_M_STA && 748*841ab66cSSepherosa Ziehau (ic->ic_bss->ni_flags & IEEE80211_NODE_QOS) == 0) || 749*841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_WME) == 0) { 750*841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 751*841ab66cSSepherosa Ziehau bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 752*841ab66cSSepherosa Ziehau 753*841ab66cSSepherosa Ziehau chanp->wmep_aifsn = bssp->wmep_aifsn = 754*841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].aifsn; 755*841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = bssp->wmep_logcwmin = 756*841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].logcwmin; 757*841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = bssp->wmep_logcwmax = 758*841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].logcwmax; 759*841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = bssp->wmep_txopLimit = 760*841ab66cSSepherosa Ziehau (ic->ic_flags & IEEE80211_F_BURST) ? 761*841ab66cSSepherosa Ziehau phyParam[ic->ic_curmode].txopLimit : 0; 762*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 763*841ab66cSSepherosa Ziehau "%s: %s [acm %u aifsn %u log2(cwmin) %u " 764*841ab66cSSepherosa Ziehau "log2(cwmax) %u txpoLimit %u]\n", __func__ 765*841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[WME_AC_BE] 766*841ab66cSSepherosa Ziehau , chanp->wmep_acm 767*841ab66cSSepherosa Ziehau , chanp->wmep_aifsn 768*841ab66cSSepherosa Ziehau , chanp->wmep_logcwmin 769*841ab66cSSepherosa Ziehau , chanp->wmep_logcwmax 770*841ab66cSSepherosa Ziehau , chanp->wmep_txopLimit 771*841ab66cSSepherosa Ziehau ); 772*841ab66cSSepherosa Ziehau } 773*841ab66cSSepherosa Ziehau 774*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && 775*841ab66cSSepherosa Ziehau ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) { 776*841ab66cSSepherosa Ziehau static const uint8_t logCwMin[IEEE80211_MODE_MAX] = { 777*841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_AUTO */ 778*841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_11A */ 779*841ab66cSSepherosa Ziehau 4, /* IEEE80211_MODE_11B */ 780*841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_11G */ 781*841ab66cSSepherosa Ziehau 4, /* IEEE80211_MODE_FH */ 782*841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_TURBO_A */ 783*841ab66cSSepherosa Ziehau 3, /* IEEE80211_MODE_TURBO_G */ 784*841ab66cSSepherosa Ziehau }; 785*841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 786*841ab66cSSepherosa Ziehau bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 787*841ab66cSSepherosa Ziehau 788*841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = bssp->wmep_logcwmin = 789*841ab66cSSepherosa Ziehau logCwMin[ic->ic_curmode]; 790*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 791*841ab66cSSepherosa Ziehau "%s: %s log2(cwmin) %u\n", __func__ 792*841ab66cSSepherosa Ziehau , ieee80211_wme_acnames[WME_AC_BE] 793*841ab66cSSepherosa Ziehau , chanp->wmep_logcwmin 794*841ab66cSSepherosa Ziehau ); 795*841ab66cSSepherosa Ziehau } 796*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */ 797*841ab66cSSepherosa Ziehau /* 798*841ab66cSSepherosa Ziehau * Arrange for a beacon update and bump the parameter 799*841ab66cSSepherosa Ziehau * set number so associated stations load the new values. 800*841ab66cSSepherosa Ziehau */ 801*841ab66cSSepherosa Ziehau wme->wme_bssChanParams.cap_info = 802*841ab66cSSepherosa Ziehau (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT; 803*841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_WMEUPDATE; 804*841ab66cSSepherosa Ziehau } 805*841ab66cSSepherosa Ziehau 806*841ab66cSSepherosa Ziehau wme->wme_update(ic); 807*841ab66cSSepherosa Ziehau 808*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 809*841ab66cSSepherosa Ziehau "%s: WME params updated, cap_info 0x%x\n", __func__, 810*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_STA ? 811*841ab66cSSepherosa Ziehau wme->wme_wmeChanParams.cap_info : 812*841ab66cSSepherosa Ziehau wme->wme_bssChanParams.cap_info); 813*841ab66cSSepherosa Ziehau } 814*841ab66cSSepherosa Ziehau 815*841ab66cSSepherosa Ziehau void 816*841ab66cSSepherosa Ziehau ieee80211_beacon_miss(struct ieee80211com *ic) 817*841ab66cSSepherosa Ziehau { 818*841ab66cSSepherosa Ziehau 819*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_SCAN) { 820*841ab66cSSepherosa Ziehau /* XXX check ic_curchan != ic_bsschan? */ 821*841ab66cSSepherosa Ziehau return; 822*841ab66cSSepherosa Ziehau } 823*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, 824*841ab66cSSepherosa Ziehau IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 825*841ab66cSSepherosa Ziehau "%s\n", "beacon miss"); 826*841ab66cSSepherosa Ziehau 827*841ab66cSSepherosa Ziehau /* 828*841ab66cSSepherosa Ziehau * Our handling is only meaningful for stations that are 829*841ab66cSSepherosa Ziehau * associated; any other conditions else will be handled 830*841ab66cSSepherosa Ziehau * through different means (e.g. the tx timeout on mgt frames). 831*841ab66cSSepherosa Ziehau */ 832*841ab66cSSepherosa Ziehau if (ic->ic_opmode != IEEE80211_M_STA || ic->ic_state != IEEE80211_S_RUN) 833*841ab66cSSepherosa Ziehau return; 834*841ab66cSSepherosa Ziehau 835*841ab66cSSepherosa Ziehau if (++ic->ic_bmiss_count < ic->ic_bmiss_max) { 836*841ab66cSSepherosa Ziehau /* 837*841ab66cSSepherosa Ziehau * Send a directed probe req before falling back to a scan; 838*841ab66cSSepherosa Ziehau * if we receive a response ic_bmiss_count will be reset. 839*841ab66cSSepherosa Ziehau * Some cards mistakenly report beacon miss so this avoids 840*841ab66cSSepherosa Ziehau * the expensive scan if the ap is still there. 841*841ab66cSSepherosa Ziehau */ 842*841ab66cSSepherosa Ziehau ieee80211_send_probereq(ic->ic_bss, ic->ic_myaddr, 843*841ab66cSSepherosa Ziehau ic->ic_bss->ni_bssid, ic->ic_bss->ni_bssid, 844*841ab66cSSepherosa Ziehau ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen, 845*841ab66cSSepherosa Ziehau ic->ic_opt_ie, ic->ic_opt_ie_len); 846*841ab66cSSepherosa Ziehau return; 847*841ab66cSSepherosa Ziehau } 848*841ab66cSSepherosa Ziehau ic->ic_bmiss_count = 0; 849*841ab66cSSepherosa Ziehau ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); 850*841ab66cSSepherosa Ziehau } 851*841ab66cSSepherosa Ziehau 852*841ab66cSSepherosa Ziehau /* 853*841ab66cSSepherosa Ziehau * Software beacon miss handling. Check if any beacons 854*841ab66cSSepherosa Ziehau * were received in the last period. If not post a 855*841ab66cSSepherosa Ziehau * beacon miss; otherwise reset the counter. 856*841ab66cSSepherosa Ziehau */ 857*841ab66cSSepherosa Ziehau static void 858*841ab66cSSepherosa Ziehau ieee80211_swbmiss(void *arg) 859*841ab66cSSepherosa Ziehau { 860*841ab66cSSepherosa Ziehau struct ieee80211com *ic = arg; 861*841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 862*841ab66cSSepherosa Ziehau 863*841ab66cSSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 864*841ab66cSSepherosa Ziehau 865*841ab66cSSepherosa Ziehau if (ic->ic_swbmiss_count == 0) { 866*841ab66cSSepherosa Ziehau ieee80211_beacon_miss(ic); 867*841ab66cSSepherosa Ziehau if (ic->ic_bmiss_count == 0) /* don't re-arm timer */ 868*841ab66cSSepherosa Ziehau goto back; 869*841ab66cSSepherosa Ziehau } else 870*841ab66cSSepherosa Ziehau ic->ic_swbmiss_count = 0; 871*841ab66cSSepherosa Ziehau callout_reset(&ic->ic_swbmiss, ic->ic_swbmiss_period, 872*841ab66cSSepherosa Ziehau ieee80211_swbmiss, ic); 873*841ab66cSSepherosa Ziehau 874*841ab66cSSepherosa Ziehau back: 875*841ab66cSSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 876*841ab66cSSepherosa Ziehau } 877*841ab66cSSepherosa Ziehau 878*841ab66cSSepherosa Ziehau static void 879*841ab66cSSepherosa Ziehau sta_disassoc(void *arg, struct ieee80211_node *ni) 880*841ab66cSSepherosa Ziehau { 881*841ab66cSSepherosa Ziehau struct ieee80211com *ic = arg; 882*841ab66cSSepherosa Ziehau 883*841ab66cSSepherosa Ziehau if (ni->ni_associd != 0) { 884*841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, 885*841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_LEAVE); 886*841ab66cSSepherosa Ziehau ieee80211_node_leave(ic, ni); 887*841ab66cSSepherosa Ziehau } 888*841ab66cSSepherosa Ziehau } 889*841ab66cSSepherosa Ziehau 890*841ab66cSSepherosa Ziehau static void 891*841ab66cSSepherosa Ziehau sta_deauth(void *arg, struct ieee80211_node *ni) 892*841ab66cSSepherosa Ziehau { 893*841ab66cSSepherosa Ziehau struct ieee80211com *ic = arg; 894*841ab66cSSepherosa Ziehau 895*841ab66cSSepherosa Ziehau IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, 896*841ab66cSSepherosa Ziehau IEEE80211_REASON_ASSOC_LEAVE); 897*841ab66cSSepherosa Ziehau } 898*841ab66cSSepherosa Ziehau 899*841ab66cSSepherosa Ziehau static int 900*841ab66cSSepherosa Ziehau ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 901*841ab66cSSepherosa Ziehau { 902*841ab66cSSepherosa Ziehau struct ifnet *ifp = ic->ic_ifp; 903f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 904f186073cSJoerg Sonnenberger enum ieee80211_state ostate; 905f186073cSJoerg Sonnenberger 906f186073cSJoerg Sonnenberger ostate = ic->ic_state; 907*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__, 908*841ab66cSSepherosa Ziehau ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 909f186073cSJoerg Sonnenberger ic->ic_state = nstate; /* state transition */ 910f186073cSJoerg Sonnenberger ni = ic->ic_bss; /* NB: no reference held */ 911*841ab66cSSepherosa Ziehau if (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS) 912*841ab66cSSepherosa Ziehau callout_stop(&ic->ic_swbmiss); 913f186073cSJoerg Sonnenberger switch (nstate) { 914f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 915f186073cSJoerg Sonnenberger switch (ostate) { 916f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 917f186073cSJoerg Sonnenberger break; 918f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 919f186073cSJoerg Sonnenberger switch (ic->ic_opmode) { 920f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 921f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 922f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DISASSOC, 923f186073cSJoerg Sonnenberger IEEE80211_REASON_ASSOC_LEAVE); 924*841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 925f186073cSJoerg Sonnenberger break; 926f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 927*841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(&ic->ic_sta, 928*841ab66cSSepherosa Ziehau sta_disassoc, ic); 929f186073cSJoerg Sonnenberger break; 930f186073cSJoerg Sonnenberger default: 931f186073cSJoerg Sonnenberger break; 932f186073cSJoerg Sonnenberger } 933*841ab66cSSepherosa Ziehau goto reset; 934f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 935f186073cSJoerg Sonnenberger switch (ic->ic_opmode) { 936f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 937f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 938f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 939f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_LEAVE); 940f186073cSJoerg Sonnenberger break; 941f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 942*841ab66cSSepherosa Ziehau ieee80211_iterate_nodes(&ic->ic_sta, 943*841ab66cSSepherosa Ziehau sta_deauth, ic); 944f186073cSJoerg Sonnenberger break; 945f186073cSJoerg Sonnenberger default: 946f186073cSJoerg Sonnenberger break; 947f186073cSJoerg Sonnenberger } 948*841ab66cSSepherosa Ziehau goto reset; 949f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 950*841ab66cSSepherosa Ziehau ieee80211_cancel_scan(ic); 951*841ab66cSSepherosa Ziehau goto reset; 952*841ab66cSSepherosa Ziehau case IEEE80211_S_AUTH: 953*841ab66cSSepherosa Ziehau reset: 954f186073cSJoerg Sonnenberger ic->ic_mgt_timer = 0; 955f186073cSJoerg Sonnenberger IF_DRAIN(&ic->ic_mgtq); 956*841ab66cSSepherosa Ziehau ieee80211_reset_bss(ic); 957f186073cSJoerg Sonnenberger break; 958f186073cSJoerg Sonnenberger } 959*841ab66cSSepherosa Ziehau if (ic->ic_auth->ia_detach != NULL) 960*841ab66cSSepherosa Ziehau ic->ic_auth->ia_detach(ic); 961f186073cSJoerg Sonnenberger break; 962f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 963f186073cSJoerg Sonnenberger switch (ostate) { 964f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 965*841ab66cSSepherosa Ziehau if ((ic->ic_opmode == IEEE80211_M_HOSTAP || 966*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_IBSS || 967*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_AHDEMO) && 968f186073cSJoerg Sonnenberger ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 969f186073cSJoerg Sonnenberger /* 970f186073cSJoerg Sonnenberger * AP operation and we already have a channel; 971f186073cSJoerg Sonnenberger * bypass the scan and startup immediately. 972f186073cSJoerg Sonnenberger */ 973f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_des_chan); 974f186073cSJoerg Sonnenberger } else { 975*841ab66cSSepherosa Ziehau ieee80211_begin_scan(ic, arg); 976f186073cSJoerg Sonnenberger } 977f186073cSJoerg Sonnenberger break; 978f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 979*841ab66cSSepherosa Ziehau /* 980*841ab66cSSepherosa Ziehau * Scan next. If doing an active scan probe 981*841ab66cSSepherosa Ziehau * for the requested ap (if any). 982*841ab66cSSepherosa Ziehau */ 983*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_ASCAN) 984*841ab66cSSepherosa Ziehau ieee80211_probe_curchan(ic, 0); 985f186073cSJoerg Sonnenberger break; 986f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 987f186073cSJoerg Sonnenberger /* beacon miss */ 988*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, 989*841ab66cSSepherosa Ziehau "no recent beacons from %6D; rescanning\n", 990f186073cSJoerg Sonnenberger ic->ic_bss->ni_bssid, ":"); 991*841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 992*841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */ 993f186073cSJoerg Sonnenberger /* FALLTHRU */ 994f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 995f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 996f186073cSJoerg Sonnenberger /* timeout restart scan */ 997*841ab66cSSepherosa Ziehau ni = ieee80211_find_node(&ic->ic_scan, 998*841ab66cSSepherosa Ziehau ic->ic_bss->ni_macaddr); 999f186073cSJoerg Sonnenberger if (ni != NULL) { 1000f186073cSJoerg Sonnenberger ni->ni_fails++; 1001f186073cSJoerg Sonnenberger ieee80211_unref_node(&ni); 1002f186073cSJoerg Sonnenberger } 1003*841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) 1004*841ab66cSSepherosa Ziehau ieee80211_begin_scan(ic, arg); 1005f186073cSJoerg Sonnenberger break; 1006f186073cSJoerg Sonnenberger } 1007f186073cSJoerg Sonnenberger break; 1008f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1009f186073cSJoerg Sonnenberger switch (ostate) { 1010f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 1011f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 1012f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1013f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 1); 1014f186073cSJoerg Sonnenberger break; 1015f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1016f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1017*841ab66cSSepherosa Ziehau switch (arg) { 1018f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 1019f186073cSJoerg Sonnenberger /* ??? */ 1020f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1021f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 2); 1022f186073cSJoerg Sonnenberger break; 1023f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 1024f186073cSJoerg Sonnenberger /* ignore and retry scan on timeout */ 1025f186073cSJoerg Sonnenberger break; 1026f186073cSJoerg Sonnenberger } 1027f186073cSJoerg Sonnenberger break; 1028f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1029*841ab66cSSepherosa Ziehau switch (arg) { 1030f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 1031f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1032f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 2); 1033f186073cSJoerg Sonnenberger ic->ic_state = ostate; /* stay RUN */ 1034f186073cSJoerg Sonnenberger break; 1035f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 1036*841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 1037*841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 1038f186073cSJoerg Sonnenberger /* try to reauth */ 1039f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1040f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 1); 1041*841ab66cSSepherosa Ziehau } 1042f186073cSJoerg Sonnenberger break; 1043f186073cSJoerg Sonnenberger } 1044f186073cSJoerg Sonnenberger break; 1045f186073cSJoerg Sonnenberger } 1046f186073cSJoerg Sonnenberger break; 1047f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1048f186073cSJoerg Sonnenberger switch (ostate) { 1049f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 1050f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 1051f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 1052*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 1053*841ab66cSSepherosa Ziehau "%s: invalid transition\n", __func__); 1054f186073cSJoerg Sonnenberger break; 1055f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1056f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1057f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 1058f186073cSJoerg Sonnenberger break; 1059f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1060*841ab66cSSepherosa Ziehau ieee80211_sta_leave(ic, ni); 1061*841ab66cSSepherosa Ziehau if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 1062f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 1063f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 1064*841ab66cSSepherosa Ziehau } 1065f186073cSJoerg Sonnenberger break; 1066f186073cSJoerg Sonnenberger } 1067f186073cSJoerg Sonnenberger break; 1068f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1069*841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_WPA) { 1070*841ab66cSSepherosa Ziehau /* XXX validate prerequisites */ 1071*841ab66cSSepherosa Ziehau } 1072f186073cSJoerg Sonnenberger switch (ostate) { 1073f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 1074*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_MONITOR) 1075*841ab66cSSepherosa Ziehau break; 1076*841ab66cSSepherosa Ziehau /* fall thru... */ 1077f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 1078*841ab66cSSepherosa Ziehau IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 1079*841ab66cSSepherosa Ziehau "%s: invalid transition\n", __func__); 1080*841ab66cSSepherosa Ziehau /* fall thru... */ 1081f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 1082f186073cSJoerg Sonnenberger break; 1083f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 1084f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: /* infra mode */ 1085f186073cSJoerg Sonnenberger KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 1086f186073cSJoerg Sonnenberger ("%s: bogus xmit rate %u setup\n", __func__, 1087f186073cSJoerg Sonnenberger ni->ni_txrate)); 1088*841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 1089*841ab66cSSepherosa Ziehau if (ieee80211_msg_debug(ic)) { 1090f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_STA) 1091*841ab66cSSepherosa Ziehau if_printf(ifp, "associated "); 1092f186073cSJoerg Sonnenberger else 1093*841ab66cSSepherosa Ziehau if_printf(ifp, "synchronized "); 1094f186073cSJoerg Sonnenberger printf("with %6D ssid ", ni->ni_bssid, ":"); 1095f186073cSJoerg Sonnenberger ieee80211_print_essid(ic->ic_bss->ni_essid, 1096f186073cSJoerg Sonnenberger ni->ni_esslen); 1097f186073cSJoerg Sonnenberger printf(" channel %d start %uMb\n", 1098*841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 1099f186073cSJoerg Sonnenberger IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 1100f186073cSJoerg Sonnenberger } 1101*841ab66cSSepherosa Ziehau #endif 1102f186073cSJoerg Sonnenberger ic->ic_mgt_timer = 0; 1103*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_STA) 1104*841ab66cSSepherosa Ziehau ieee80211_notify_node_join(ic, ni, 1105*841ab66cSSepherosa Ziehau arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 1106*841ab66cSSepherosa Ziehau ifp->if_start(ifp); /* XXX not authorized yet */ 1107f186073cSJoerg Sonnenberger break; 1108f186073cSJoerg Sonnenberger } 1109*841ab66cSSepherosa Ziehau if (ostate != IEEE80211_S_RUN && 1110*841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_STA && 1111*841ab66cSSepherosa Ziehau (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS)) { 1112*841ab66cSSepherosa Ziehau /* 1113*841ab66cSSepherosa Ziehau * Start s/w beacon miss timer for devices w/o 1114*841ab66cSSepherosa Ziehau * hardware support. We fudge a bit here since 1115*841ab66cSSepherosa Ziehau * we're doing this in software. 1116*841ab66cSSepherosa Ziehau */ 1117*841ab66cSSepherosa Ziehau ic->ic_swbmiss_period = IEEE80211_TU_TO_TICKS( 1118*841ab66cSSepherosa Ziehau 2 * ic->ic_bmissthreshold * ni->ni_intval); 1119*841ab66cSSepherosa Ziehau ic->ic_swbmiss_count = 0; 1120*841ab66cSSepherosa Ziehau callout_reset(&ic->ic_swbmiss, ic->ic_swbmiss_period, 1121*841ab66cSSepherosa Ziehau ieee80211_swbmiss, ic); 1122*841ab66cSSepherosa Ziehau } 1123*841ab66cSSepherosa Ziehau /* 1124*841ab66cSSepherosa Ziehau * Start/stop the authenticator when operating as an 1125*841ab66cSSepherosa Ziehau * AP. We delay until here to allow configuration to 1126*841ab66cSSepherosa Ziehau * happen out of order. 1127*841ab66cSSepherosa Ziehau */ 1128*841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */ 1129*841ab66cSSepherosa Ziehau ic->ic_auth->ia_attach != NULL) { 1130*841ab66cSSepherosa Ziehau /* XXX check failure */ 1131*841ab66cSSepherosa Ziehau ic->ic_auth->ia_attach(ic); 1132*841ab66cSSepherosa Ziehau } else if (ic->ic_auth->ia_detach != NULL) { 1133*841ab66cSSepherosa Ziehau ic->ic_auth->ia_detach(ic); 1134*841ab66cSSepherosa Ziehau } 1135*841ab66cSSepherosa Ziehau /* 1136*841ab66cSSepherosa Ziehau * When 802.1x is not in use mark the port authorized 1137*841ab66cSSepherosa Ziehau * at this point so traffic can flow. 1138*841ab66cSSepherosa Ziehau */ 1139*841ab66cSSepherosa Ziehau if (ni->ni_authmode != IEEE80211_AUTH_8021X) 1140*841ab66cSSepherosa Ziehau ieee80211_node_authorize(ni); 1141*841ab66cSSepherosa Ziehau /* 1142*841ab66cSSepherosa Ziehau * Enable inactivity processing. 1143*841ab66cSSepherosa Ziehau * XXX 1144*841ab66cSSepherosa Ziehau */ 1145*841ab66cSSepherosa Ziehau ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT; 1146*841ab66cSSepherosa Ziehau ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT; 1147f186073cSJoerg Sonnenberger break; 1148f186073cSJoerg Sonnenberger } 1149f186073cSJoerg Sonnenberger return 0; 1150f186073cSJoerg Sonnenberger } 1151