132176cfdSRui Paulo /*-
2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe
332176cfdSRui Paulo * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
44f655ef5SMatthew Dillon * Copyright (c) 2012 IEEE
5f186073cSJoerg Sonnenberger * All rights reserved.
6f186073cSJoerg Sonnenberger *
7f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
8f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions
9f186073cSJoerg Sonnenberger * are met:
10f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
11f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
12f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
13f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
14f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
15f186073cSJoerg Sonnenberger *
16f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f186073cSJoerg Sonnenberger */
27f186073cSJoerg Sonnenberger
28085ff963SMatthew Dillon #include <sys/cdefs.h>
29085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
30085ff963SMatthew Dillon
31f186073cSJoerg Sonnenberger /*
32f186073cSJoerg Sonnenberger * IEEE 802.11 protocol support.
33f186073cSJoerg Sonnenberger */
34f186073cSJoerg Sonnenberger
35f186073cSJoerg Sonnenberger #include "opt_inet.h"
3632176cfdSRui Paulo #include "opt_wlan.h"
37f186073cSJoerg Sonnenberger
38f186073cSJoerg Sonnenberger #include <sys/param.h>
39841ab66cSSepherosa Ziehau #include <sys/systm.h>
404f655ef5SMatthew Dillon #include <sys/kernel.h>
414f655ef5SMatthew Dillon #include <sys/malloc.h>
42f186073cSJoerg Sonnenberger
43841ab66cSSepherosa Ziehau #include <sys/socket.h>
4432176cfdSRui Paulo #include <sys/sockio.h>
45f186073cSJoerg Sonnenberger
46f186073cSJoerg Sonnenberger #include <net/if.h>
47085ff963SMatthew Dillon #include <net/if_var.h>
48841ab66cSSepherosa Ziehau #include <net/if_media.h>
49085ff963SMatthew Dillon #include <net/ethernet.h> /* XXX for ether_sprintf */
50085ff963SMatthew Dillon
51085ff963SMatthew Dillon #if defined(__DragonFly__)
529ed293e0SSepherosa Ziehau #include <net/ifq_var.h>
53085ff963SMatthew Dillon #endif
54f186073cSJoerg Sonnenberger
55f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h>
5632176cfdSRui Paulo #include <netproto/802_11/ieee80211_adhoc.h>
5732176cfdSRui Paulo #include <netproto/802_11/ieee80211_sta.h>
5832176cfdSRui Paulo #include <netproto/802_11/ieee80211_hostap.h>
5932176cfdSRui Paulo #include <netproto/802_11/ieee80211_wds.h>
6032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH
6132176cfdSRui Paulo #include <netproto/802_11/ieee80211_mesh.h>
6232176cfdSRui Paulo #endif
6332176cfdSRui Paulo #include <netproto/802_11/ieee80211_monitor.h>
6432176cfdSRui Paulo #include <netproto/802_11/ieee80211_input.h>
65f186073cSJoerg Sonnenberger
66841ab66cSSepherosa Ziehau /* XXX tunables */
67841ab66cSSepherosa Ziehau #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */
68841ab66cSSepherosa Ziehau #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */
69f186073cSJoerg Sonnenberger
704f655ef5SMatthew Dillon const char *mgt_subtype_name[] = {
7132176cfdSRui Paulo "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
724f655ef5SMatthew Dillon "probe_req", "probe_resp", "timing_adv", "reserved#7",
7332176cfdSRui Paulo "beacon", "atim", "disassoc", "auth",
74085ff963SMatthew Dillon "deauth", "action", "action_noack", "reserved#15"
7532176cfdSRui Paulo };
764f655ef5SMatthew Dillon const char *ctl_subtype_name[] = {
7732176cfdSRui Paulo "reserved#0", "reserved#1", "reserved#2", "reserved#3",
784f655ef5SMatthew Dillon "reserved#4", "reserved#5", "reserved#6", "control_wrap",
794f655ef5SMatthew Dillon "bar", "ba", "ps_poll", "rts",
8032176cfdSRui Paulo "cts", "ack", "cf_end", "cf_end_ack"
8132176cfdSRui Paulo };
8232176cfdSRui Paulo const char *ieee80211_opmode_name[IEEE80211_OPMODE_MAX] = {
8332176cfdSRui Paulo "IBSS", /* IEEE80211_M_IBSS */
8432176cfdSRui Paulo "STA", /* IEEE80211_M_STA */
8532176cfdSRui Paulo "WDS", /* IEEE80211_M_WDS */
8632176cfdSRui Paulo "AHDEMO", /* IEEE80211_M_AHDEMO */
8732176cfdSRui Paulo "HOSTAP", /* IEEE80211_M_HOSTAP */
8832176cfdSRui Paulo "MONITOR", /* IEEE80211_M_MONITOR */
8932176cfdSRui Paulo "MBSS" /* IEEE80211_M_MBSS */
9032176cfdSRui Paulo };
91f186073cSJoerg Sonnenberger const char *ieee80211_state_name[IEEE80211_S_MAX] = {
92f186073cSJoerg Sonnenberger "INIT", /* IEEE80211_S_INIT */
93f186073cSJoerg Sonnenberger "SCAN", /* IEEE80211_S_SCAN */
94f186073cSJoerg Sonnenberger "AUTH", /* IEEE80211_S_AUTH */
95f186073cSJoerg Sonnenberger "ASSOC", /* IEEE80211_S_ASSOC */
9632176cfdSRui Paulo "CAC", /* IEEE80211_S_CAC */
9732176cfdSRui Paulo "RUN", /* IEEE80211_S_RUN */
9832176cfdSRui Paulo "CSA", /* IEEE80211_S_CSA */
9932176cfdSRui Paulo "SLEEP", /* IEEE80211_S_SLEEP */
100f186073cSJoerg Sonnenberger };
101841ab66cSSepherosa Ziehau const char *ieee80211_wme_acnames[] = {
102841ab66cSSepherosa Ziehau "WME_AC_BE",
103841ab66cSSepherosa Ziehau "WME_AC_BK",
104841ab66cSSepherosa Ziehau "WME_AC_VI",
105841ab66cSSepherosa Ziehau "WME_AC_VO",
106841ab66cSSepherosa Ziehau "WME_UPSD",
107841ab66cSSepherosa Ziehau };
108f186073cSJoerg Sonnenberger
1094f655ef5SMatthew Dillon
1104f655ef5SMatthew Dillon /*
1114f655ef5SMatthew Dillon * Reason code descriptions were (mostly) obtained from
1124f655ef5SMatthew Dillon * IEEE Std 802.11-2012, pp. 442-445 Table 8-36.
1134f655ef5SMatthew Dillon */
1144f655ef5SMatthew Dillon const char *
ieee80211_reason_to_string(uint16_t reason)1154f655ef5SMatthew Dillon ieee80211_reason_to_string(uint16_t reason)
1164f655ef5SMatthew Dillon {
1174f655ef5SMatthew Dillon switch (reason) {
1184f655ef5SMatthew Dillon case IEEE80211_REASON_UNSPECIFIED:
1194f655ef5SMatthew Dillon return ("unspecified");
1204f655ef5SMatthew Dillon case IEEE80211_REASON_AUTH_EXPIRE:
1214f655ef5SMatthew Dillon return ("previous authentication is expired");
1224f655ef5SMatthew Dillon case IEEE80211_REASON_AUTH_LEAVE:
1234f655ef5SMatthew Dillon return ("sending STA is leaving/has left IBSS or ESS");
1244f655ef5SMatthew Dillon case IEEE80211_REASON_ASSOC_EXPIRE:
1254f655ef5SMatthew Dillon return ("disassociated due to inactivity");
1264f655ef5SMatthew Dillon case IEEE80211_REASON_ASSOC_TOOMANY:
1274f655ef5SMatthew Dillon return ("too many associated STAs");
1284f655ef5SMatthew Dillon case IEEE80211_REASON_NOT_AUTHED:
1294f655ef5SMatthew Dillon return ("class 2 frame received from nonauthenticated STA");
1304f655ef5SMatthew Dillon case IEEE80211_REASON_NOT_ASSOCED:
1314f655ef5SMatthew Dillon return ("class 3 frame received from nonassociated STA");
1324f655ef5SMatthew Dillon case IEEE80211_REASON_ASSOC_LEAVE:
1334f655ef5SMatthew Dillon return ("sending STA is leaving/has left BSS");
1344f655ef5SMatthew Dillon case IEEE80211_REASON_ASSOC_NOT_AUTHED:
1354f655ef5SMatthew Dillon return ("STA requesting (re)association is not authenticated");
1364f655ef5SMatthew Dillon case IEEE80211_REASON_DISASSOC_PWRCAP_BAD:
1374f655ef5SMatthew Dillon return ("information in the Power Capability element is "
1384f655ef5SMatthew Dillon "unacceptable");
1394f655ef5SMatthew Dillon case IEEE80211_REASON_DISASSOC_SUPCHAN_BAD:
1404f655ef5SMatthew Dillon return ("information in the Supported Channels element is "
1414f655ef5SMatthew Dillon "unacceptable");
1424f655ef5SMatthew Dillon case IEEE80211_REASON_IE_INVALID:
1434f655ef5SMatthew Dillon return ("invalid element");
1444f655ef5SMatthew Dillon case IEEE80211_REASON_MIC_FAILURE:
1454f655ef5SMatthew Dillon return ("MIC failure");
1464f655ef5SMatthew Dillon case IEEE80211_REASON_4WAY_HANDSHAKE_TIMEOUT:
1474f655ef5SMatthew Dillon return ("4-Way handshake timeout");
1484f655ef5SMatthew Dillon case IEEE80211_REASON_GROUP_KEY_UPDATE_TIMEOUT:
1494f655ef5SMatthew Dillon return ("group key update timeout");
1504f655ef5SMatthew Dillon case IEEE80211_REASON_IE_IN_4WAY_DIFFERS:
1514f655ef5SMatthew Dillon return ("element in 4-Way handshake different from "
1524f655ef5SMatthew Dillon "(re)association request/probe response/beacon frame");
1534f655ef5SMatthew Dillon case IEEE80211_REASON_GROUP_CIPHER_INVALID:
1544f655ef5SMatthew Dillon return ("invalid group cipher");
1554f655ef5SMatthew Dillon case IEEE80211_REASON_PAIRWISE_CIPHER_INVALID:
1564f655ef5SMatthew Dillon return ("invalid pairwise cipher");
1574f655ef5SMatthew Dillon case IEEE80211_REASON_AKMP_INVALID:
1584f655ef5SMatthew Dillon return ("invalid AKMP");
1594f655ef5SMatthew Dillon case IEEE80211_REASON_UNSUPP_RSN_IE_VERSION:
1604f655ef5SMatthew Dillon return ("unsupported version in RSN IE");
1614f655ef5SMatthew Dillon case IEEE80211_REASON_INVALID_RSN_IE_CAP:
1624f655ef5SMatthew Dillon return ("invalid capabilities in RSN IE");
1634f655ef5SMatthew Dillon case IEEE80211_REASON_802_1X_AUTH_FAILED:
1644f655ef5SMatthew Dillon return ("IEEE 802.1X authentication failed");
1654f655ef5SMatthew Dillon case IEEE80211_REASON_CIPHER_SUITE_REJECTED:
1664f655ef5SMatthew Dillon return ("cipher suite rejected because of the security "
1674f655ef5SMatthew Dillon "policy");
1684f655ef5SMatthew Dillon case IEEE80211_REASON_UNSPECIFIED_QOS:
1694f655ef5SMatthew Dillon return ("unspecified (QoS-related)");
1704f655ef5SMatthew Dillon case IEEE80211_REASON_INSUFFICIENT_BW:
1714f655ef5SMatthew Dillon return ("QoS AP lacks sufficient bandwidth for this QoS STA");
1724f655ef5SMatthew Dillon case IEEE80211_REASON_TOOMANY_FRAMES:
1734f655ef5SMatthew Dillon return ("too many frames need to be acknowledged");
1744f655ef5SMatthew Dillon case IEEE80211_REASON_OUTSIDE_TXOP:
1754f655ef5SMatthew Dillon return ("STA is transmitting outside the limits of its TXOPs");
1764f655ef5SMatthew Dillon case IEEE80211_REASON_LEAVING_QBSS:
1774f655ef5SMatthew Dillon return ("requested from peer STA (the STA is "
1784f655ef5SMatthew Dillon "resetting/leaving the BSS)");
1794f655ef5SMatthew Dillon case IEEE80211_REASON_BAD_MECHANISM:
1804f655ef5SMatthew Dillon return ("requested from peer STA (it does not want to use "
1814f655ef5SMatthew Dillon "the mechanism)");
1824f655ef5SMatthew Dillon case IEEE80211_REASON_SETUP_NEEDED:
1834f655ef5SMatthew Dillon return ("requested from peer STA (setup is required for the "
1844f655ef5SMatthew Dillon "used mechanism)");
1854f655ef5SMatthew Dillon case IEEE80211_REASON_TIMEOUT:
1864f655ef5SMatthew Dillon return ("requested from peer STA (timeout)");
1874f655ef5SMatthew Dillon case IEEE80211_REASON_PEER_LINK_CANCELED:
1884f655ef5SMatthew Dillon return ("SME cancels the mesh peering instance (not related "
1894f655ef5SMatthew Dillon "to the maximum number of peer mesh STAs)");
1904f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_MAX_PEERS:
1914f655ef5SMatthew Dillon return ("maximum number of peer mesh STAs was reached");
1924f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_CPVIOLATION:
1934f655ef5SMatthew Dillon return ("the received information violates the Mesh "
1944f655ef5SMatthew Dillon "Configuration policy configured in the mesh STA "
1954f655ef5SMatthew Dillon "profile");
1964f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_CLOSE_RCVD:
1974f655ef5SMatthew Dillon return ("the mesh STA has received a Mesh Peering Close "
1984f655ef5SMatthew Dillon "message requesting to close the mesh peering");
1994f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_MAX_RETRIES:
2004f655ef5SMatthew Dillon return ("the mesh STA has resent dot11MeshMaxRetries Mesh "
2014f655ef5SMatthew Dillon "Peering Open messages, without receiving a Mesh "
2024f655ef5SMatthew Dillon "Peering Confirm message");
2034f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_CONFIRM_TIMEOUT:
2044f655ef5SMatthew Dillon return ("the confirmTimer for the mesh peering instance times "
2054f655ef5SMatthew Dillon "out");
2064f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_INVALID_GTK:
2074f655ef5SMatthew Dillon return ("the mesh STA fails to unwrap the GTK or the values "
2084f655ef5SMatthew Dillon "in the wrapped contents do not match");
2094f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_INCONS_PARAMS:
2104f655ef5SMatthew Dillon return ("the mesh STA receives inconsistent information about "
2114f655ef5SMatthew Dillon "the mesh parameters between Mesh Peering Management "
2124f655ef5SMatthew Dillon "frames");
2134f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_INVALID_SECURITY:
2144f655ef5SMatthew Dillon return ("the mesh STA fails the authenticated mesh peering "
2154f655ef5SMatthew Dillon "exchange because due to failure in selecting "
2164f655ef5SMatthew Dillon "pairwise/group ciphersuite");
2174f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_PERR_NO_PROXY:
2184f655ef5SMatthew Dillon return ("the mesh STA does not have proxy information for "
2194f655ef5SMatthew Dillon "this external destination");
2204f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_PERR_NO_FI:
2214f655ef5SMatthew Dillon return ("the mesh STA does not have forwarding information "
2224f655ef5SMatthew Dillon "for this destination");
2234f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_PERR_DEST_UNREACH:
2244f655ef5SMatthew Dillon return ("the mesh STA determines that the link to the next "
2254f655ef5SMatthew Dillon "hop of an active path in its forwarding information "
2264f655ef5SMatthew Dillon "is no longer usable");
2274f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_MAC_ALRDY_EXISTS_MBSS:
2284f655ef5SMatthew Dillon return ("the MAC address of the STA already exists in the "
2294f655ef5SMatthew Dillon "mesh BSS");
2304f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_CHAN_SWITCH_REG:
2314f655ef5SMatthew Dillon return ("the mesh STA performs channel switch to meet "
2324f655ef5SMatthew Dillon "regulatory requirements");
2334f655ef5SMatthew Dillon case IEEE80211_REASON_MESH_CHAN_SWITCH_UNSPEC:
2344f655ef5SMatthew Dillon return ("the mesh STA performs channel switch with "
2354f655ef5SMatthew Dillon "unspecified reason");
2364f655ef5SMatthew Dillon default:
2374f655ef5SMatthew Dillon return ("reserved/unknown");
2384f655ef5SMatthew Dillon }
2394f655ef5SMatthew Dillon }
2404f655ef5SMatthew Dillon
241085ff963SMatthew Dillon static void beacon_miss(void *, int);
242085ff963SMatthew Dillon static void beacon_swmiss(void *, int);
243085ff963SMatthew Dillon static void parent_updown(void *, int);
244085ff963SMatthew Dillon static void update_mcast(void *, int);
245085ff963SMatthew Dillon static void update_promisc(void *, int);
246085ff963SMatthew Dillon static void update_channel(void *, int);
247085ff963SMatthew Dillon static void update_chw(void *, int);
2484f655ef5SMatthew Dillon static void update_wme(void *, int);
2494f655ef5SMatthew Dillon static void restart_vaps(void *, int);
250085ff963SMatthew Dillon static void ieee80211_newstate_cb(void *, int);
25132176cfdSRui Paulo
25232176cfdSRui Paulo static int
null_raw_xmit(struct ieee80211_node * ni,struct mbuf * m,const struct ieee80211_bpf_params * params)25332176cfdSRui Paulo null_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
25432176cfdSRui Paulo const struct ieee80211_bpf_params *params)
25532176cfdSRui Paulo {
25632176cfdSRui Paulo
2574f898719SImre Vadász ic_printf(ni->ni_ic, "missing ic_raw_xmit callback, drop frame\n");
25832176cfdSRui Paulo m_freem(m);
25932176cfdSRui Paulo return ENETDOWN;
26032176cfdSRui Paulo }
261f186073cSJoerg Sonnenberger
262f186073cSJoerg Sonnenberger void
ieee80211_proto_attach(struct ieee80211com * ic)263841ab66cSSepherosa Ziehau ieee80211_proto_attach(struct ieee80211com *ic)
264f186073cSJoerg Sonnenberger {
2654f655ef5SMatthew Dillon uint8_t hdrlen;
266f186073cSJoerg Sonnenberger
26732176cfdSRui Paulo /* override the 802.3 setting */
2684f655ef5SMatthew Dillon hdrlen = ic->ic_headroom
26932176cfdSRui Paulo + sizeof(struct ieee80211_qosframe_addr4)
27032176cfdSRui Paulo + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN
27132176cfdSRui Paulo + IEEE80211_WEP_EXTIVLEN;
27232176cfdSRui Paulo /* XXX no way to recalculate on ifdetach */
2734f655ef5SMatthew Dillon if (ALIGN(hdrlen) > max_linkhdr) {
27432176cfdSRui Paulo /* XXX sanity check... */
2754f655ef5SMatthew Dillon max_linkhdr = ALIGN(hdrlen);
27632176cfdSRui Paulo max_hdr = max_linkhdr + max_protohdr;
27732176cfdSRui Paulo max_datalen = MHLEN - max_hdr;
27832176cfdSRui Paulo }
279f186073cSJoerg Sonnenberger ic->ic_protmode = IEEE80211_PROT_CTSONLY;
28032176cfdSRui Paulo
2814f655ef5SMatthew Dillon TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ic);
282085ff963SMatthew Dillon TASK_INIT(&ic->ic_mcast_task, 0, update_mcast, ic);
283085ff963SMatthew Dillon TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic);
284085ff963SMatthew Dillon TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic);
285085ff963SMatthew Dillon TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic);
286085ff963SMatthew Dillon TASK_INIT(&ic->ic_chw_task, 0, update_chw, ic);
2874f655ef5SMatthew Dillon TASK_INIT(&ic->ic_wme_task, 0, update_wme, ic);
2884f655ef5SMatthew Dillon TASK_INIT(&ic->ic_restart_task, 0, restart_vaps, ic);
289841ab66cSSepherosa Ziehau
290841ab66cSSepherosa Ziehau ic->ic_wme.wme_hipri_switch_hysteresis =
291841ab66cSSepherosa Ziehau AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
292f186073cSJoerg Sonnenberger
293f186073cSJoerg Sonnenberger /* initialize management frame handlers */
294f186073cSJoerg Sonnenberger ic->ic_send_mgmt = ieee80211_send_mgmt;
29532176cfdSRui Paulo ic->ic_raw_xmit = null_raw_xmit;
29632176cfdSRui Paulo
29732176cfdSRui Paulo ieee80211_adhoc_attach(ic);
29832176cfdSRui Paulo ieee80211_sta_attach(ic);
29932176cfdSRui Paulo ieee80211_wds_attach(ic);
30032176cfdSRui Paulo ieee80211_hostap_attach(ic);
30132176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH
30232176cfdSRui Paulo ieee80211_mesh_attach(ic);
30332176cfdSRui Paulo #endif
30432176cfdSRui Paulo ieee80211_monitor_attach(ic);
305f186073cSJoerg Sonnenberger }
306f186073cSJoerg Sonnenberger
307f186073cSJoerg Sonnenberger void
ieee80211_proto_detach(struct ieee80211com * ic)308841ab66cSSepherosa Ziehau ieee80211_proto_detach(struct ieee80211com *ic)
309f186073cSJoerg Sonnenberger {
31032176cfdSRui Paulo ieee80211_monitor_detach(ic);
31132176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH
31232176cfdSRui Paulo ieee80211_mesh_detach(ic);
31332176cfdSRui Paulo #endif
31432176cfdSRui Paulo ieee80211_hostap_detach(ic);
31532176cfdSRui Paulo ieee80211_wds_detach(ic);
31632176cfdSRui Paulo ieee80211_adhoc_detach(ic);
31732176cfdSRui Paulo ieee80211_sta_detach(ic);
31832176cfdSRui Paulo }
319841ab66cSSepherosa Ziehau
32032176cfdSRui Paulo static void
null_update_beacon(struct ieee80211vap * vap,int item)32132176cfdSRui Paulo null_update_beacon(struct ieee80211vap *vap, int item)
32232176cfdSRui Paulo {
32332176cfdSRui Paulo }
32432176cfdSRui Paulo
32532176cfdSRui Paulo void
ieee80211_proto_vattach(struct ieee80211vap * vap)32632176cfdSRui Paulo ieee80211_proto_vattach(struct ieee80211vap *vap)
32732176cfdSRui Paulo {
32832176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
32932176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
33032176cfdSRui Paulo int i;
33132176cfdSRui Paulo
33232176cfdSRui Paulo /* override the 802.3 setting */
3334f655ef5SMatthew Dillon ifp->if_hdrlen = ic->ic_headroom
3344f655ef5SMatthew Dillon + sizeof(struct ieee80211_qosframe_addr4)
3354f655ef5SMatthew Dillon + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN
3364f655ef5SMatthew Dillon + IEEE80211_WEP_EXTIVLEN;
33732176cfdSRui Paulo
33832176cfdSRui Paulo vap->iv_rtsthreshold = IEEE80211_RTS_DEFAULT;
33932176cfdSRui Paulo vap->iv_fragthreshold = IEEE80211_FRAG_DEFAULT;
34032176cfdSRui Paulo vap->iv_bmiss_max = IEEE80211_BMISS_MAX;
341085ff963SMatthew Dillon callout_init_mtx(&vap->iv_swbmiss, IEEE80211_LOCK_OBJ(ic), 0);
3424f655ef5SMatthew Dillon #if defined(__DragonFly__)
34334a60cf6SRui Paulo callout_init_mp(&vap->iv_mgtsend);
3444f655ef5SMatthew Dillon #else
3454f655ef5SMatthew Dillon callout_init(&vap->iv_mgtsend, 1);
3464f655ef5SMatthew Dillon #endif
347085ff963SMatthew Dillon TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_cb, vap);
348085ff963SMatthew Dillon TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss, vap);
34932176cfdSRui Paulo /*
35032176cfdSRui Paulo * Install default tx rate handling: no fixed rate, lowest
35132176cfdSRui Paulo * supported rate for mgmt and multicast frames. Default
35232176cfdSRui Paulo * max retry count. These settings can be changed by the
35332176cfdSRui Paulo * driver and/or user applications.
35432176cfdSRui Paulo */
35532176cfdSRui Paulo for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) {
35632176cfdSRui Paulo const struct ieee80211_rateset *rs = &ic->ic_sup_rates[i];
35732176cfdSRui Paulo
35832176cfdSRui Paulo vap->iv_txparms[i].ucastrate = IEEE80211_FIXED_RATE_NONE;
359085ff963SMatthew Dillon
360085ff963SMatthew Dillon /*
361085ff963SMatthew Dillon * Setting the management rate to MCS 0 assumes that the
362085ff963SMatthew Dillon * BSS Basic rate set is empty and the BSS Basic MCS set
363085ff963SMatthew Dillon * is not.
364085ff963SMatthew Dillon *
365085ff963SMatthew Dillon * Since we're not checking this, default to the lowest
366085ff963SMatthew Dillon * defined rate for this mode.
367085ff963SMatthew Dillon *
368085ff963SMatthew Dillon * At least one 11n AP (DLINK DIR-825) is reported to drop
369085ff963SMatthew Dillon * some MCS management traffic (eg BA response frames.)
370085ff963SMatthew Dillon *
371085ff963SMatthew Dillon * See also: 9.6.0 of the 802.11n-2009 specification.
372085ff963SMatthew Dillon */
373085ff963SMatthew Dillon #ifdef NOTYET
37432176cfdSRui Paulo if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) {
37532176cfdSRui Paulo vap->iv_txparms[i].mgmtrate = 0 | IEEE80211_RATE_MCS;
37632176cfdSRui Paulo vap->iv_txparms[i].mcastrate = 0 | IEEE80211_RATE_MCS;
37732176cfdSRui Paulo } else {
37832176cfdSRui Paulo vap->iv_txparms[i].mgmtrate =
37932176cfdSRui Paulo rs->rs_rates[0] & IEEE80211_RATE_VAL;
38032176cfdSRui Paulo vap->iv_txparms[i].mcastrate =
38132176cfdSRui Paulo rs->rs_rates[0] & IEEE80211_RATE_VAL;
38232176cfdSRui Paulo }
383085ff963SMatthew Dillon #endif
384085ff963SMatthew Dillon vap->iv_txparms[i].mgmtrate = rs->rs_rates[0] & IEEE80211_RATE_VAL;
385085ff963SMatthew Dillon vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL;
38632176cfdSRui Paulo vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT;
38732176cfdSRui Paulo }
38832176cfdSRui Paulo vap->iv_roaming = IEEE80211_ROAMING_AUTO;
38932176cfdSRui Paulo
39032176cfdSRui Paulo vap->iv_update_beacon = null_update_beacon;
39132176cfdSRui Paulo vap->iv_deliver_data = ieee80211_deliver_data;
39232176cfdSRui Paulo
39332176cfdSRui Paulo /* attach support for operating mode */
39432176cfdSRui Paulo ic->ic_vattach[vap->iv_opmode](vap);
39532176cfdSRui Paulo }
39632176cfdSRui Paulo
39732176cfdSRui Paulo void
ieee80211_proto_vdetach(struct ieee80211vap * vap)39832176cfdSRui Paulo ieee80211_proto_vdetach(struct ieee80211vap *vap)
39932176cfdSRui Paulo {
40032176cfdSRui Paulo #define FREEAPPIE(ie) do { \
40132176cfdSRui Paulo if (ie != NULL) \
4024f655ef5SMatthew Dillon IEEE80211_FREE(ie, M_80211_NODE_IE); \
40332176cfdSRui Paulo } while (0)
40432176cfdSRui Paulo /*
40532176cfdSRui Paulo * Detach operating mode module.
40632176cfdSRui Paulo */
40732176cfdSRui Paulo if (vap->iv_opdetach != NULL)
40832176cfdSRui Paulo vap->iv_opdetach(vap);
409841ab66cSSepherosa Ziehau /*
410841ab66cSSepherosa Ziehau * This should not be needed as we detach when reseting
411841ab66cSSepherosa Ziehau * the state but be conservative here since the
412841ab66cSSepherosa Ziehau * authenticator may do things like spawn kernel threads.
413841ab66cSSepherosa Ziehau */
41432176cfdSRui Paulo if (vap->iv_auth->ia_detach != NULL)
41532176cfdSRui Paulo vap->iv_auth->ia_detach(vap);
416841ab66cSSepherosa Ziehau /*
417841ab66cSSepherosa Ziehau * Detach any ACL'ator.
418841ab66cSSepherosa Ziehau */
41932176cfdSRui Paulo if (vap->iv_acl != NULL)
42032176cfdSRui Paulo vap->iv_acl->iac_detach(vap);
42132176cfdSRui Paulo
42232176cfdSRui Paulo FREEAPPIE(vap->iv_appie_beacon);
42332176cfdSRui Paulo FREEAPPIE(vap->iv_appie_probereq);
42432176cfdSRui Paulo FREEAPPIE(vap->iv_appie_proberesp);
42532176cfdSRui Paulo FREEAPPIE(vap->iv_appie_assocreq);
42632176cfdSRui Paulo FREEAPPIE(vap->iv_appie_assocresp);
42732176cfdSRui Paulo FREEAPPIE(vap->iv_appie_wpa);
42832176cfdSRui Paulo #undef FREEAPPIE
429841ab66cSSepherosa Ziehau }
430841ab66cSSepherosa Ziehau
431841ab66cSSepherosa Ziehau /*
432841ab66cSSepherosa Ziehau * Simple-minded authenticator module support.
433841ab66cSSepherosa Ziehau */
434841ab66cSSepherosa Ziehau
435841ab66cSSepherosa Ziehau #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1)
436841ab66cSSepherosa Ziehau /* XXX well-known names */
437841ab66cSSepherosa Ziehau static const char *auth_modnames[IEEE80211_AUTH_MAX] = {
438841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_NONE */
439841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_OPEN */
440841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_SHARED */
441841ab66cSSepherosa Ziehau "wlan_xauth", /* IEEE80211_AUTH_8021X */
442841ab66cSSepherosa Ziehau "wlan_internal", /* IEEE80211_AUTH_AUTO */
443841ab66cSSepherosa Ziehau "wlan_xauth", /* IEEE80211_AUTH_WPA */
444841ab66cSSepherosa Ziehau };
445841ab66cSSepherosa Ziehau static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX];
446841ab66cSSepherosa Ziehau
447841ab66cSSepherosa Ziehau static const struct ieee80211_authenticator auth_internal = {
448841ab66cSSepherosa Ziehau .ia_name = "wlan_internal",
449841ab66cSSepherosa Ziehau .ia_attach = NULL,
450841ab66cSSepherosa Ziehau .ia_detach = NULL,
451841ab66cSSepherosa Ziehau .ia_node_join = NULL,
452841ab66cSSepherosa Ziehau .ia_node_leave = NULL,
453841ab66cSSepherosa Ziehau };
454841ab66cSSepherosa Ziehau
455841ab66cSSepherosa Ziehau /*
456841ab66cSSepherosa Ziehau * Setup internal authenticators once; they are never unregistered.
457841ab66cSSepherosa Ziehau */
458841ab66cSSepherosa Ziehau static void
ieee80211_auth_setup(void)459841ab66cSSepherosa Ziehau ieee80211_auth_setup(void)
460841ab66cSSepherosa Ziehau {
461841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal);
462841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal);
463841ab66cSSepherosa Ziehau ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal);
464841ab66cSSepherosa Ziehau }
465841ab66cSSepherosa Ziehau SYSINIT(wlan_auth, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_auth_setup, NULL);
466841ab66cSSepherosa Ziehau
467841ab66cSSepherosa Ziehau const struct ieee80211_authenticator *
ieee80211_authenticator_get(int auth)468841ab66cSSepherosa Ziehau ieee80211_authenticator_get(int auth)
469841ab66cSSepherosa Ziehau {
470841ab66cSSepherosa Ziehau if (auth >= IEEE80211_AUTH_MAX)
471841ab66cSSepherosa Ziehau return NULL;
472841ab66cSSepherosa Ziehau if (authenticators[auth] == NULL)
473841ab66cSSepherosa Ziehau ieee80211_load_module(auth_modnames[auth]);
474841ab66cSSepherosa Ziehau return authenticators[auth];
475f186073cSJoerg Sonnenberger }
476f186073cSJoerg Sonnenberger
477f186073cSJoerg Sonnenberger void
ieee80211_authenticator_register(int type,const struct ieee80211_authenticator * auth)478841ab66cSSepherosa Ziehau ieee80211_authenticator_register(int type,
479841ab66cSSepherosa Ziehau const struct ieee80211_authenticator *auth)
480f186073cSJoerg Sonnenberger {
481841ab66cSSepherosa Ziehau if (type >= IEEE80211_AUTH_MAX)
482841ab66cSSepherosa Ziehau return;
483841ab66cSSepherosa Ziehau authenticators[type] = auth;
484841ab66cSSepherosa Ziehau }
485841ab66cSSepherosa Ziehau
486841ab66cSSepherosa Ziehau void
ieee80211_authenticator_unregister(int type)487841ab66cSSepherosa Ziehau ieee80211_authenticator_unregister(int type)
488841ab66cSSepherosa Ziehau {
489841ab66cSSepherosa Ziehau
490841ab66cSSepherosa Ziehau if (type >= IEEE80211_AUTH_MAX)
491841ab66cSSepherosa Ziehau return;
492841ab66cSSepherosa Ziehau authenticators[type] = NULL;
493841ab66cSSepherosa Ziehau }
494841ab66cSSepherosa Ziehau
495841ab66cSSepherosa Ziehau /*
496841ab66cSSepherosa Ziehau * Very simple-minded ACL module support.
497841ab66cSSepherosa Ziehau */
498841ab66cSSepherosa Ziehau /* XXX just one for now */
499841ab66cSSepherosa Ziehau static const struct ieee80211_aclator *acl = NULL;
500841ab66cSSepherosa Ziehau
501841ab66cSSepherosa Ziehau void
ieee80211_aclator_register(const struct ieee80211_aclator * iac)502841ab66cSSepherosa Ziehau ieee80211_aclator_register(const struct ieee80211_aclator *iac)
503841ab66cSSepherosa Ziehau {
504a6ec04bcSSascha Wildner kprintf("wlan: %s acl policy registered\n", iac->iac_name);
505841ab66cSSepherosa Ziehau acl = iac;
506841ab66cSSepherosa Ziehau }
507841ab66cSSepherosa Ziehau
508841ab66cSSepherosa Ziehau void
ieee80211_aclator_unregister(const struct ieee80211_aclator * iac)509841ab66cSSepherosa Ziehau ieee80211_aclator_unregister(const struct ieee80211_aclator *iac)
510841ab66cSSepherosa Ziehau {
511841ab66cSSepherosa Ziehau if (acl == iac)
512841ab66cSSepherosa Ziehau acl = NULL;
513a6ec04bcSSascha Wildner kprintf("wlan: %s acl policy unregistered\n", iac->iac_name);
514841ab66cSSepherosa Ziehau }
515841ab66cSSepherosa Ziehau
516841ab66cSSepherosa Ziehau const struct ieee80211_aclator *
ieee80211_aclator_get(const char * name)517841ab66cSSepherosa Ziehau ieee80211_aclator_get(const char *name)
518841ab66cSSepherosa Ziehau {
519841ab66cSSepherosa Ziehau if (acl == NULL)
520841ab66cSSepherosa Ziehau ieee80211_load_module("wlan_acl");
521841ab66cSSepherosa Ziehau return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL;
522841ab66cSSepherosa Ziehau }
523841ab66cSSepherosa Ziehau
524841ab66cSSepherosa Ziehau void
ieee80211_print_essid(const uint8_t * essid,int len)525841ab66cSSepherosa Ziehau ieee80211_print_essid(const uint8_t *essid, int len)
526841ab66cSSepherosa Ziehau {
527841ab66cSSepherosa Ziehau const uint8_t *p;
528f186073cSJoerg Sonnenberger int i;
529f186073cSJoerg Sonnenberger
530f186073cSJoerg Sonnenberger if (len > IEEE80211_NWID_LEN)
531f186073cSJoerg Sonnenberger len = IEEE80211_NWID_LEN;
532f186073cSJoerg Sonnenberger /* determine printable or not */
533f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) {
534f186073cSJoerg Sonnenberger if (*p < ' ' || *p > 0x7e)
535f186073cSJoerg Sonnenberger break;
536f186073cSJoerg Sonnenberger }
537f186073cSJoerg Sonnenberger if (i == len) {
538a6ec04bcSSascha Wildner kprintf("\"");
539f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++)
540a6ec04bcSSascha Wildner kprintf("%c", *p);
541a6ec04bcSSascha Wildner kprintf("\"");
542f186073cSJoerg Sonnenberger } else {
543a6ec04bcSSascha Wildner kprintf("0x");
544f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++)
545a6ec04bcSSascha Wildner kprintf("%02x", *p);
546f186073cSJoerg Sonnenberger }
547f186073cSJoerg Sonnenberger }
548f186073cSJoerg Sonnenberger
549f186073cSJoerg Sonnenberger void
ieee80211_dump_pkt(struct ieee80211com * ic,const uint8_t * buf,int len,int rate,int rssi)55032176cfdSRui Paulo ieee80211_dump_pkt(struct ieee80211com *ic,
55132176cfdSRui Paulo const uint8_t *buf, int len, int rate, int rssi)
552f186073cSJoerg Sonnenberger {
553841ab66cSSepherosa Ziehau const struct ieee80211_frame *wh;
554f186073cSJoerg Sonnenberger int i;
555f186073cSJoerg Sonnenberger
556841ab66cSSepherosa Ziehau wh = (const struct ieee80211_frame *)buf;
557f186073cSJoerg Sonnenberger switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
558f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_NODS:
559085ff963SMatthew Dillon kprintf("NODS %s", ether_sprintf(wh->i_addr2));
560085ff963SMatthew Dillon kprintf("->%s", ether_sprintf(wh->i_addr1));
561085ff963SMatthew Dillon kprintf("(%s)", ether_sprintf(wh->i_addr3));
562f186073cSJoerg Sonnenberger break;
563f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_TODS:
564085ff963SMatthew Dillon kprintf("TODS %s", ether_sprintf(wh->i_addr2));
565085ff963SMatthew Dillon kprintf("->%s", ether_sprintf(wh->i_addr3));
566085ff963SMatthew Dillon kprintf("(%s)", ether_sprintf(wh->i_addr1));
567f186073cSJoerg Sonnenberger break;
568f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_FROMDS:
569085ff963SMatthew Dillon kprintf("FRDS %s", ether_sprintf(wh->i_addr3));
570085ff963SMatthew Dillon kprintf("->%s", ether_sprintf(wh->i_addr1));
571085ff963SMatthew Dillon kprintf("(%s)", ether_sprintf(wh->i_addr2));
572f186073cSJoerg Sonnenberger break;
573f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_DSTODS:
574085ff963SMatthew Dillon kprintf("DSDS %s", ether_sprintf((const uint8_t *)&wh[1]));
575085ff963SMatthew Dillon kprintf("->%s", ether_sprintf(wh->i_addr3));
576085ff963SMatthew Dillon kprintf("(%s", ether_sprintf(wh->i_addr2));
577085ff963SMatthew Dillon kprintf("->%s)", ether_sprintf(wh->i_addr1));
578f186073cSJoerg Sonnenberger break;
579f186073cSJoerg Sonnenberger }
580f186073cSJoerg Sonnenberger switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
581f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_DATA:
582a6ec04bcSSascha Wildner kprintf(" data");
583f186073cSJoerg Sonnenberger break;
584f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_MGT:
5854f655ef5SMatthew Dillon kprintf(" %s", ieee80211_mgt_subtype_name(wh->i_fc[0]));
586f186073cSJoerg Sonnenberger break;
587f186073cSJoerg Sonnenberger default:
588a6ec04bcSSascha Wildner kprintf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
589f186073cSJoerg Sonnenberger break;
590f186073cSJoerg Sonnenberger }
59132176cfdSRui Paulo if (IEEE80211_QOS_HAS_SEQ(wh)) {
59232176cfdSRui Paulo const struct ieee80211_qosframe *qwh =
59332176cfdSRui Paulo (const struct ieee80211_qosframe *)buf;
59432176cfdSRui Paulo kprintf(" QoS [TID %u%s]", qwh->i_qos[0] & IEEE80211_QOS_TID,
59532176cfdSRui Paulo qwh->i_qos[0] & IEEE80211_QOS_ACKPOLICY ? " ACM" : "");
59632176cfdSRui Paulo }
597085ff963SMatthew Dillon if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
59832176cfdSRui Paulo int off;
59932176cfdSRui Paulo
60032176cfdSRui Paulo off = ieee80211_anyhdrspace(ic, wh);
60132176cfdSRui Paulo kprintf(" WEP [IV %.02x %.02x %.02x",
60232176cfdSRui Paulo buf[off+0], buf[off+1], buf[off+2]);
60332176cfdSRui Paulo if (buf[off+IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)
60432176cfdSRui Paulo kprintf(" %.02x %.02x %.02x",
60532176cfdSRui Paulo buf[off+4], buf[off+5], buf[off+6]);
60632176cfdSRui Paulo kprintf(" KID %u]", buf[off+IEEE80211_WEP_IVLEN] >> 6);
607841ab66cSSepherosa Ziehau }
608f186073cSJoerg Sonnenberger if (rate >= 0)
609a6ec04bcSSascha Wildner kprintf(" %dM", rate / 2);
610f186073cSJoerg Sonnenberger if (rssi >= 0)
611a6ec04bcSSascha Wildner kprintf(" +%d", rssi);
612a6ec04bcSSascha Wildner kprintf("\n");
613f186073cSJoerg Sonnenberger if (len > 0) {
614f186073cSJoerg Sonnenberger for (i = 0; i < len; i++) {
615f186073cSJoerg Sonnenberger if ((i & 1) == 0)
616a6ec04bcSSascha Wildner kprintf(" ");
617a6ec04bcSSascha Wildner kprintf("%02x", buf[i]);
618f186073cSJoerg Sonnenberger }
619a6ec04bcSSascha Wildner kprintf("\n");
620f186073cSJoerg Sonnenberger }
621f186073cSJoerg Sonnenberger }
622f186073cSJoerg Sonnenberger
62332176cfdSRui Paulo static __inline int
findrix(const struct ieee80211_rateset * rs,int r)62432176cfdSRui Paulo findrix(const struct ieee80211_rateset *rs, int r)
62532176cfdSRui Paulo {
62632176cfdSRui Paulo int i;
62732176cfdSRui Paulo
62832176cfdSRui Paulo for (i = 0; i < rs->rs_nrates; i++)
62932176cfdSRui Paulo if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == r)
63032176cfdSRui Paulo return i;
63132176cfdSRui Paulo return -1;
63232176cfdSRui Paulo }
63332176cfdSRui Paulo
634f186073cSJoerg Sonnenberger int
ieee80211_fix_rate(struct ieee80211_node * ni,struct ieee80211_rateset * nrs,int flags)63532176cfdSRui Paulo ieee80211_fix_rate(struct ieee80211_node *ni,
63632176cfdSRui Paulo struct ieee80211_rateset *nrs, int flags)
637f186073cSJoerg Sonnenberger {
63832176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap;
639841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic;
64032176cfdSRui Paulo int i, j, rix, error;
64132176cfdSRui Paulo int okrate, badrate, fixedrate, ucastrate;
642208a1285SSepherosa Ziehau const struct ieee80211_rateset *srs;
643f186073cSJoerg Sonnenberger uint8_t r;
644f186073cSJoerg Sonnenberger
645f186073cSJoerg Sonnenberger error = 0;
64632176cfdSRui Paulo okrate = badrate = 0;
64732176cfdSRui Paulo ucastrate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].ucastrate;
64832176cfdSRui Paulo if (ucastrate != IEEE80211_FIXED_RATE_NONE) {
64932176cfdSRui Paulo /*
65032176cfdSRui Paulo * Workaround awkwardness with fixed rate. We are called
65132176cfdSRui Paulo * to check both the legacy rate set and the HT rate set
65232176cfdSRui Paulo * but we must apply any legacy fixed rate check only to the
65332176cfdSRui Paulo * legacy rate set and vice versa. We cannot tell what type
65432176cfdSRui Paulo * of rate set we've been given (legacy or HT) but we can
65532176cfdSRui Paulo * distinguish the fixed rate type (MCS have 0x80 set).
65632176cfdSRui Paulo * So to deal with this the caller communicates whether to
65732176cfdSRui Paulo * check MCS or legacy rate using the flags and we use the
65832176cfdSRui Paulo * type of any fixed rate to avoid applying an MCS to a
65932176cfdSRui Paulo * legacy rate and vice versa.
66032176cfdSRui Paulo */
66132176cfdSRui Paulo if (ucastrate & 0x80) {
66232176cfdSRui Paulo if (flags & IEEE80211_F_DOFRATE)
66332176cfdSRui Paulo flags &= ~IEEE80211_F_DOFRATE;
66432176cfdSRui Paulo } else if ((ucastrate & 0x80) == 0) {
66532176cfdSRui Paulo if (flags & IEEE80211_F_DOFMCS)
66632176cfdSRui Paulo flags &= ~IEEE80211_F_DOFMCS;
66732176cfdSRui Paulo }
66832176cfdSRui Paulo /* NB: required to make MCS match below work */
66932176cfdSRui Paulo ucastrate &= IEEE80211_RATE_VAL;
67032176cfdSRui Paulo }
67132176cfdSRui Paulo fixedrate = IEEE80211_FIXED_RATE_NONE;
67232176cfdSRui Paulo /*
67332176cfdSRui Paulo * XXX we are called to process both MCS and legacy rates;
67432176cfdSRui Paulo * we must use the appropriate basic rate set or chaos will
67532176cfdSRui Paulo * ensue; for now callers that want MCS must supply
67632176cfdSRui Paulo * IEEE80211_F_DOBRS; at some point we'll need to split this
67732176cfdSRui Paulo * function so there are two variants, one for MCS and one
67832176cfdSRui Paulo * for legacy rates.
67932176cfdSRui Paulo */
68032176cfdSRui Paulo if (flags & IEEE80211_F_DOBRS)
68132176cfdSRui Paulo srs = (const struct ieee80211_rateset *)
68232176cfdSRui Paulo ieee80211_get_suphtrates(ic, ni->ni_chan);
68332176cfdSRui Paulo else
68432176cfdSRui Paulo srs = ieee80211_get_suprates(ic, ni->ni_chan);
685f186073cSJoerg Sonnenberger for (i = 0; i < nrs->rs_nrates; ) {
686f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOSORT) {
687f186073cSJoerg Sonnenberger /*
688f186073cSJoerg Sonnenberger * Sort rates.
689f186073cSJoerg Sonnenberger */
690f186073cSJoerg Sonnenberger for (j = i + 1; j < nrs->rs_nrates; j++) {
6914f655ef5SMatthew Dillon if (IEEE80211_RV(nrs->rs_rates[i]) >
6924f655ef5SMatthew Dillon IEEE80211_RV(nrs->rs_rates[j])) {
693f186073cSJoerg Sonnenberger r = nrs->rs_rates[i];
694f186073cSJoerg Sonnenberger nrs->rs_rates[i] = nrs->rs_rates[j];
695f186073cSJoerg Sonnenberger nrs->rs_rates[j] = r;
696f186073cSJoerg Sonnenberger }
697f186073cSJoerg Sonnenberger }
698f186073cSJoerg Sonnenberger }
699f186073cSJoerg Sonnenberger r = nrs->rs_rates[i] & IEEE80211_RATE_VAL;
700f186073cSJoerg Sonnenberger badrate = r;
701f186073cSJoerg Sonnenberger /*
70232176cfdSRui Paulo * Check for fixed rate.
703f186073cSJoerg Sonnenberger */
70432176cfdSRui Paulo if (r == ucastrate)
705841ab66cSSepherosa Ziehau fixedrate = r;
706f186073cSJoerg Sonnenberger /*
707f186073cSJoerg Sonnenberger * Check against supported rates.
708f186073cSJoerg Sonnenberger */
70932176cfdSRui Paulo rix = findrix(srs, r);
71032176cfdSRui Paulo if (flags & IEEE80211_F_DONEGO) {
71132176cfdSRui Paulo if (rix < 0) {
71232176cfdSRui Paulo /*
71332176cfdSRui Paulo * A rate in the node's rate set is not
71432176cfdSRui Paulo * supported. If this is a basic rate and we
71532176cfdSRui Paulo * are operating as a STA then this is an error.
71632176cfdSRui Paulo * Otherwise we just discard/ignore the rate.
71732176cfdSRui Paulo */
71832176cfdSRui Paulo if ((flags & IEEE80211_F_JOIN) &&
71932176cfdSRui Paulo (nrs->rs_rates[i] & IEEE80211_RATE_BASIC))
72032176cfdSRui Paulo error++;
72132176cfdSRui Paulo } else if ((flags & IEEE80211_F_JOIN) == 0) {
722f186073cSJoerg Sonnenberger /*
723f186073cSJoerg Sonnenberger * Overwrite with the supported rate
724f186073cSJoerg Sonnenberger * value so any basic rate bit is set.
725f186073cSJoerg Sonnenberger */
72632176cfdSRui Paulo nrs->rs_rates[i] = srs->rs_rates[rix];
727f186073cSJoerg Sonnenberger }
728f186073cSJoerg Sonnenberger }
72932176cfdSRui Paulo if ((flags & IEEE80211_F_DODEL) && rix < 0) {
730f186073cSJoerg Sonnenberger /*
731f186073cSJoerg Sonnenberger * Delete unacceptable rates.
732f186073cSJoerg Sonnenberger */
733f186073cSJoerg Sonnenberger nrs->rs_nrates--;
734f186073cSJoerg Sonnenberger for (j = i; j < nrs->rs_nrates; j++)
735f186073cSJoerg Sonnenberger nrs->rs_rates[j] = nrs->rs_rates[j + 1];
736f186073cSJoerg Sonnenberger nrs->rs_rates[j] = 0;
737f186073cSJoerg Sonnenberger continue;
738f186073cSJoerg Sonnenberger }
73932176cfdSRui Paulo if (rix >= 0)
740f186073cSJoerg Sonnenberger okrate = nrs->rs_rates[i];
741f186073cSJoerg Sonnenberger i++;
742f186073cSJoerg Sonnenberger }
743841ab66cSSepherosa Ziehau if (okrate == 0 || error != 0 ||
74432176cfdSRui Paulo ((flags & (IEEE80211_F_DOFRATE|IEEE80211_F_DOFMCS)) &&
74532176cfdSRui Paulo fixedrate != ucastrate)) {
74632176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
74732176cfdSRui Paulo "%s: flags 0x%x okrate %d error %d fixedrate 0x%x "
7482c7ccc4aSSascha Wildner "ucastrate %x\n", __func__, flags, okrate, error,
7492c7ccc4aSSascha Wildner fixedrate, ucastrate);
750f186073cSJoerg Sonnenberger return badrate | IEEE80211_RATE_BASIC;
75132176cfdSRui Paulo } else
7524f655ef5SMatthew Dillon return IEEE80211_RV(okrate);
753f186073cSJoerg Sonnenberger }
754f186073cSJoerg Sonnenberger
755841ab66cSSepherosa Ziehau /*
756841ab66cSSepherosa Ziehau * Reset 11g-related state.
757841ab66cSSepherosa Ziehau */
758841ab66cSSepherosa Ziehau void
ieee80211_reset_erp(struct ieee80211com * ic)759841ab66cSSepherosa Ziehau ieee80211_reset_erp(struct ieee80211com *ic)
760f186073cSJoerg Sonnenberger {
761841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_USEPROT;
762841ab66cSSepherosa Ziehau ic->ic_nonerpsta = 0;
763841ab66cSSepherosa Ziehau ic->ic_longslotsta = 0;
764841ab66cSSepherosa Ziehau /*
765841ab66cSSepherosa Ziehau * Short slot time is enabled only when operating in 11g
766841ab66cSSepherosa Ziehau * and not in an IBSS. We must also honor whether or not
767841ab66cSSepherosa Ziehau * the driver is capable of doing it.
768841ab66cSSepherosa Ziehau */
769841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(ic,
77032176cfdSRui Paulo IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
77132176cfdSRui Paulo IEEE80211_IS_CHAN_HT(ic->ic_curchan) ||
77232176cfdSRui Paulo (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
773841ab66cSSepherosa Ziehau ic->ic_opmode == IEEE80211_M_HOSTAP &&
774841ab66cSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHSLOT)));
775841ab66cSSepherosa Ziehau /*
776841ab66cSSepherosa Ziehau * Set short preamble and ERP barker-preamble flags.
777841ab66cSSepherosa Ziehau */
77832176cfdSRui Paulo if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
77932176cfdSRui Paulo (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) {
78032176cfdSRui Paulo ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
78132176cfdSRui Paulo ic->ic_flags &= ~IEEE80211_F_USEBARKER;
78232176cfdSRui Paulo } else {
78332176cfdSRui Paulo ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
78432176cfdSRui Paulo ic->ic_flags |= IEEE80211_F_USEBARKER;
78532176cfdSRui Paulo }
786841ab66cSSepherosa Ziehau }
787841ab66cSSepherosa Ziehau
788841ab66cSSepherosa Ziehau /*
789841ab66cSSepherosa Ziehau * Set the short slot time state and notify the driver.
790841ab66cSSepherosa Ziehau */
791841ab66cSSepherosa Ziehau void
ieee80211_set_shortslottime(struct ieee80211com * ic,int onoff)792841ab66cSSepherosa Ziehau ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff)
793841ab66cSSepherosa Ziehau {
794841ab66cSSepherosa Ziehau if (onoff)
795841ab66cSSepherosa Ziehau ic->ic_flags |= IEEE80211_F_SHSLOT;
796841ab66cSSepherosa Ziehau else
797841ab66cSSepherosa Ziehau ic->ic_flags &= ~IEEE80211_F_SHSLOT;
79832176cfdSRui Paulo /* notify driver */
799841ab66cSSepherosa Ziehau if (ic->ic_updateslot != NULL)
8004f898719SImre Vadász ic->ic_updateslot(ic);
801841ab66cSSepherosa Ziehau }
802841ab66cSSepherosa Ziehau
803841ab66cSSepherosa Ziehau /*
804841ab66cSSepherosa Ziehau * Check if the specified rate set supports ERP.
805841ab66cSSepherosa Ziehau * NB: the rate set is assumed to be sorted.
806841ab66cSSepherosa Ziehau */
807841ab66cSSepherosa Ziehau int
ieee80211_iserp_rateset(const struct ieee80211_rateset * rs)80832176cfdSRui Paulo ieee80211_iserp_rateset(const struct ieee80211_rateset *rs)
809841ab66cSSepherosa Ziehau {
810841ab66cSSepherosa Ziehau static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 };
811841ab66cSSepherosa Ziehau int i, j;
812841ab66cSSepherosa Ziehau
813085ff963SMatthew Dillon if (rs->rs_nrates < nitems(rates))
814841ab66cSSepherosa Ziehau return 0;
815085ff963SMatthew Dillon for (i = 0; i < nitems(rates); i++) {
816841ab66cSSepherosa Ziehau for (j = 0; j < rs->rs_nrates; j++) {
817841ab66cSSepherosa Ziehau int r = rs->rs_rates[j] & IEEE80211_RATE_VAL;
818841ab66cSSepherosa Ziehau if (rates[i] == r)
819841ab66cSSepherosa Ziehau goto next;
820841ab66cSSepherosa Ziehau if (r > rates[i])
821841ab66cSSepherosa Ziehau return 0;
822841ab66cSSepherosa Ziehau }
823841ab66cSSepherosa Ziehau return 0;
824841ab66cSSepherosa Ziehau next:
825841ab66cSSepherosa Ziehau ;
826841ab66cSSepherosa Ziehau }
827841ab66cSSepherosa Ziehau return 1;
828841ab66cSSepherosa Ziehau }
829841ab66cSSepherosa Ziehau
830841ab66cSSepherosa Ziehau /*
83132176cfdSRui Paulo * Mark the basic rates for the rate table based on the
832841ab66cSSepherosa Ziehau * operating mode. For real 11g we mark all the 11b rates
833841ab66cSSepherosa Ziehau * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
834841ab66cSSepherosa Ziehau * 11b rates. There's also a pseudo 11a-mode used to mark only
835841ab66cSSepherosa Ziehau * the basic OFDM rates.
836841ab66cSSepherosa Ziehau */
83732176cfdSRui Paulo static void
setbasicrates(struct ieee80211_rateset * rs,enum ieee80211_phymode mode,int add)83832176cfdSRui Paulo setbasicrates(struct ieee80211_rateset *rs,
83932176cfdSRui Paulo enum ieee80211_phymode mode, int add)
840841ab66cSSepherosa Ziehau {
84132176cfdSRui Paulo static const struct ieee80211_rateset basic[IEEE80211_MODE_MAX] = {
8429639b71dSSepherosa Ziehau [IEEE80211_MODE_11A] = { 3, { 12, 24, 48 } },
8439639b71dSSepherosa Ziehau [IEEE80211_MODE_11B] = { 2, { 2, 4 } },
84432176cfdSRui Paulo /* NB: mixed b/g */
8459639b71dSSepherosa Ziehau [IEEE80211_MODE_11G] = { 4, { 2, 4, 11, 22 } },
8469639b71dSSepherosa Ziehau [IEEE80211_MODE_TURBO_A] = { 3, { 12, 24, 48 } },
84732176cfdSRui Paulo [IEEE80211_MODE_TURBO_G] = { 4, { 2, 4, 11, 22 } },
84832176cfdSRui Paulo [IEEE80211_MODE_STURBO_A] = { 3, { 12, 24, 48 } },
84932176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 3, { 6, 12, 24 } },
85032176cfdSRui Paulo [IEEE80211_MODE_QUARTER] = { 3, { 3, 6, 12 } },
85132176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 3, { 12, 24, 48 } },
85232176cfdSRui Paulo /* NB: mixed b/g */
85332176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 4, { 2, 4, 11, 22 } },
854841ab66cSSepherosa Ziehau };
855841ab66cSSepherosa Ziehau int i, j;
856841ab66cSSepherosa Ziehau
857841ab66cSSepherosa Ziehau for (i = 0; i < rs->rs_nrates; i++) {
85832176cfdSRui Paulo if (!add)
859841ab66cSSepherosa Ziehau rs->rs_rates[i] &= IEEE80211_RATE_VAL;
86032176cfdSRui Paulo for (j = 0; j < basic[mode].rs_nrates; j++)
86132176cfdSRui Paulo if (basic[mode].rs_rates[j] == rs->rs_rates[i]) {
862841ab66cSSepherosa Ziehau rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
863841ab66cSSepherosa Ziehau break;
864841ab66cSSepherosa Ziehau }
865841ab66cSSepherosa Ziehau }
866841ab66cSSepherosa Ziehau }
867841ab66cSSepherosa Ziehau
86832176cfdSRui Paulo /*
86932176cfdSRui Paulo * Set the basic rates in a rate set.
87032176cfdSRui Paulo */
87132176cfdSRui Paulo void
ieee80211_setbasicrates(struct ieee80211_rateset * rs,enum ieee80211_phymode mode)87232176cfdSRui Paulo ieee80211_setbasicrates(struct ieee80211_rateset *rs,
87332176cfdSRui Paulo enum ieee80211_phymode mode)
874208a1285SSepherosa Ziehau {
87532176cfdSRui Paulo setbasicrates(rs, mode, 0);
876208a1285SSepherosa Ziehau }
877208a1285SSepherosa Ziehau
878841ab66cSSepherosa Ziehau /*
87932176cfdSRui Paulo * Add basic rates to a rate set.
88032176cfdSRui Paulo */
88132176cfdSRui Paulo void
ieee80211_addbasicrates(struct ieee80211_rateset * rs,enum ieee80211_phymode mode)88232176cfdSRui Paulo ieee80211_addbasicrates(struct ieee80211_rateset *rs,
88332176cfdSRui Paulo enum ieee80211_phymode mode)
88432176cfdSRui Paulo {
88532176cfdSRui Paulo setbasicrates(rs, mode, 1);
88632176cfdSRui Paulo }
88732176cfdSRui Paulo
88832176cfdSRui Paulo /*
88932176cfdSRui Paulo * WME protocol support.
89032176cfdSRui Paulo *
89132176cfdSRui Paulo * The default 11a/b/g/n parameters come from the WiFi Alliance WMM
89232176cfdSRui Paulo * System Interopability Test Plan (v1.4, Appendix F) and the 802.11n
89332176cfdSRui Paulo * Draft 2.0 Test Plan (Appendix D).
89432176cfdSRui Paulo *
89532176cfdSRui Paulo * Static/Dynamic Turbo mode settings come from Atheros.
896841ab66cSSepherosa Ziehau */
897841ab66cSSepherosa Ziehau typedef struct phyParamType {
898841ab66cSSepherosa Ziehau uint8_t aifsn;
899841ab66cSSepherosa Ziehau uint8_t logcwmin;
900841ab66cSSepherosa Ziehau uint8_t logcwmax;
901841ab66cSSepherosa Ziehau uint16_t txopLimit;
902841ab66cSSepherosa Ziehau uint8_t acm;
903841ab66cSSepherosa Ziehau } paramType;
904841ab66cSSepherosa Ziehau
905841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = {
90632176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 3, 4, 6, 0, 0 },
90732176cfdSRui Paulo [IEEE80211_MODE_11A] = { 3, 4, 6, 0, 0 },
90832176cfdSRui Paulo [IEEE80211_MODE_11B] = { 3, 4, 6, 0, 0 },
90932176cfdSRui Paulo [IEEE80211_MODE_11G] = { 3, 4, 6, 0, 0 },
91032176cfdSRui Paulo [IEEE80211_MODE_FH] = { 3, 4, 6, 0, 0 },
91132176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 2, 3, 5, 0, 0 },
91232176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 2, 3, 5, 0, 0 },
91332176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 2, 3, 5, 0, 0 },
91432176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 3, 4, 6, 0, 0 },
91532176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 3, 4, 6, 0, 0 },
91632176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 3, 4, 6, 0, 0 },
91732176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 3, 4, 6, 0, 0 },
918841ab66cSSepherosa Ziehau };
919841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = {
92032176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 7, 4, 10, 0, 0 },
92132176cfdSRui Paulo [IEEE80211_MODE_11A] = { 7, 4, 10, 0, 0 },
92232176cfdSRui Paulo [IEEE80211_MODE_11B] = { 7, 4, 10, 0, 0 },
92332176cfdSRui Paulo [IEEE80211_MODE_11G] = { 7, 4, 10, 0, 0 },
92432176cfdSRui Paulo [IEEE80211_MODE_FH] = { 7, 4, 10, 0, 0 },
92532176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 7, 3, 10, 0, 0 },
92632176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 7, 3, 10, 0, 0 },
92732176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 7, 3, 10, 0, 0 },
92832176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 7, 4, 10, 0, 0 },
92932176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 7, 4, 10, 0, 0 },
93032176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 7, 4, 10, 0, 0 },
93132176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 7, 4, 10, 0, 0 },
932841ab66cSSepherosa Ziehau };
933841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = {
93432176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 1, 3, 4, 94, 0 },
93532176cfdSRui Paulo [IEEE80211_MODE_11A] = { 1, 3, 4, 94, 0 },
93632176cfdSRui Paulo [IEEE80211_MODE_11B] = { 1, 3, 4, 188, 0 },
93732176cfdSRui Paulo [IEEE80211_MODE_11G] = { 1, 3, 4, 94, 0 },
93832176cfdSRui Paulo [IEEE80211_MODE_FH] = { 1, 3, 4, 188, 0 },
93932176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 1, 2, 3, 94, 0 },
94032176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 1, 2, 3, 94, 0 },
94132176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 1, 2, 3, 94, 0 },
94232176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 1, 3, 4, 94, 0 },
94332176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 1, 3, 4, 94, 0 },
94432176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 1, 3, 4, 94, 0 },
94532176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 1, 3, 4, 94, 0 },
946841ab66cSSepherosa Ziehau };
947841ab66cSSepherosa Ziehau static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = {
94832176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 1, 2, 3, 47, 0 },
94932176cfdSRui Paulo [IEEE80211_MODE_11A] = { 1, 2, 3, 47, 0 },
95032176cfdSRui Paulo [IEEE80211_MODE_11B] = { 1, 2, 3, 102, 0 },
95132176cfdSRui Paulo [IEEE80211_MODE_11G] = { 1, 2, 3, 47, 0 },
95232176cfdSRui Paulo [IEEE80211_MODE_FH] = { 1, 2, 3, 102, 0 },
95332176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 1, 2, 2, 47, 0 },
95432176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 1, 2, 2, 47, 0 },
95532176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 1, 2, 2, 47, 0 },
95632176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 1, 2, 3, 47, 0 },
95732176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 1, 2, 3, 47, 0 },
95832176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 1, 2, 3, 47, 0 },
95932176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 1, 2, 3, 47, 0 },
960841ab66cSSepherosa Ziehau };
961841ab66cSSepherosa Ziehau
962841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = {
96332176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 3, 4, 10, 0, 0 },
96432176cfdSRui Paulo [IEEE80211_MODE_11A] = { 3, 4, 10, 0, 0 },
96532176cfdSRui Paulo [IEEE80211_MODE_11B] = { 3, 4, 10, 0, 0 },
96632176cfdSRui Paulo [IEEE80211_MODE_11G] = { 3, 4, 10, 0, 0 },
96732176cfdSRui Paulo [IEEE80211_MODE_FH] = { 3, 4, 10, 0, 0 },
96832176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 2, 3, 10, 0, 0 },
96932176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 2, 3, 10, 0, 0 },
97032176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 2, 3, 10, 0, 0 },
97132176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 3, 4, 10, 0, 0 },
97232176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 3, 4, 10, 0, 0 },
97332176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 3, 4, 10, 0, 0 },
97432176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 3, 4, 10, 0, 0 },
975841ab66cSSepherosa Ziehau };
976841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = {
97732176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 2, 3, 4, 94, 0 },
97832176cfdSRui Paulo [IEEE80211_MODE_11A] = { 2, 3, 4, 94, 0 },
97932176cfdSRui Paulo [IEEE80211_MODE_11B] = { 2, 3, 4, 188, 0 },
98032176cfdSRui Paulo [IEEE80211_MODE_11G] = { 2, 3, 4, 94, 0 },
98132176cfdSRui Paulo [IEEE80211_MODE_FH] = { 2, 3, 4, 188, 0 },
98232176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 2, 2, 3, 94, 0 },
98332176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 2, 2, 3, 94, 0 },
98432176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 2, 2, 3, 94, 0 },
98532176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 2, 3, 4, 94, 0 },
98632176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 2, 3, 4, 94, 0 },
98732176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 2, 3, 4, 94, 0 },
98832176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 2, 3, 4, 94, 0 },
989841ab66cSSepherosa Ziehau };
990841ab66cSSepherosa Ziehau static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = {
99132176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 2, 2, 3, 47, 0 },
99232176cfdSRui Paulo [IEEE80211_MODE_11A] = { 2, 2, 3, 47, 0 },
99332176cfdSRui Paulo [IEEE80211_MODE_11B] = { 2, 2, 3, 102, 0 },
99432176cfdSRui Paulo [IEEE80211_MODE_11G] = { 2, 2, 3, 47, 0 },
99532176cfdSRui Paulo [IEEE80211_MODE_FH] = { 2, 2, 3, 102, 0 },
99632176cfdSRui Paulo [IEEE80211_MODE_TURBO_A]= { 1, 2, 2, 47, 0 },
99732176cfdSRui Paulo [IEEE80211_MODE_TURBO_G]= { 1, 2, 2, 47, 0 },
99832176cfdSRui Paulo [IEEE80211_MODE_STURBO_A]={ 1, 2, 2, 47, 0 },
99932176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 2, 2, 3, 47, 0 },
100032176cfdSRui Paulo [IEEE80211_MODE_QUARTER]= { 2, 2, 3, 47, 0 },
100132176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 2, 2, 3, 47, 0 },
100232176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 2, 2, 3, 47, 0 },
1003841ab66cSSepherosa Ziehau };
1004841ab66cSSepherosa Ziehau
100532176cfdSRui Paulo static void
_setifsparams(struct wmeParams * wmep,const paramType * phy)100632176cfdSRui Paulo _setifsparams(struct wmeParams *wmep, const paramType *phy)
1007841ab66cSSepherosa Ziehau {
100832176cfdSRui Paulo wmep->wmep_aifsn = phy->aifsn;
100932176cfdSRui Paulo wmep->wmep_logcwmin = phy->logcwmin;
101032176cfdSRui Paulo wmep->wmep_logcwmax = phy->logcwmax;
101132176cfdSRui Paulo wmep->wmep_txopLimit = phy->txopLimit;
101232176cfdSRui Paulo }
101332176cfdSRui Paulo
101432176cfdSRui Paulo static void
setwmeparams(struct ieee80211vap * vap,const char * type,int ac,struct wmeParams * wmep,const paramType * phy)101532176cfdSRui Paulo setwmeparams(struct ieee80211vap *vap, const char *type, int ac,
101632176cfdSRui Paulo struct wmeParams *wmep, const paramType *phy)
101732176cfdSRui Paulo {
101832176cfdSRui Paulo wmep->wmep_acm = phy->acm;
101932176cfdSRui Paulo _setifsparams(wmep, phy);
102032176cfdSRui Paulo
102132176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
102232176cfdSRui Paulo "set %s (%s) [acm %u aifsn %u logcwmin %u logcwmax %u txop %u]\n",
102332176cfdSRui Paulo ieee80211_wme_acnames[ac], type,
102432176cfdSRui Paulo wmep->wmep_acm, wmep->wmep_aifsn, wmep->wmep_logcwmin,
102532176cfdSRui Paulo wmep->wmep_logcwmax, wmep->wmep_txopLimit);
102632176cfdSRui Paulo }
102732176cfdSRui Paulo
102832176cfdSRui Paulo static void
ieee80211_wme_initparams_locked(struct ieee80211vap * vap)102932176cfdSRui Paulo ieee80211_wme_initparams_locked(struct ieee80211vap *vap)
103032176cfdSRui Paulo {
103132176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
1032841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme;
1033841ab66cSSepherosa Ziehau const paramType *pPhyParam, *pBssPhyParam;
1034841ab66cSSepherosa Ziehau struct wmeParams *wmep;
103532176cfdSRui Paulo enum ieee80211_phymode mode;
1036841ab66cSSepherosa Ziehau int i;
1037841ab66cSSepherosa Ziehau
1038085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1039085ff963SMatthew Dillon
104032176cfdSRui Paulo if ((ic->ic_caps & IEEE80211_C_WME) == 0 || ic->ic_nrunning > 1)
1041841ab66cSSepherosa Ziehau return;
1042841ab66cSSepherosa Ziehau
104332176cfdSRui Paulo /*
1044085ff963SMatthew Dillon * Clear the wme cap_info field so a qoscount from a previous
1045085ff963SMatthew Dillon * vap doesn't confuse later code which only parses the beacon
1046085ff963SMatthew Dillon * field and updates hardware when said field changes.
1047085ff963SMatthew Dillon * Otherwise the hardware is programmed with defaults, not what
1048085ff963SMatthew Dillon * the beacon actually announces.
1049085ff963SMatthew Dillon */
1050085ff963SMatthew Dillon wme->wme_wmeChanParams.cap_info = 0;
1051085ff963SMatthew Dillon
1052085ff963SMatthew Dillon /*
105332176cfdSRui Paulo * Select mode; we can be called early in which case we
105432176cfdSRui Paulo * always use auto mode. We know we'll be called when
105532176cfdSRui Paulo * entering the RUN state with bsschan setup properly
105632176cfdSRui Paulo * so state will eventually get set correctly
105732176cfdSRui Paulo */
105832176cfdSRui Paulo if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)
105932176cfdSRui Paulo mode = ieee80211_chan2mode(ic->ic_bsschan);
106032176cfdSRui Paulo else
106132176cfdSRui Paulo mode = IEEE80211_MODE_AUTO;
1062841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) {
1063841ab66cSSepherosa Ziehau switch (i) {
1064841ab66cSSepherosa Ziehau case WME_AC_BK:
106532176cfdSRui Paulo pPhyParam = &phyParamForAC_BK[mode];
106632176cfdSRui Paulo pBssPhyParam = &phyParamForAC_BK[mode];
1067841ab66cSSepherosa Ziehau break;
1068841ab66cSSepherosa Ziehau case WME_AC_VI:
106932176cfdSRui Paulo pPhyParam = &phyParamForAC_VI[mode];
107032176cfdSRui Paulo pBssPhyParam = &bssPhyParamForAC_VI[mode];
1071841ab66cSSepherosa Ziehau break;
1072841ab66cSSepherosa Ziehau case WME_AC_VO:
107332176cfdSRui Paulo pPhyParam = &phyParamForAC_VO[mode];
107432176cfdSRui Paulo pBssPhyParam = &bssPhyParamForAC_VO[mode];
1075841ab66cSSepherosa Ziehau break;
1076841ab66cSSepherosa Ziehau case WME_AC_BE:
1077841ab66cSSepherosa Ziehau default:
107832176cfdSRui Paulo pPhyParam = &phyParamForAC_BE[mode];
107932176cfdSRui Paulo pBssPhyParam = &bssPhyParamForAC_BE[mode];
1080841ab66cSSepherosa Ziehau break;
1081841ab66cSSepherosa Ziehau }
1082841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
1083841ab66cSSepherosa Ziehau if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
108432176cfdSRui Paulo setwmeparams(vap, "chan", i, wmep, pPhyParam);
1085841ab66cSSepherosa Ziehau } else {
108632176cfdSRui Paulo setwmeparams(vap, "chan", i, wmep, pBssPhyParam);
1087841ab66cSSepherosa Ziehau }
1088841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
108932176cfdSRui Paulo setwmeparams(vap, "bss ", i, wmep, pBssPhyParam);
1090841ab66cSSepherosa Ziehau }
1091841ab66cSSepherosa Ziehau /* NB: check ic_bss to avoid NULL deref on initial attach */
109232176cfdSRui Paulo if (vap->iv_bss != NULL) {
1093841ab66cSSepherosa Ziehau /*
10944f655ef5SMatthew Dillon * Calculate aggressive mode switching threshold based
1095841ab66cSSepherosa Ziehau * on beacon interval. This doesn't need locking since
1096841ab66cSSepherosa Ziehau * we're only called before entering the RUN state at
1097841ab66cSSepherosa Ziehau * which point we start sending beacon frames.
1098841ab66cSSepherosa Ziehau */
1099841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh =
110032176cfdSRui Paulo (HIGH_PRI_SWITCH_THRESH * vap->iv_bss->ni_intval) / 100;
110132176cfdSRui Paulo wme->wme_flags &= ~WME_F_AGGRMODE;
110232176cfdSRui Paulo ieee80211_wme_updateparams(vap);
1103841ab66cSSepherosa Ziehau }
1104841ab66cSSepherosa Ziehau }
1105841ab66cSSepherosa Ziehau
110632176cfdSRui Paulo void
ieee80211_wme_initparams(struct ieee80211vap * vap)110732176cfdSRui Paulo ieee80211_wme_initparams(struct ieee80211vap *vap)
110832176cfdSRui Paulo {
1109085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic;
1110085ff963SMatthew Dillon
1111085ff963SMatthew Dillon IEEE80211_LOCK(ic);
111232176cfdSRui Paulo ieee80211_wme_initparams_locked(vap);
1113085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
111432176cfdSRui Paulo }
111532176cfdSRui Paulo
1116841ab66cSSepherosa Ziehau /*
1117841ab66cSSepherosa Ziehau * Update WME parameters for ourself and the BSS.
1118841ab66cSSepherosa Ziehau */
1119841ab66cSSepherosa Ziehau void
ieee80211_wme_updateparams_locked(struct ieee80211vap * vap)112032176cfdSRui Paulo ieee80211_wme_updateparams_locked(struct ieee80211vap *vap)
1121841ab66cSSepherosa Ziehau {
112232176cfdSRui Paulo static const paramType aggrParam[IEEE80211_MODE_MAX] = {
112332176cfdSRui Paulo [IEEE80211_MODE_AUTO] = { 2, 4, 10, 64, 0 },
112432176cfdSRui Paulo [IEEE80211_MODE_11A] = { 2, 4, 10, 64, 0 },
112532176cfdSRui Paulo [IEEE80211_MODE_11B] = { 2, 5, 10, 64, 0 },
112632176cfdSRui Paulo [IEEE80211_MODE_11G] = { 2, 4, 10, 64, 0 },
112732176cfdSRui Paulo [IEEE80211_MODE_FH] = { 2, 5, 10, 64, 0 },
112832176cfdSRui Paulo [IEEE80211_MODE_TURBO_A] = { 1, 3, 10, 64, 0 },
112932176cfdSRui Paulo [IEEE80211_MODE_TURBO_G] = { 1, 3, 10, 64, 0 },
113032176cfdSRui Paulo [IEEE80211_MODE_STURBO_A] = { 1, 3, 10, 64, 0 },
113132176cfdSRui Paulo [IEEE80211_MODE_HALF] = { 2, 4, 10, 64, 0 },
113232176cfdSRui Paulo [IEEE80211_MODE_QUARTER] = { 2, 4, 10, 64, 0 },
113332176cfdSRui Paulo [IEEE80211_MODE_11NA] = { 2, 4, 10, 64, 0 }, /* XXXcheck*/
113432176cfdSRui Paulo [IEEE80211_MODE_11NG] = { 2, 4, 10, 64, 0 }, /* XXXcheck*/
1135841ab66cSSepherosa Ziehau };
113632176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
1137841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme;
1138841ab66cSSepherosa Ziehau const struct wmeParams *wmep;
1139841ab66cSSepherosa Ziehau struct wmeParams *chanp, *bssp;
114032176cfdSRui Paulo enum ieee80211_phymode mode;
1141841ab66cSSepherosa Ziehau int i;
1142085ff963SMatthew Dillon int do_aggrmode = 0;
1143841ab66cSSepherosa Ziehau
114432176cfdSRui Paulo /*
114532176cfdSRui Paulo * Set up the channel access parameters for the physical
114632176cfdSRui Paulo * device. First populate the configured settings.
114732176cfdSRui Paulo */
1148841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) {
1149841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[i];
1150841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
1151841ab66cSSepherosa Ziehau chanp->wmep_aifsn = wmep->wmep_aifsn;
1152841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = wmep->wmep_logcwmin;
1153841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = wmep->wmep_logcwmax;
1154841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = wmep->wmep_txopLimit;
1155841ab66cSSepherosa Ziehau
1156841ab66cSSepherosa Ziehau chanp = &wme->wme_bssChanParams.cap_wmeParams[i];
1157841ab66cSSepherosa Ziehau wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
1158841ab66cSSepherosa Ziehau chanp->wmep_aifsn = wmep->wmep_aifsn;
1159841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = wmep->wmep_logcwmin;
1160841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = wmep->wmep_logcwmax;
1161841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = wmep->wmep_txopLimit;
1162841ab66cSSepherosa Ziehau }
1163841ab66cSSepherosa Ziehau
1164841ab66cSSepherosa Ziehau /*
116532176cfdSRui Paulo * Select mode; we can be called early in which case we
116632176cfdSRui Paulo * always use auto mode. We know we'll be called when
116732176cfdSRui Paulo * entering the RUN state with bsschan setup properly
116832176cfdSRui Paulo * so state will eventually get set correctly
116932176cfdSRui Paulo */
117032176cfdSRui Paulo if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)
117132176cfdSRui Paulo mode = ieee80211_chan2mode(ic->ic_bsschan);
117232176cfdSRui Paulo else
117332176cfdSRui Paulo mode = IEEE80211_MODE_AUTO;
117432176cfdSRui Paulo
117532176cfdSRui Paulo /*
11764f655ef5SMatthew Dillon * This implements aggressive mode as found in certain
1177841ab66cSSepherosa Ziehau * vendors' AP's. When there is significant high
1178841ab66cSSepherosa Ziehau * priority (VI/VO) traffic in the BSS throttle back BE
1179841ab66cSSepherosa Ziehau * traffic by using conservative parameters. Otherwise
11804f655ef5SMatthew Dillon * BE uses aggressive params to optimize performance of
1181841ab66cSSepherosa Ziehau * legacy/non-QoS traffic.
1182841ab66cSSepherosa Ziehau */
1183085ff963SMatthew Dillon
1184085ff963SMatthew Dillon /* Hostap? Only if aggressive mode is enabled */
1185085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
1186085ff963SMatthew Dillon (wme->wme_flags & WME_F_AGGRMODE) != 0)
1187085ff963SMatthew Dillon do_aggrmode = 1;
1188085ff963SMatthew Dillon
1189085ff963SMatthew Dillon /*
1190085ff963SMatthew Dillon * Station? Only if we're in a non-QoS BSS.
1191085ff963SMatthew Dillon */
1192085ff963SMatthew Dillon else if ((vap->iv_opmode == IEEE80211_M_STA &&
1193085ff963SMatthew Dillon (vap->iv_bss->ni_flags & IEEE80211_NODE_QOS) == 0))
1194085ff963SMatthew Dillon do_aggrmode = 1;
1195085ff963SMatthew Dillon
1196085ff963SMatthew Dillon /*
1197085ff963SMatthew Dillon * IBSS? Only if we we have WME enabled.
1198085ff963SMatthew Dillon */
1199085ff963SMatthew Dillon else if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
1200085ff963SMatthew Dillon (vap->iv_flags & IEEE80211_F_WME))
1201085ff963SMatthew Dillon do_aggrmode = 1;
1202085ff963SMatthew Dillon
1203085ff963SMatthew Dillon /*
1204085ff963SMatthew Dillon * If WME is disabled on this VAP, default to aggressive mode
1205085ff963SMatthew Dillon * regardless of the configuration.
1206085ff963SMatthew Dillon */
1207085ff963SMatthew Dillon if ((vap->iv_flags & IEEE80211_F_WME) == 0)
1208085ff963SMatthew Dillon do_aggrmode = 1;
1209085ff963SMatthew Dillon
1210085ff963SMatthew Dillon /* XXX WDS? */
1211085ff963SMatthew Dillon
1212085ff963SMatthew Dillon /* XXX MBSS? */
1213085ff963SMatthew Dillon
1214085ff963SMatthew Dillon if (do_aggrmode) {
1215841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
1216841ab66cSSepherosa Ziehau bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
1217841ab66cSSepherosa Ziehau
121832176cfdSRui Paulo chanp->wmep_aifsn = bssp->wmep_aifsn = aggrParam[mode].aifsn;
1219841ab66cSSepherosa Ziehau chanp->wmep_logcwmin = bssp->wmep_logcwmin =
122032176cfdSRui Paulo aggrParam[mode].logcwmin;
1221841ab66cSSepherosa Ziehau chanp->wmep_logcwmax = bssp->wmep_logcwmax =
122232176cfdSRui Paulo aggrParam[mode].logcwmax;
1223841ab66cSSepherosa Ziehau chanp->wmep_txopLimit = bssp->wmep_txopLimit =
122432176cfdSRui Paulo (vap->iv_flags & IEEE80211_F_BURST) ?
122532176cfdSRui Paulo aggrParam[mode].txopLimit : 0;
122632176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
122732176cfdSRui Paulo "update %s (chan+bss) [acm %u aifsn %u logcwmin %u "
122832176cfdSRui Paulo "logcwmax %u txop %u]\n", ieee80211_wme_acnames[WME_AC_BE],
122932176cfdSRui Paulo chanp->wmep_acm, chanp->wmep_aifsn, chanp->wmep_logcwmin,
123032176cfdSRui Paulo chanp->wmep_logcwmax, chanp->wmep_txopLimit);
1231841ab66cSSepherosa Ziehau }
1232841ab66cSSepherosa Ziehau
1233085ff963SMatthew Dillon
1234085ff963SMatthew Dillon /*
1235085ff963SMatthew Dillon * Change the contention window based on the number of associated
1236085ff963SMatthew Dillon * stations. If the number of associated stations is 1 and
1237085ff963SMatthew Dillon * aggressive mode is enabled, lower the contention window even
1238085ff963SMatthew Dillon * further.
1239085ff963SMatthew Dillon */
124032176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
1241841ab66cSSepherosa Ziehau ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) {
1242841ab66cSSepherosa Ziehau static const uint8_t logCwMin[IEEE80211_MODE_MAX] = {
124332176cfdSRui Paulo [IEEE80211_MODE_AUTO] = 3,
124432176cfdSRui Paulo [IEEE80211_MODE_11A] = 3,
124532176cfdSRui Paulo [IEEE80211_MODE_11B] = 4,
124632176cfdSRui Paulo [IEEE80211_MODE_11G] = 3,
124732176cfdSRui Paulo [IEEE80211_MODE_FH] = 4,
124832176cfdSRui Paulo [IEEE80211_MODE_TURBO_A] = 3,
124932176cfdSRui Paulo [IEEE80211_MODE_TURBO_G] = 3,
125032176cfdSRui Paulo [IEEE80211_MODE_STURBO_A] = 3,
125132176cfdSRui Paulo [IEEE80211_MODE_HALF] = 3,
125232176cfdSRui Paulo [IEEE80211_MODE_QUARTER] = 3,
125332176cfdSRui Paulo [IEEE80211_MODE_11NA] = 3,
125432176cfdSRui Paulo [IEEE80211_MODE_11NG] = 3,
1255841ab66cSSepherosa Ziehau };
1256841ab66cSSepherosa Ziehau chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
1257841ab66cSSepherosa Ziehau bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
1258841ab66cSSepherosa Ziehau
125932176cfdSRui Paulo chanp->wmep_logcwmin = bssp->wmep_logcwmin = logCwMin[mode];
126032176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
126132176cfdSRui Paulo "update %s (chan+bss) logcwmin %u\n",
126232176cfdSRui Paulo ieee80211_wme_acnames[WME_AC_BE], chanp->wmep_logcwmin);
1263841ab66cSSepherosa Ziehau }
1264085ff963SMatthew Dillon
1265085ff963SMatthew Dillon /*
1266085ff963SMatthew Dillon * Arrange for the beacon update.
1267085ff963SMatthew Dillon *
1268085ff963SMatthew Dillon * XXX what about MBSS, WDS?
1269085ff963SMatthew Dillon */
1270085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_HOSTAP
1271085ff963SMatthew Dillon || vap->iv_opmode == IEEE80211_M_IBSS) {
1272841ab66cSSepherosa Ziehau /*
1273841ab66cSSepherosa Ziehau * Arrange for a beacon update and bump the parameter
1274841ab66cSSepherosa Ziehau * set number so associated stations load the new values.
1275841ab66cSSepherosa Ziehau */
1276841ab66cSSepherosa Ziehau wme->wme_bssChanParams.cap_info =
1277841ab66cSSepherosa Ziehau (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT;
127832176cfdSRui Paulo ieee80211_beacon_notify(vap, IEEE80211_BEACON_WME);
1279841ab66cSSepherosa Ziehau }
1280841ab66cSSepherosa Ziehau
12814f655ef5SMatthew Dillon /* schedule the deferred WME update */
12824f655ef5SMatthew Dillon ieee80211_runtask(ic, &ic->ic_wme_task);
1283841ab66cSSepherosa Ziehau
128432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
1285841ab66cSSepherosa Ziehau "%s: WME params updated, cap_info 0x%x\n", __func__,
128632176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_STA ?
1287841ab66cSSepherosa Ziehau wme->wme_wmeChanParams.cap_info :
1288841ab66cSSepherosa Ziehau wme->wme_bssChanParams.cap_info);
1289841ab66cSSepherosa Ziehau }
1290841ab66cSSepherosa Ziehau
1291841ab66cSSepherosa Ziehau void
ieee80211_wme_updateparams(struct ieee80211vap * vap)129232176cfdSRui Paulo ieee80211_wme_updateparams(struct ieee80211vap *vap)
129332176cfdSRui Paulo {
129432176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
129532176cfdSRui Paulo
129632176cfdSRui Paulo if (ic->ic_caps & IEEE80211_C_WME) {
1297085ff963SMatthew Dillon IEEE80211_LOCK(ic);
129832176cfdSRui Paulo ieee80211_wme_updateparams_locked(vap);
1299085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
130032176cfdSRui Paulo }
130132176cfdSRui Paulo }
130232176cfdSRui Paulo
130332176cfdSRui Paulo static void
parent_updown(void * arg,int npending)1304085ff963SMatthew Dillon parent_updown(void *arg, int npending)
130532176cfdSRui Paulo {
13064f655ef5SMatthew Dillon struct ieee80211com *ic = arg;
130732176cfdSRui Paulo
13084f655ef5SMatthew Dillon ic->ic_parent(ic);
130932176cfdSRui Paulo }
131032176cfdSRui Paulo
131132176cfdSRui Paulo static void
update_mcast(void * arg,int npending)1312085ff963SMatthew Dillon update_mcast(void *arg, int npending)
131332176cfdSRui Paulo {
131432176cfdSRui Paulo struct ieee80211com *ic = arg;
131532176cfdSRui Paulo
13164f898719SImre Vadász ic->ic_update_mcast(ic);
131732176cfdSRui Paulo }
131832176cfdSRui Paulo
131932176cfdSRui Paulo static void
update_promisc(void * arg,int npending)1320085ff963SMatthew Dillon update_promisc(void *arg, int npending)
132132176cfdSRui Paulo {
132232176cfdSRui Paulo struct ieee80211com *ic = arg;
132332176cfdSRui Paulo
13244f898719SImre Vadász ic->ic_update_promisc(ic);
132532176cfdSRui Paulo }
132632176cfdSRui Paulo
132732176cfdSRui Paulo static void
update_channel(void * arg,int npending)1328085ff963SMatthew Dillon update_channel(void *arg, int npending)
132932176cfdSRui Paulo {
133032176cfdSRui Paulo struct ieee80211com *ic = arg;
133132176cfdSRui Paulo
133232176cfdSRui Paulo ic->ic_set_channel(ic);
133332176cfdSRui Paulo ieee80211_radiotap_chan_change(ic);
1334085ff963SMatthew Dillon }
1335085ff963SMatthew Dillon
1336085ff963SMatthew Dillon static void
update_chw(void * arg,int npending)1337085ff963SMatthew Dillon update_chw(void *arg, int npending)
1338085ff963SMatthew Dillon {
1339085ff963SMatthew Dillon struct ieee80211com *ic = arg;
1340085ff963SMatthew Dillon
1341085ff963SMatthew Dillon /*
1342085ff963SMatthew Dillon * XXX should we defer the channel width _config_ update until now?
1343085ff963SMatthew Dillon */
1344085ff963SMatthew Dillon ic->ic_update_chw(ic);
134532176cfdSRui Paulo }
134632176cfdSRui Paulo
13474f655ef5SMatthew Dillon static void
update_wme(void * arg,int npending)13484f655ef5SMatthew Dillon update_wme(void *arg, int npending)
13494f655ef5SMatthew Dillon {
13504f655ef5SMatthew Dillon struct ieee80211com *ic = arg;
13514f655ef5SMatthew Dillon
13524f655ef5SMatthew Dillon /*
13534f655ef5SMatthew Dillon * XXX should we defer the WME configuration update until now?
13544f655ef5SMatthew Dillon */
13554f655ef5SMatthew Dillon ic->ic_wme.wme_update(ic);
13564f655ef5SMatthew Dillon }
13574f655ef5SMatthew Dillon
13584f655ef5SMatthew Dillon static void
restart_vaps(void * arg,int npending)13594f655ef5SMatthew Dillon restart_vaps(void *arg, int npending)
13604f655ef5SMatthew Dillon {
13614f655ef5SMatthew Dillon struct ieee80211com *ic = arg;
13624f655ef5SMatthew Dillon
13634f655ef5SMatthew Dillon ieee80211_suspend_all(ic);
13644f655ef5SMatthew Dillon ieee80211_resume_all(ic);
13654f655ef5SMatthew Dillon }
13664f655ef5SMatthew Dillon
136732176cfdSRui Paulo /*
136832176cfdSRui Paulo * Block until the parent is in a known state. This is
136932176cfdSRui Paulo * used after any operations that dispatch a task (e.g.
137032176cfdSRui Paulo * to auto-configure the parent device up/down).
137132176cfdSRui Paulo */
137232176cfdSRui Paulo void
ieee80211_waitfor_parent(struct ieee80211com * ic)137332176cfdSRui Paulo ieee80211_waitfor_parent(struct ieee80211com *ic)
137432176cfdSRui Paulo {
137532176cfdSRui Paulo taskqueue_block(ic->ic_tq);
137632176cfdSRui Paulo ieee80211_draintask(ic, &ic->ic_parent_task);
137732176cfdSRui Paulo ieee80211_draintask(ic, &ic->ic_mcast_task);
137832176cfdSRui Paulo ieee80211_draintask(ic, &ic->ic_promisc_task);
137932176cfdSRui Paulo ieee80211_draintask(ic, &ic->ic_chan_task);
138032176cfdSRui Paulo ieee80211_draintask(ic, &ic->ic_bmiss_task);
1381085ff963SMatthew Dillon ieee80211_draintask(ic, &ic->ic_chw_task);
13824f655ef5SMatthew Dillon ieee80211_draintask(ic, &ic->ic_wme_task);
138332176cfdSRui Paulo taskqueue_unblock(ic->ic_tq);
138432176cfdSRui Paulo }
138532176cfdSRui Paulo
138632176cfdSRui Paulo /*
13874f898719SImre Vadász * Check to see whether the current channel needs reset.
13884f898719SImre Vadász *
13894f898719SImre Vadász * Some devices don't handle being given an invalid channel
13904f898719SImre Vadász * in their operating mode very well (eg wpi(4) will throw a
13914f898719SImre Vadász * firmware exception.)
13924f898719SImre Vadász *
13934f898719SImre Vadász * Return 0 if we're ok, 1 if the channel needs to be reset.
13944f898719SImre Vadász *
13954f898719SImre Vadász * See PR kern/202502.
13964f898719SImre Vadász */
13974f898719SImre Vadász static int
ieee80211_start_check_reset_chan(struct ieee80211vap * vap)13984f898719SImre Vadász ieee80211_start_check_reset_chan(struct ieee80211vap *vap)
13994f898719SImre Vadász {
14004f898719SImre Vadász struct ieee80211com *ic = vap->iv_ic;
14014f898719SImre Vadász
14024f898719SImre Vadász if ((vap->iv_opmode == IEEE80211_M_IBSS &&
14034f898719SImre Vadász IEEE80211_IS_CHAN_NOADHOC(ic->ic_curchan)) ||
14044f898719SImre Vadász (vap->iv_opmode == IEEE80211_M_HOSTAP &&
14054f898719SImre Vadász IEEE80211_IS_CHAN_NOHOSTAP(ic->ic_curchan)))
14064f898719SImre Vadász return (1);
14074f898719SImre Vadász return (0);
14084f898719SImre Vadász }
14094f898719SImre Vadász
14104f898719SImre Vadász /*
14114f898719SImre Vadász * Reset the curchan to a known good state.
14124f898719SImre Vadász */
14134f898719SImre Vadász static void
ieee80211_start_reset_chan(struct ieee80211vap * vap)14144f898719SImre Vadász ieee80211_start_reset_chan(struct ieee80211vap *vap)
14154f898719SImre Vadász {
14164f898719SImre Vadász struct ieee80211com *ic = vap->iv_ic;
14174f898719SImre Vadász
14184f898719SImre Vadász ic->ic_curchan = &ic->ic_channels[0];
14194f898719SImre Vadász }
14204f898719SImre Vadász
14214f898719SImre Vadász /*
142232176cfdSRui Paulo * Start a vap running. If this is the first vap to be
142332176cfdSRui Paulo * set running on the underlying device then we
142432176cfdSRui Paulo * automatically bring the device up.
142532176cfdSRui Paulo */
142632176cfdSRui Paulo void
ieee80211_start_locked(struct ieee80211vap * vap)142732176cfdSRui Paulo ieee80211_start_locked(struct ieee80211vap *vap)
142832176cfdSRui Paulo {
142932176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
143032176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
143132176cfdSRui Paulo
1432085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1433085ff963SMatthew Dillon
143432176cfdSRui Paulo IEEE80211_DPRINTF(vap,
143532176cfdSRui Paulo IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
143632176cfdSRui Paulo "start running, %d vaps running\n", ic->ic_nrunning);
143732176cfdSRui Paulo
1438085ff963SMatthew Dillon if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
143932176cfdSRui Paulo /*
144032176cfdSRui Paulo * Mark us running. Note that it's ok to do this first;
144132176cfdSRui Paulo * if we need to bring the parent device up we defer that
144232176cfdSRui Paulo * to avoid dropping the com lock. We expect the device
144332176cfdSRui Paulo * to respond to being marked up by calling back into us
144432176cfdSRui Paulo * through ieee80211_start_all at which point we'll come
144532176cfdSRui Paulo * back in here and complete the work.
144632176cfdSRui Paulo */
1447085ff963SMatthew Dillon ifp->if_drv_flags |= IFF_DRV_RUNNING;
144832176cfdSRui Paulo /*
144932176cfdSRui Paulo * We are not running; if this we are the first vap
145032176cfdSRui Paulo * to be brought up auto-up the parent if necessary.
145132176cfdSRui Paulo */
14524f655ef5SMatthew Dillon if (ic->ic_nrunning++ == 0) {
14534f898719SImre Vadász
14544f898719SImre Vadász /* reset the channel to a known good channel */
14554f898719SImre Vadász if (ieee80211_start_check_reset_chan(vap))
14564f898719SImre Vadász ieee80211_start_reset_chan(vap);
14574f898719SImre Vadász
145832176cfdSRui Paulo IEEE80211_DPRINTF(vap,
145932176cfdSRui Paulo IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
14604f655ef5SMatthew Dillon "%s: up parent %s\n", __func__, ic->ic_name);
146132176cfdSRui Paulo ieee80211_runtask(ic, &ic->ic_parent_task);
146232176cfdSRui Paulo return;
146332176cfdSRui Paulo }
146432176cfdSRui Paulo }
146532176cfdSRui Paulo /*
146632176cfdSRui Paulo * If the parent is up and running, then kick the
146732176cfdSRui Paulo * 802.11 state machine as appropriate.
146832176cfdSRui Paulo */
14694f655ef5SMatthew Dillon if (vap->iv_roaming != IEEE80211_ROAMING_MANUAL) {
147032176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA) {
147132176cfdSRui Paulo #if 0
147232176cfdSRui Paulo /* XXX bypasses scan too easily; disable for now */
147332176cfdSRui Paulo /*
147432176cfdSRui Paulo * Try to be intelligent about clocking the state
147532176cfdSRui Paulo * machine. If we're currently in RUN state then
147632176cfdSRui Paulo * we should be able to apply any new state/parameters
147732176cfdSRui Paulo * simply by re-associating. Otherwise we need to
147832176cfdSRui Paulo * re-scan to select an appropriate ap.
147932176cfdSRui Paulo */
148032176cfdSRui Paulo if (vap->iv_state >= IEEE80211_S_RUN)
148132176cfdSRui Paulo ieee80211_new_state_locked(vap,
148232176cfdSRui Paulo IEEE80211_S_ASSOC, 1);
148332176cfdSRui Paulo else
148432176cfdSRui Paulo #endif
148532176cfdSRui Paulo ieee80211_new_state_locked(vap,
148632176cfdSRui Paulo IEEE80211_S_SCAN, 0);
148732176cfdSRui Paulo } else {
148832176cfdSRui Paulo /*
148932176cfdSRui Paulo * For monitor+wds mode there's nothing to do but
149032176cfdSRui Paulo * start running. Otherwise if this is the first
149132176cfdSRui Paulo * vap to be brought up, start a scan which may be
149232176cfdSRui Paulo * preempted if the station is locked to a particular
149332176cfdSRui Paulo * channel.
149432176cfdSRui Paulo */
149532176cfdSRui Paulo vap->iv_flags_ext |= IEEE80211_FEXT_REINIT;
149632176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MONITOR ||
149732176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_WDS)
149832176cfdSRui Paulo ieee80211_new_state_locked(vap,
149932176cfdSRui Paulo IEEE80211_S_RUN, -1);
150032176cfdSRui Paulo else
150132176cfdSRui Paulo ieee80211_new_state_locked(vap,
150232176cfdSRui Paulo IEEE80211_S_SCAN, 0);
150332176cfdSRui Paulo }
150432176cfdSRui Paulo }
150532176cfdSRui Paulo }
150632176cfdSRui Paulo
150732176cfdSRui Paulo /*
150832176cfdSRui Paulo * Start a single vap.
150932176cfdSRui Paulo */
151032176cfdSRui Paulo void
ieee80211_init(void * arg)151132176cfdSRui Paulo ieee80211_init(void *arg)
151232176cfdSRui Paulo {
151332176cfdSRui Paulo struct ieee80211vap *vap = arg;
151432176cfdSRui Paulo
151532176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
151632176cfdSRui Paulo "%s\n", __func__);
151732176cfdSRui Paulo
1518085ff963SMatthew Dillon IEEE80211_LOCK(vap->iv_ic);
151932176cfdSRui Paulo ieee80211_start_locked(vap);
1520085ff963SMatthew Dillon IEEE80211_UNLOCK(vap->iv_ic);
152132176cfdSRui Paulo }
152232176cfdSRui Paulo
152332176cfdSRui Paulo /*
152432176cfdSRui Paulo * Start all runnable vap's on a device.
152532176cfdSRui Paulo */
152632176cfdSRui Paulo void
ieee80211_start_all(struct ieee80211com * ic)152732176cfdSRui Paulo ieee80211_start_all(struct ieee80211com *ic)
152832176cfdSRui Paulo {
152932176cfdSRui Paulo struct ieee80211vap *vap;
153032176cfdSRui Paulo
1531085ff963SMatthew Dillon IEEE80211_LOCK(ic);
153232176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
153332176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
153432176cfdSRui Paulo if (IFNET_IS_UP_RUNNING(ifp)) /* NB: avoid recursion */
153532176cfdSRui Paulo ieee80211_start_locked(vap);
153632176cfdSRui Paulo }
1537085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
153832176cfdSRui Paulo }
153932176cfdSRui Paulo
154032176cfdSRui Paulo /*
154132176cfdSRui Paulo * Stop a vap. We force it down using the state machine
154232176cfdSRui Paulo * then mark it's ifnet not running. If this is the last
154332176cfdSRui Paulo * vap running on the underlying device then we close it
154432176cfdSRui Paulo * too to insure it will be properly initialized when the
154532176cfdSRui Paulo * next vap is brought up.
154632176cfdSRui Paulo */
154732176cfdSRui Paulo void
ieee80211_stop_locked(struct ieee80211vap * vap)154832176cfdSRui Paulo ieee80211_stop_locked(struct ieee80211vap *vap)
154932176cfdSRui Paulo {
155032176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
155132176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
155232176cfdSRui Paulo
1553085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1554085ff963SMatthew Dillon
155532176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
155632176cfdSRui Paulo "stop running, %d vaps running\n", ic->ic_nrunning);
155732176cfdSRui Paulo
155832176cfdSRui Paulo ieee80211_new_state_locked(vap, IEEE80211_S_INIT, -1);
1559085ff963SMatthew Dillon if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1560085ff963SMatthew Dillon ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* mark us stopped */
15614f655ef5SMatthew Dillon if (--ic->ic_nrunning == 0) {
156232176cfdSRui Paulo IEEE80211_DPRINTF(vap,
156332176cfdSRui Paulo IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
15644f655ef5SMatthew Dillon "down parent %s\n", ic->ic_name);
156532176cfdSRui Paulo ieee80211_runtask(ic, &ic->ic_parent_task);
156632176cfdSRui Paulo }
156732176cfdSRui Paulo }
156832176cfdSRui Paulo }
156932176cfdSRui Paulo
157032176cfdSRui Paulo void
ieee80211_stop(struct ieee80211vap * vap)157132176cfdSRui Paulo ieee80211_stop(struct ieee80211vap *vap)
157232176cfdSRui Paulo {
1573085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic;
1574085ff963SMatthew Dillon
1575085ff963SMatthew Dillon IEEE80211_LOCK(ic);
157632176cfdSRui Paulo ieee80211_stop_locked(vap);
1577085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
157832176cfdSRui Paulo }
157932176cfdSRui Paulo
158032176cfdSRui Paulo /*
158132176cfdSRui Paulo * Stop all vap's running on a device.
158232176cfdSRui Paulo */
158332176cfdSRui Paulo void
ieee80211_stop_all(struct ieee80211com * ic)158432176cfdSRui Paulo ieee80211_stop_all(struct ieee80211com *ic)
158532176cfdSRui Paulo {
158632176cfdSRui Paulo struct ieee80211vap *vap;
158732176cfdSRui Paulo
1588085ff963SMatthew Dillon IEEE80211_LOCK(ic);
158932176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
159032176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
159132176cfdSRui Paulo if (IFNET_IS_UP_RUNNING(ifp)) /* NB: avoid recursion */
159232176cfdSRui Paulo ieee80211_stop_locked(vap);
159332176cfdSRui Paulo }
1594085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
159532176cfdSRui Paulo
159632176cfdSRui Paulo ieee80211_waitfor_parent(ic);
159732176cfdSRui Paulo }
159832176cfdSRui Paulo
159932176cfdSRui Paulo /*
160032176cfdSRui Paulo * Stop all vap's running on a device and arrange
160132176cfdSRui Paulo * for those that were running to be resumed.
160232176cfdSRui Paulo */
160332176cfdSRui Paulo void
ieee80211_suspend_all(struct ieee80211com * ic)160432176cfdSRui Paulo ieee80211_suspend_all(struct ieee80211com *ic)
160532176cfdSRui Paulo {
160632176cfdSRui Paulo struct ieee80211vap *vap;
160732176cfdSRui Paulo
1608085ff963SMatthew Dillon IEEE80211_LOCK(ic);
160932176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
161032176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
161132176cfdSRui Paulo if (IFNET_IS_UP_RUNNING(ifp)) { /* NB: avoid recursion */
161232176cfdSRui Paulo vap->iv_flags_ext |= IEEE80211_FEXT_RESUME;
161332176cfdSRui Paulo ieee80211_stop_locked(vap);
161432176cfdSRui Paulo }
161532176cfdSRui Paulo }
1616085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
161732176cfdSRui Paulo
161832176cfdSRui Paulo ieee80211_waitfor_parent(ic);
161932176cfdSRui Paulo }
162032176cfdSRui Paulo
162132176cfdSRui Paulo /*
162232176cfdSRui Paulo * Start all vap's marked for resume.
162332176cfdSRui Paulo */
162432176cfdSRui Paulo void
ieee80211_resume_all(struct ieee80211com * ic)162532176cfdSRui Paulo ieee80211_resume_all(struct ieee80211com *ic)
162632176cfdSRui Paulo {
162732176cfdSRui Paulo struct ieee80211vap *vap;
162832176cfdSRui Paulo
1629085ff963SMatthew Dillon IEEE80211_LOCK(ic);
163032176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
163132176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp;
163232176cfdSRui Paulo if (!IFNET_IS_UP_RUNNING(ifp) &&
163332176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_RESUME)) {
163432176cfdSRui Paulo vap->iv_flags_ext &= ~IEEE80211_FEXT_RESUME;
163532176cfdSRui Paulo ieee80211_start_locked(vap);
163632176cfdSRui Paulo }
163732176cfdSRui Paulo }
1638085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
163932176cfdSRui Paulo }
164032176cfdSRui Paulo
16414f655ef5SMatthew Dillon /*
16424f655ef5SMatthew Dillon * Restart all vap's running on a device.
16434f655ef5SMatthew Dillon */
16444f655ef5SMatthew Dillon void
ieee80211_restart_all(struct ieee80211com * ic)16454f655ef5SMatthew Dillon ieee80211_restart_all(struct ieee80211com *ic)
16464f655ef5SMatthew Dillon {
16474f655ef5SMatthew Dillon /*
16484f655ef5SMatthew Dillon * NB: do not use ieee80211_runtask here, we will
16494f655ef5SMatthew Dillon * block & drain net80211 taskqueue.
16504f655ef5SMatthew Dillon */
16514f655ef5SMatthew Dillon #if defined(__DragonFly__)
1652*dd3f3f08SImre Vadász taskqueue_enqueue(taskqueue_thread[0], &ic->ic_restart_task);
16534f655ef5SMatthew Dillon #else
16544f655ef5SMatthew Dillon taskqueue_enqueue(taskqueue_thread, &ic->ic_restart_task);
16554f655ef5SMatthew Dillon #endif
16564f655ef5SMatthew Dillon }
16574f655ef5SMatthew Dillon
165832176cfdSRui Paulo void
ieee80211_beacon_miss(struct ieee80211com * ic)1659841ab66cSSepherosa Ziehau ieee80211_beacon_miss(struct ieee80211com *ic)
1660841ab66cSSepherosa Ziehau {
1661085ff963SMatthew Dillon IEEE80211_LOCK(ic);
166232176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
166332176cfdSRui Paulo /* Process in a taskq, the handler may reenter the driver */
166432176cfdSRui Paulo ieee80211_runtask(ic, &ic->ic_bmiss_task);
1665841ab66cSSepherosa Ziehau }
1666085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
1667841ab66cSSepherosa Ziehau }
166832176cfdSRui Paulo
166932176cfdSRui Paulo static void
beacon_miss(void * arg,int npending)1670085ff963SMatthew Dillon beacon_miss(void *arg, int npending)
167132176cfdSRui Paulo {
167232176cfdSRui Paulo struct ieee80211com *ic = arg;
167332176cfdSRui Paulo struct ieee80211vap *vap;
167432176cfdSRui Paulo
1675085ff963SMatthew Dillon IEEE80211_LOCK(ic);
167632176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
167732176cfdSRui Paulo /*
16784f655ef5SMatthew Dillon * We only pass events through for sta vap's in RUN+ state;
167932176cfdSRui Paulo * may be too restrictive but for now this saves all the
168032176cfdSRui Paulo * handlers duplicating these checks.
168132176cfdSRui Paulo */
168232176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA &&
168332176cfdSRui Paulo vap->iv_state >= IEEE80211_S_RUN &&
168432176cfdSRui Paulo vap->iv_bmiss != NULL)
168532176cfdSRui Paulo vap->iv_bmiss(vap);
168632176cfdSRui Paulo }
1687085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
168832176cfdSRui Paulo }
168932176cfdSRui Paulo
169032176cfdSRui Paulo static void
beacon_swmiss(void * arg,int npending)1691085ff963SMatthew Dillon beacon_swmiss(void *arg, int npending)
169232176cfdSRui Paulo {
169332176cfdSRui Paulo struct ieee80211vap *vap = arg;
1694085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic;
169532176cfdSRui Paulo
1696085ff963SMatthew Dillon IEEE80211_LOCK(ic);
16974f655ef5SMatthew Dillon if (vap->iv_state >= IEEE80211_S_RUN) {
169832176cfdSRui Paulo /* XXX Call multiple times if npending > zero? */
169932176cfdSRui Paulo vap->iv_bmiss(vap);
1700841ab66cSSepherosa Ziehau }
1701085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
170247156d48SMatthew Dillon }
1703841ab66cSSepherosa Ziehau
1704841ab66cSSepherosa Ziehau /*
1705841ab66cSSepherosa Ziehau * Software beacon miss handling. Check if any beacons
1706841ab66cSSepherosa Ziehau * were received in the last period. If not post a
1707841ab66cSSepherosa Ziehau * beacon miss; otherwise reset the counter.
1708841ab66cSSepherosa Ziehau */
170932176cfdSRui Paulo void
ieee80211_swbmiss(void * arg)1710085ff963SMatthew Dillon ieee80211_swbmiss(void *arg)
1711841ab66cSSepherosa Ziehau {
171232176cfdSRui Paulo struct ieee80211vap *vap = arg;
171332176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
1714841ab66cSSepherosa Ziehau
1715085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1716085ff963SMatthew Dillon
17174f655ef5SMatthew Dillon KASSERT(vap->iv_state >= IEEE80211_S_RUN,
171832176cfdSRui Paulo ("wrong state %d", vap->iv_state));
1719841ab66cSSepherosa Ziehau
172032176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_SCAN) {
172132176cfdSRui Paulo /*
172232176cfdSRui Paulo * If scanning just ignore and reset state. If we get a
172332176cfdSRui Paulo * bmiss after coming out of scan because we haven't had
172432176cfdSRui Paulo * time to receive a beacon then we should probe the AP
172532176cfdSRui Paulo * before posting a real bmiss (unless iv_bmiss_max has
172632176cfdSRui Paulo * been artifiically lowered). A cleaner solution might
172732176cfdSRui Paulo * be to disable the timer on scan start/end but to handle
172832176cfdSRui Paulo * case of multiple sta vap's we'd need to disable the
172932176cfdSRui Paulo * timers of all affected vap's.
173032176cfdSRui Paulo */
173132176cfdSRui Paulo vap->iv_swbmiss_count = 0;
173232176cfdSRui Paulo } else if (vap->iv_swbmiss_count == 0) {
173332176cfdSRui Paulo if (vap->iv_bmiss != NULL)
173432176cfdSRui Paulo ieee80211_runtask(ic, &vap->iv_swbmiss_task);
1735085ff963SMatthew Dillon } else
173632176cfdSRui Paulo vap->iv_swbmiss_count = 0;
173732176cfdSRui Paulo callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
1738085ff963SMatthew Dillon ieee80211_swbmiss, vap);
173932176cfdSRui Paulo }
1740841ab66cSSepherosa Ziehau
174132176cfdSRui Paulo /*
174232176cfdSRui Paulo * Start an 802.11h channel switch. We record the parameters,
174332176cfdSRui Paulo * mark the operation pending, notify each vap through the
174432176cfdSRui Paulo * beacon update mechanism so it can update the beacon frame
174532176cfdSRui Paulo * contents, and then switch vap's to CSA state to block outbound
174632176cfdSRui Paulo * traffic. Devices that handle CSA directly can use the state
174732176cfdSRui Paulo * switch to do the right thing so long as they call
174832176cfdSRui Paulo * ieee80211_csa_completeswitch when it's time to complete the
174932176cfdSRui Paulo * channel change. Devices that depend on the net80211 layer can
175032176cfdSRui Paulo * use ieee80211_beacon_update to handle the countdown and the
175132176cfdSRui Paulo * channel switch.
175232176cfdSRui Paulo */
175332176cfdSRui Paulo void
ieee80211_csa_startswitch(struct ieee80211com * ic,struct ieee80211_channel * c,int mode,int count)175432176cfdSRui Paulo ieee80211_csa_startswitch(struct ieee80211com *ic,
175532176cfdSRui Paulo struct ieee80211_channel *c, int mode, int count)
175632176cfdSRui Paulo {
175732176cfdSRui Paulo struct ieee80211vap *vap;
175832176cfdSRui Paulo
1759085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1760085ff963SMatthew Dillon
176132176cfdSRui Paulo ic->ic_csa_newchan = c;
176232176cfdSRui Paulo ic->ic_csa_mode = mode;
176332176cfdSRui Paulo ic->ic_csa_count = count;
176432176cfdSRui Paulo ic->ic_flags |= IEEE80211_F_CSAPENDING;
176532176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
176632176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
176732176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_IBSS ||
176832176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_MBSS)
176932176cfdSRui Paulo ieee80211_beacon_notify(vap, IEEE80211_BEACON_CSA);
177032176cfdSRui Paulo /* switch to CSA state to block outbound traffic */
177132176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_RUN)
177232176cfdSRui Paulo ieee80211_new_state_locked(vap, IEEE80211_S_CSA, 0);
177332176cfdSRui Paulo }
177432176cfdSRui Paulo ieee80211_notify_csa(ic, c, mode, count);
1775841ab66cSSepherosa Ziehau }
1776841ab66cSSepherosa Ziehau
1777085ff963SMatthew Dillon /*
1778085ff963SMatthew Dillon * Complete the channel switch by transitioning all CSA VAPs to RUN.
1779085ff963SMatthew Dillon * This is called by both the completion and cancellation functions
1780085ff963SMatthew Dillon * so each VAP is placed back in the RUN state and can thus transmit.
1781085ff963SMatthew Dillon */
1782841ab66cSSepherosa Ziehau static void
csa_completeswitch(struct ieee80211com * ic)178332176cfdSRui Paulo csa_completeswitch(struct ieee80211com *ic)
1784841ab66cSSepherosa Ziehau {
178532176cfdSRui Paulo struct ieee80211vap *vap;
1786841ab66cSSepherosa Ziehau
178732176cfdSRui Paulo ic->ic_csa_newchan = NULL;
178832176cfdSRui Paulo ic->ic_flags &= ~IEEE80211_F_CSAPENDING;
178932176cfdSRui Paulo
179032176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
179132176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CSA)
179232176cfdSRui Paulo ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0);
1793846cf0bcSSepherosa Ziehau }
1794846cf0bcSSepherosa Ziehau
179532176cfdSRui Paulo /*
179632176cfdSRui Paulo * Complete an 802.11h channel switch started by ieee80211_csa_startswitch.
179732176cfdSRui Paulo * We clear state and move all vap's in CSA state to RUN state
179832176cfdSRui Paulo * so they can again transmit.
1799085ff963SMatthew Dillon *
1800085ff963SMatthew Dillon * Although this may not be completely correct, update the BSS channel
1801085ff963SMatthew Dillon * for each VAP to the newly configured channel. The setcurchan sets
1802085ff963SMatthew Dillon * the current operating channel for the interface (so the radio does
1803085ff963SMatthew Dillon * switch over) but the VAP BSS isn't updated, leading to incorrectly
1804085ff963SMatthew Dillon * reported information via ioctl.
180532176cfdSRui Paulo */
1806846cf0bcSSepherosa Ziehau void
ieee80211_csa_completeswitch(struct ieee80211com * ic)180732176cfdSRui Paulo ieee80211_csa_completeswitch(struct ieee80211com *ic)
1808846cf0bcSSepherosa Ziehau {
1809085ff963SMatthew Dillon struct ieee80211vap *vap;
1810085ff963SMatthew Dillon
1811085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1812085ff963SMatthew Dillon
181332176cfdSRui Paulo KASSERT(ic->ic_flags & IEEE80211_F_CSAPENDING, ("csa not pending"));
1814846cf0bcSSepherosa Ziehau
181532176cfdSRui Paulo ieee80211_setcurchan(ic, ic->ic_csa_newchan);
1816085ff963SMatthew Dillon TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
1817085ff963SMatthew Dillon if (vap->iv_state == IEEE80211_S_CSA)
1818085ff963SMatthew Dillon vap->iv_bss->ni_chan = ic->ic_curchan;
1819085ff963SMatthew Dillon
182032176cfdSRui Paulo csa_completeswitch(ic);
182132176cfdSRui Paulo }
1822846cf0bcSSepherosa Ziehau
1823846cf0bcSSepherosa Ziehau /*
182432176cfdSRui Paulo * Cancel an 802.11h channel switch started by ieee80211_csa_startswitch.
182532176cfdSRui Paulo * We clear state and move all vap's in CSA state to RUN state
182632176cfdSRui Paulo * so they can again transmit.
1827846cf0bcSSepherosa Ziehau */
182832176cfdSRui Paulo void
ieee80211_csa_cancelswitch(struct ieee80211com * ic)182932176cfdSRui Paulo ieee80211_csa_cancelswitch(struct ieee80211com *ic)
183032176cfdSRui Paulo {
1831085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1832085ff963SMatthew Dillon
183332176cfdSRui Paulo csa_completeswitch(ic);
1834846cf0bcSSepherosa Ziehau }
183532176cfdSRui Paulo
1836846cf0bcSSepherosa Ziehau /*
183732176cfdSRui Paulo * Complete a DFS CAC started by ieee80211_dfs_cac_start.
183832176cfdSRui Paulo * We clear state and move all vap's in CAC state to RUN state.
1839846cf0bcSSepherosa Ziehau */
184032176cfdSRui Paulo void
ieee80211_cac_completeswitch(struct ieee80211vap * vap0)184132176cfdSRui Paulo ieee80211_cac_completeswitch(struct ieee80211vap *vap0)
184232176cfdSRui Paulo {
184332176cfdSRui Paulo struct ieee80211com *ic = vap0->iv_ic;
184432176cfdSRui Paulo struct ieee80211vap *vap;
184532176cfdSRui Paulo
1846085ff963SMatthew Dillon IEEE80211_LOCK(ic);
184732176cfdSRui Paulo /*
184832176cfdSRui Paulo * Complete CAC state change for lead vap first; then
184932176cfdSRui Paulo * clock all the other vap's waiting.
185032176cfdSRui Paulo */
185132176cfdSRui Paulo KASSERT(vap0->iv_state == IEEE80211_S_CAC,
185232176cfdSRui Paulo ("wrong state %d", vap0->iv_state));
185332176cfdSRui Paulo ieee80211_new_state_locked(vap0, IEEE80211_S_RUN, 0);
185432176cfdSRui Paulo
185532176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
185632176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC)
185732176cfdSRui Paulo ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0);
1858085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
1859846cf0bcSSepherosa Ziehau }
1860846cf0bcSSepherosa Ziehau
186132176cfdSRui Paulo /*
186232176cfdSRui Paulo * Force all vap's other than the specified vap to the INIT state
186332176cfdSRui Paulo * and mark them as waiting for a scan to complete. These vaps
186432176cfdSRui Paulo * will be brought up when the scan completes and the scanning vap
186532176cfdSRui Paulo * reaches RUN state by wakeupwaiting.
186632176cfdSRui Paulo */
186732176cfdSRui Paulo static void
markwaiting(struct ieee80211vap * vap0)186832176cfdSRui Paulo markwaiting(struct ieee80211vap *vap0)
186932176cfdSRui Paulo {
187032176cfdSRui Paulo struct ieee80211com *ic = vap0->iv_ic;
187132176cfdSRui Paulo struct ieee80211vap *vap;
187232176cfdSRui Paulo
1873085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1874085ff963SMatthew Dillon
187532176cfdSRui Paulo /*
187632176cfdSRui Paulo * A vap list entry can not disappear since we are running on the
187732176cfdSRui Paulo * taskqueue and a vap destroy will queue and drain another state
187832176cfdSRui Paulo * change task.
187932176cfdSRui Paulo */
188032176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
188132176cfdSRui Paulo if (vap == vap0)
188232176cfdSRui Paulo continue;
188332176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_INIT) {
188432176cfdSRui Paulo /* NB: iv_newstate may drop the lock */
188532176cfdSRui Paulo vap->iv_newstate(vap, IEEE80211_S_INIT, 0);
1886085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
188732176cfdSRui Paulo vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT;
188832176cfdSRui Paulo }
188932176cfdSRui Paulo }
1890841ab66cSSepherosa Ziehau }
1891841ab66cSSepherosa Ziehau
189232176cfdSRui Paulo /*
189332176cfdSRui Paulo * Wakeup all vap's waiting for a scan to complete. This is the
189432176cfdSRui Paulo * companion to markwaiting (above) and is used to coordinate
189532176cfdSRui Paulo * multiple vaps scanning.
189632176cfdSRui Paulo * This is called from the state taskqueue.
189732176cfdSRui Paulo */
189832176cfdSRui Paulo static void
wakeupwaiting(struct ieee80211vap * vap0)189932176cfdSRui Paulo wakeupwaiting(struct ieee80211vap *vap0)
190032176cfdSRui Paulo {
190132176cfdSRui Paulo struct ieee80211com *ic = vap0->iv_ic;
190232176cfdSRui Paulo struct ieee80211vap *vap;
190332176cfdSRui Paulo
1904085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
1905085ff963SMatthew Dillon
190632176cfdSRui Paulo /*
190732176cfdSRui Paulo * A vap list entry can not disappear since we are running on the
190832176cfdSRui Paulo * taskqueue and a vap destroy will queue and drain another state
190932176cfdSRui Paulo * change task.
191032176cfdSRui Paulo */
191132176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
191232176cfdSRui Paulo if (vap == vap0)
191332176cfdSRui Paulo continue;
191432176cfdSRui Paulo if (vap->iv_flags_ext & IEEE80211_FEXT_SCANWAIT) {
191532176cfdSRui Paulo vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANWAIT;
191632176cfdSRui Paulo /* NB: sta's cannot go INIT->RUN */
191732176cfdSRui Paulo /* NB: iv_newstate may drop the lock */
191832176cfdSRui Paulo vap->iv_newstate(vap,
191932176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_STA ?
192032176cfdSRui Paulo IEEE80211_S_SCAN : IEEE80211_S_RUN, 0);
1921085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
192232176cfdSRui Paulo }
192332176cfdSRui Paulo }
192432176cfdSRui Paulo }
192532176cfdSRui Paulo
192632176cfdSRui Paulo /*
192732176cfdSRui Paulo * Handle post state change work common to all operating modes.
192832176cfdSRui Paulo */
192932176cfdSRui Paulo static void
ieee80211_newstate_cb(void * xvap,int npending)1930085ff963SMatthew Dillon ieee80211_newstate_cb(void *xvap, int npending)
193132176cfdSRui Paulo {
193232176cfdSRui Paulo struct ieee80211vap *vap = xvap;
1933085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic;
193432176cfdSRui Paulo enum ieee80211_state nstate, ostate;
193532176cfdSRui Paulo int arg, rc;
193632176cfdSRui Paulo
1937085ff963SMatthew Dillon IEEE80211_LOCK(ic);
193832176cfdSRui Paulo nstate = vap->iv_nstate;
193932176cfdSRui Paulo arg = vap->iv_nstate_arg;
194032176cfdSRui Paulo
194132176cfdSRui Paulo if (vap->iv_flags_ext & IEEE80211_FEXT_REINIT) {
194232176cfdSRui Paulo /*
194332176cfdSRui Paulo * We have been requested to drop back to the INIT before
194432176cfdSRui Paulo * proceeding to the new state.
194532176cfdSRui Paulo */
19464f655ef5SMatthew Dillon /* Deny any state changes while we are here. */
19474f655ef5SMatthew Dillon vap->iv_nstate = IEEE80211_S_INIT;
194832176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
194932176cfdSRui Paulo "%s: %s -> %s arg %d\n", __func__,
195032176cfdSRui Paulo ieee80211_state_name[vap->iv_state],
19514f655ef5SMatthew Dillon ieee80211_state_name[vap->iv_nstate], arg);
19524f655ef5SMatthew Dillon vap->iv_newstate(vap, vap->iv_nstate, 0);
1953085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
19544f655ef5SMatthew Dillon vap->iv_flags_ext &= ~(IEEE80211_FEXT_REINIT |
19554f655ef5SMatthew Dillon IEEE80211_FEXT_STATEWAIT);
19564f655ef5SMatthew Dillon /* enqueue new state transition after cancel_scan() task */
19574f655ef5SMatthew Dillon ieee80211_new_state_locked(vap, nstate, arg);
19584f655ef5SMatthew Dillon goto done;
195932176cfdSRui Paulo }
196032176cfdSRui Paulo
196132176cfdSRui Paulo ostate = vap->iv_state;
196232176cfdSRui Paulo if (nstate == IEEE80211_S_SCAN && ostate != IEEE80211_S_INIT) {
196332176cfdSRui Paulo /*
196432176cfdSRui Paulo * SCAN was forced; e.g. on beacon miss. Force other running
196532176cfdSRui Paulo * vap's to INIT state and mark them as waiting for the scan to
196632176cfdSRui Paulo * complete. This insures they don't interfere with our
196732176cfdSRui Paulo * scanning. Since we are single threaded the vaps can not
196832176cfdSRui Paulo * transition again while we are executing.
196932176cfdSRui Paulo *
197032176cfdSRui Paulo * XXX not always right, assumes ap follows sta
197132176cfdSRui Paulo */
197232176cfdSRui Paulo markwaiting(vap);
197332176cfdSRui Paulo }
197432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
197532176cfdSRui Paulo "%s: %s -> %s arg %d\n", __func__,
197632176cfdSRui Paulo ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg);
197732176cfdSRui Paulo
197832176cfdSRui Paulo rc = vap->iv_newstate(vap, nstate, arg);
1979085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
198032176cfdSRui Paulo vap->iv_flags_ext &= ~IEEE80211_FEXT_STATEWAIT;
198132176cfdSRui Paulo if (rc != 0) {
198232176cfdSRui Paulo /* State transition failed */
198332176cfdSRui Paulo KASSERT(rc != EINPROGRESS, ("iv_newstate was deferred"));
198432176cfdSRui Paulo KASSERT(nstate != IEEE80211_S_INIT,
198532176cfdSRui Paulo ("INIT state change failed"));
198632176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
198732176cfdSRui Paulo "%s: %s returned error %d\n", __func__,
198832176cfdSRui Paulo ieee80211_state_name[nstate], rc);
198932176cfdSRui Paulo goto done;
199032176cfdSRui Paulo }
199132176cfdSRui Paulo
199232176cfdSRui Paulo /* No actual transition, skip post processing */
199332176cfdSRui Paulo if (ostate == nstate)
199432176cfdSRui Paulo goto done;
199532176cfdSRui Paulo
199632176cfdSRui Paulo if (nstate == IEEE80211_S_RUN) {
199732176cfdSRui Paulo /*
199832176cfdSRui Paulo * OACTIVE may be set on the vap if the upper layer
199932176cfdSRui Paulo * tried to transmit (e.g. IPv6 NDP) before we reach
200032176cfdSRui Paulo * RUN state. Clear it and restart xmit.
200132176cfdSRui Paulo *
200232176cfdSRui Paulo * Note this can also happen as a result of SLEEP->RUN
200332176cfdSRui Paulo * (i.e. coming out of power save mode).
200432176cfdSRui Paulo */
2005085ff963SMatthew Dillon #if defined(__DragonFly__)
2006085ff963SMatthew Dillon struct ifaltq_subque *ifsq;
2007085ff963SMatthew Dillon int wst;
2008085ff963SMatthew Dillon
2009085ff963SMatthew Dillon ifsq = ifq_get_subq_default(&vap->iv_ifp->if_snd);
2010f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifsq);
2011085ff963SMatthew Dillon wst = wlan_serialize_push();
2012f0a26983SSepherosa Ziehau vap->iv_ifp->if_start(vap->iv_ifp, ifsq);
2013085ff963SMatthew Dillon wlan_serialize_pop(wst);
2014085ff963SMatthew Dillon #else
2015085ff963SMatthew Dillon vap->iv_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2016085ff963SMatthew Dillon #endif
2017085ff963SMatthew Dillon
2018085ff963SMatthew Dillon /*
2019085ff963SMatthew Dillon * XXX TODO Kick-start a VAP queue - this should be a method!
2020085ff963SMatthew Dillon */
202132176cfdSRui Paulo
202232176cfdSRui Paulo /* bring up any vaps waiting on us */
202332176cfdSRui Paulo wakeupwaiting(vap);
202432176cfdSRui Paulo } else if (nstate == IEEE80211_S_INIT) {
202532176cfdSRui Paulo /*
202632176cfdSRui Paulo * Flush the scan cache if we did the last scan (XXX?)
202732176cfdSRui Paulo * and flush any frames on send queues from this vap.
202832176cfdSRui Paulo * Note the mgt q is used only for legacy drivers and
202932176cfdSRui Paulo * will go away shortly.
203032176cfdSRui Paulo */
203132176cfdSRui Paulo ieee80211_scan_flush(vap);
203232176cfdSRui Paulo
2033085ff963SMatthew Dillon /*
2034085ff963SMatthew Dillon * XXX TODO: ic/vap queue flush
2035085ff963SMatthew Dillon */
203632176cfdSRui Paulo }
203732176cfdSRui Paulo done:
2038085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
203932176cfdSRui Paulo }
204032176cfdSRui Paulo
204132176cfdSRui Paulo /*
204232176cfdSRui Paulo * Public interface for initiating a state machine change.
204332176cfdSRui Paulo * This routine single-threads the request and coordinates
204432176cfdSRui Paulo * the scheduling of multiple vaps for the purpose of selecting
204532176cfdSRui Paulo * an operating channel. Specifically the following scenarios
204632176cfdSRui Paulo * are handled:
204732176cfdSRui Paulo * o only one vap can be selecting a channel so on transition to
204832176cfdSRui Paulo * SCAN state if another vap is already scanning then
204932176cfdSRui Paulo * mark the caller for later processing and return without
205032176cfdSRui Paulo * doing anything (XXX? expectations by caller of synchronous operation)
205132176cfdSRui Paulo * o only one vap can be doing CAC of a channel so on transition to
205232176cfdSRui Paulo * CAC state if another vap is already scanning for radar then
205332176cfdSRui Paulo * mark the caller for later processing and return without
205432176cfdSRui Paulo * doing anything (XXX? expectations by caller of synchronous operation)
205532176cfdSRui Paulo * o if another vap is already running when a request is made
205632176cfdSRui Paulo * to SCAN then an operating channel has been chosen; bypass
205732176cfdSRui Paulo * the scan and just join the channel
205832176cfdSRui Paulo *
205932176cfdSRui Paulo * Note that the state change call is done through the iv_newstate
206032176cfdSRui Paulo * method pointer so any driver routine gets invoked. The driver
206132176cfdSRui Paulo * will normally call back into operating mode-specific
206232176cfdSRui Paulo * ieee80211_newstate routines (below) unless it needs to completely
206332176cfdSRui Paulo * bypass the state machine (e.g. because the firmware has it's
206432176cfdSRui Paulo * own idea how things should work). Bypassing the net80211 layer
206532176cfdSRui Paulo * is usually a mistake and indicates lack of proper integration
206632176cfdSRui Paulo * with the net80211 layer.
206732176cfdSRui Paulo */
2068d98a0bcfSMatthew Dillon int
ieee80211_new_state_locked(struct ieee80211vap * vap,enum ieee80211_state nstate,int arg)206932176cfdSRui Paulo ieee80211_new_state_locked(struct ieee80211vap *vap,
207032176cfdSRui Paulo enum ieee80211_state nstate, int arg)
2071841ab66cSSepherosa Ziehau {
207232176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
207332176cfdSRui Paulo struct ieee80211vap *vp;
2074f186073cSJoerg Sonnenberger enum ieee80211_state ostate;
207532176cfdSRui Paulo int nrunning, nscanning;
2076f186073cSJoerg Sonnenberger
2077085ff963SMatthew Dillon IEEE80211_LOCK_ASSERT(ic);
2078085ff963SMatthew Dillon
207932176cfdSRui Paulo if (vap->iv_flags_ext & IEEE80211_FEXT_STATEWAIT) {
20804f655ef5SMatthew Dillon if (vap->iv_nstate == IEEE80211_S_INIT ||
20814f655ef5SMatthew Dillon ((vap->iv_state == IEEE80211_S_INIT ||
20824f655ef5SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_REINIT)) &&
20834f655ef5SMatthew Dillon vap->iv_nstate == IEEE80211_S_SCAN &&
20844f655ef5SMatthew Dillon nstate > IEEE80211_S_SCAN)) {
208532176cfdSRui Paulo /*
20864f655ef5SMatthew Dillon * XXX The vap is being stopped/started,
20874f655ef5SMatthew Dillon * do not allow any other state changes
20884f655ef5SMatthew Dillon * until this is completed.
208932176cfdSRui Paulo */
20904f655ef5SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
20914f655ef5SMatthew Dillon "%s: %s -> %s (%s) transition discarded\n",
20924f655ef5SMatthew Dillon __func__,
20934f655ef5SMatthew Dillon ieee80211_state_name[vap->iv_state],
20944f655ef5SMatthew Dillon ieee80211_state_name[nstate],
20954f655ef5SMatthew Dillon ieee80211_state_name[vap->iv_nstate]);
209632176cfdSRui Paulo return -1;
209732176cfdSRui Paulo } else if (vap->iv_state != vap->iv_nstate) {
209832176cfdSRui Paulo #if 0
209932176cfdSRui Paulo /* Warn if the previous state hasn't completed. */
210032176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
210132176cfdSRui Paulo "%s: pending %s -> %s transition lost\n", __func__,
210232176cfdSRui Paulo ieee80211_state_name[vap->iv_state],
210332176cfdSRui Paulo ieee80211_state_name[vap->iv_nstate]);
210432176cfdSRui Paulo #else
210532176cfdSRui Paulo /* XXX temporarily enable to identify issues */
210632176cfdSRui Paulo if_printf(vap->iv_ifp,
210732176cfdSRui Paulo "%s: pending %s -> %s transition lost\n",
210832176cfdSRui Paulo __func__, ieee80211_state_name[vap->iv_state],
210932176cfdSRui Paulo ieee80211_state_name[vap->iv_nstate]);
211032176cfdSRui Paulo #endif
211132176cfdSRui Paulo }
211232176cfdSRui Paulo }
211332176cfdSRui Paulo
211432176cfdSRui Paulo nrunning = nscanning = 0;
211532176cfdSRui Paulo /* XXX can track this state instead of calculating */
211632176cfdSRui Paulo TAILQ_FOREACH(vp, &ic->ic_vaps, iv_next) {
211732176cfdSRui Paulo if (vp != vap) {
211832176cfdSRui Paulo if (vp->iv_state >= IEEE80211_S_RUN)
211932176cfdSRui Paulo nrunning++;
212032176cfdSRui Paulo /* XXX doesn't handle bg scan */
212132176cfdSRui Paulo /* NB: CAC+AUTH+ASSOC treated like SCAN */
212232176cfdSRui Paulo else if (vp->iv_state > IEEE80211_S_INIT)
212332176cfdSRui Paulo nscanning++;
212432176cfdSRui Paulo }
212532176cfdSRui Paulo }
212632176cfdSRui Paulo ostate = vap->iv_state;
212732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
212832176cfdSRui Paulo "%s: %s -> %s (nrunning %d nscanning %d)\n", __func__,
212932176cfdSRui Paulo ieee80211_state_name[ostate], ieee80211_state_name[nstate],
213032176cfdSRui Paulo nrunning, nscanning);
2131f186073cSJoerg Sonnenberger switch (nstate) {
2132f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN:
213332176cfdSRui Paulo if (ostate == IEEE80211_S_INIT) {
2134f186073cSJoerg Sonnenberger /*
213532176cfdSRui Paulo * INIT -> SCAN happens on initial bringup.
2136f186073cSJoerg Sonnenberger */
213732176cfdSRui Paulo KASSERT(!(nscanning && nrunning),
213832176cfdSRui Paulo ("%d scanning and %d running", nscanning, nrunning));
213932176cfdSRui Paulo if (nscanning) {
2140841ab66cSSepherosa Ziehau /*
214132176cfdSRui Paulo * Someone is scanning, defer our state
214232176cfdSRui Paulo * change until the work has completed.
2143841ab66cSSepherosa Ziehau */
214432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
214532176cfdSRui Paulo "%s: defer %s -> %s\n",
214632176cfdSRui Paulo __func__, ieee80211_state_name[ostate],
214732176cfdSRui Paulo ieee80211_state_name[nstate]);
214832176cfdSRui Paulo vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT;
214932176cfdSRui Paulo return 0;
2150f186073cSJoerg Sonnenberger }
215132176cfdSRui Paulo if (nrunning) {
215232176cfdSRui Paulo /*
215332176cfdSRui Paulo * Someone is operating; just join the channel
215432176cfdSRui Paulo * they have chosen.
215532176cfdSRui Paulo */
215632176cfdSRui Paulo /* XXX kill arg? */
215732176cfdSRui Paulo /* XXX check each opmode, adhoc? */
215832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA)
215932176cfdSRui Paulo nstate = IEEE80211_S_SCAN;
2160f186073cSJoerg Sonnenberger else
216132176cfdSRui Paulo nstate = IEEE80211_S_RUN;
216232176cfdSRui Paulo #ifdef IEEE80211_DEBUG
216332176cfdSRui Paulo if (nstate != IEEE80211_S_SCAN) {
216432176cfdSRui Paulo IEEE80211_DPRINTF(vap,
216532176cfdSRui Paulo IEEE80211_MSG_STATE,
216632176cfdSRui Paulo "%s: override, now %s -> %s\n",
216732176cfdSRui Paulo __func__,
216832176cfdSRui Paulo ieee80211_state_name[ostate],
216932176cfdSRui Paulo ieee80211_state_name[nstate]);
2170f186073cSJoerg Sonnenberger }
2171841ab66cSSepherosa Ziehau #endif
217232176cfdSRui Paulo }
217332176cfdSRui Paulo }
2174f186073cSJoerg Sonnenberger break;
217532176cfdSRui Paulo case IEEE80211_S_RUN:
217632176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_WDS &&
217732176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) &&
217832176cfdSRui Paulo nscanning) {
2179841ab66cSSepherosa Ziehau /*
218032176cfdSRui Paulo * Legacy WDS with someone else scanning; don't
218132176cfdSRui Paulo * go online until that completes as we should
218232176cfdSRui Paulo * follow the other vap to the channel they choose.
2183841ab66cSSepherosa Ziehau */
218432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
218532176cfdSRui Paulo "%s: defer %s -> %s (legacy WDS)\n", __func__,
218632176cfdSRui Paulo ieee80211_state_name[ostate],
218732176cfdSRui Paulo ieee80211_state_name[nstate]);
218832176cfdSRui Paulo vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT;
2189f186073cSJoerg Sonnenberger return 0;
2190f186073cSJoerg Sonnenberger }
219132176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
219232176cfdSRui Paulo IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
219332176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_DFS) &&
219432176cfdSRui Paulo !IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) {
219532176cfdSRui Paulo /*
219632176cfdSRui Paulo * This is a DFS channel, transition to CAC state
219732176cfdSRui Paulo * instead of RUN. This allows us to initiate
219832176cfdSRui Paulo * Channel Availability Check (CAC) as specified
219932176cfdSRui Paulo * by 11h/DFS.
220032176cfdSRui Paulo */
220132176cfdSRui Paulo nstate = IEEE80211_S_CAC;
220232176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
220332176cfdSRui Paulo "%s: override %s -> %s (DFS)\n", __func__,
220432176cfdSRui Paulo ieee80211_state_name[ostate],
220532176cfdSRui Paulo ieee80211_state_name[nstate]);
220632176cfdSRui Paulo }
220732176cfdSRui Paulo break;
220832176cfdSRui Paulo case IEEE80211_S_INIT:
220932176cfdSRui Paulo /* cancel any scan in progress */
221032176cfdSRui Paulo ieee80211_cancel_scan(vap);
221132176cfdSRui Paulo if (ostate == IEEE80211_S_INIT ) {
221232176cfdSRui Paulo /* XXX don't believe this */
221332176cfdSRui Paulo /* INIT -> INIT. nothing to do */
221432176cfdSRui Paulo vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANWAIT;
221532176cfdSRui Paulo }
221632176cfdSRui Paulo /* fall thru... */
221732176cfdSRui Paulo default:
221832176cfdSRui Paulo break;
221932176cfdSRui Paulo }
222032176cfdSRui Paulo /* defer the state change to a thread */
222132176cfdSRui Paulo vap->iv_nstate = nstate;
222232176cfdSRui Paulo vap->iv_nstate_arg = arg;
222332176cfdSRui Paulo vap->iv_flags_ext |= IEEE80211_FEXT_STATEWAIT;
222432176cfdSRui Paulo ieee80211_runtask(ic, &vap->iv_nstate_task);
222532176cfdSRui Paulo return EINPROGRESS;
222632176cfdSRui Paulo }
222732176cfdSRui Paulo
222832176cfdSRui Paulo int
ieee80211_new_state(struct ieee80211vap * vap,enum ieee80211_state nstate,int arg)222932176cfdSRui Paulo ieee80211_new_state(struct ieee80211vap *vap,
223032176cfdSRui Paulo enum ieee80211_state nstate, int arg)
223132176cfdSRui Paulo {
2232085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic;
223332176cfdSRui Paulo int rc;
223432176cfdSRui Paulo
2235085ff963SMatthew Dillon IEEE80211_LOCK(ic);
223632176cfdSRui Paulo rc = ieee80211_new_state_locked(vap, nstate, arg);
2237085ff963SMatthew Dillon IEEE80211_UNLOCK(ic);
223832176cfdSRui Paulo return rc;
223932176cfdSRui Paulo }
2240