ieee80211_proto.c revision 1.29.4.1 1 1.29 degroote /* $NetBSD: ieee80211_proto.c,v 1.29.4.1 2008/02/22 16:50:25 skrll Exp $ */
2 1.1 dyoung /*-
3 1.1 dyoung * Copyright (c) 2001 Atsushi Onoe
4 1.29.4.1 skrll * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
5 1.1 dyoung * All rights reserved.
6 1.1 dyoung *
7 1.1 dyoung * Redistribution and use in source and binary forms, with or without
8 1.1 dyoung * modification, are permitted provided that the following conditions
9 1.1 dyoung * are met:
10 1.1 dyoung * 1. Redistributions of source code must retain the above copyright
11 1.1 dyoung * notice, this list of conditions and the following disclaimer.
12 1.1 dyoung * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 dyoung * notice, this list of conditions and the following disclaimer in the
14 1.1 dyoung * documentation and/or other materials provided with the distribution.
15 1.1 dyoung *
16 1.1 dyoung * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 dyoung * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 dyoung * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 dyoung * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 dyoung * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.1 dyoung * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.1 dyoung * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.1 dyoung * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.1 dyoung * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.1 dyoung * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.1 dyoung */
27 1.1 dyoung
28 1.1 dyoung #include <sys/cdefs.h>
29 1.3 dyoung #ifdef __FreeBSD__
30 1.29.4.1 skrll __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.45 2007/11/23 05:55:06 sam Exp $");
31 1.19 dyoung #endif
32 1.19 dyoung #ifdef __NetBSD__
33 1.29 degroote __KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.29.4.1 2008/02/22 16:50:25 skrll Exp $");
34 1.3 dyoung #endif
35 1.1 dyoung
36 1.1 dyoung /*
37 1.1 dyoung * IEEE 802.11 protocol support.
38 1.1 dyoung */
39 1.1 dyoung
40 1.1 dyoung #include "opt_inet.h"
41 1.1 dyoung
42 1.1 dyoung #include <sys/param.h>
43 1.1 dyoung #include <sys/kernel.h>
44 1.29.4.1 skrll #include <sys/systm.h>
45 1.29.4.1 skrll
46 1.1 dyoung #include <sys/socket.h>
47 1.1 dyoung #include <sys/sockio.h>
48 1.1 dyoung #include <sys/endian.h>
49 1.1 dyoung #include <sys/errno.h>
50 1.1 dyoung #include <sys/proc.h>
51 1.1 dyoung #include <sys/sysctl.h>
52 1.1 dyoung
53 1.1 dyoung #include <net/if.h>
54 1.1 dyoung #include <net/if_media.h>
55 1.1 dyoung #include <net/if_arp.h>
56 1.4 dyoung #include <net/if_ether.h>
57 1.1 dyoung #include <net/if_llc.h>
58 1.1 dyoung
59 1.19 dyoung #include <net80211/ieee80211_netbsd.h>
60 1.1 dyoung #include <net80211/ieee80211_var.h>
61 1.1 dyoung
62 1.1 dyoung #include <net/bpf.h>
63 1.1 dyoung
64 1.1 dyoung #ifdef INET
65 1.19 dyoung #include <netinet/in.h>
66 1.4 dyoung #include <net/if_ether.h>
67 1.4 dyoung #endif
68 1.1 dyoung
69 1.9 dyoung #include <net/route.h>
70 1.19 dyoung /* XXX tunables */
71 1.19 dyoung #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */
72 1.19 dyoung #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */
73 1.9 dyoung
74 1.1 dyoung #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
75 1.1 dyoung
76 1.1 dyoung const char *ieee80211_mgt_subtype_name[] = {
77 1.1 dyoung "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
78 1.1 dyoung "probe_req", "probe_resp", "reserved#6", "reserved#7",
79 1.1 dyoung "beacon", "atim", "disassoc", "auth",
80 1.29.4.1 skrll "deauth", "action", "reserved#14", "reserved#15"
81 1.1 dyoung };
82 1.19 dyoung const char *ieee80211_ctl_subtype_name[] = {
83 1.19 dyoung "reserved#0", "reserved#1", "reserved#2", "reserved#3",
84 1.19 dyoung "reserved#3", "reserved#5", "reserved#6", "reserved#7",
85 1.19 dyoung "reserved#8", "reserved#9", "ps_poll", "rts",
86 1.19 dyoung "cts", "ack", "cf_end", "cf_end_ack"
87 1.19 dyoung };
88 1.29.4.1 skrll const char *ieee80211_opmode_name[IEEE80211_OPMODE_MAX] = {
89 1.29.4.1 skrll "IBSS", /* IEEE80211_M_IBSS */
90 1.29.4.1 skrll "STA", /* IEEE80211_M_STA */
91 1.29.4.1 skrll "#2",
92 1.29.4.1 skrll "AHDEMO", /* IEEE80211_M_AHDEMO */
93 1.29.4.1 skrll "#4", "#5",
94 1.29.4.1 skrll "HOSTAP", /* IEEE80211_M_HOSTAP */
95 1.29.4.1 skrll "#7",
96 1.29.4.1 skrll "MONITOR" /* IEEE80211_M_MONITOR */
97 1.29.4.1 skrll };
98 1.1 dyoung const char *ieee80211_state_name[IEEE80211_S_MAX] = {
99 1.1 dyoung "INIT", /* IEEE80211_S_INIT */
100 1.1 dyoung "SCAN", /* IEEE80211_S_SCAN */
101 1.1 dyoung "AUTH", /* IEEE80211_S_AUTH */
102 1.1 dyoung "ASSOC", /* IEEE80211_S_ASSOC */
103 1.29.4.1 skrll "CAC", /* IEEE80211_S_CAC */
104 1.29.4.1 skrll "RUN", /* IEEE80211_S_RUN */
105 1.29.4.1 skrll "CSA", /* IEEE80211_S_CSA */
106 1.29.4.1 skrll "SLEEP", /* IEEE80211_S_SLEEP */
107 1.1 dyoung };
108 1.19 dyoung const char *ieee80211_wme_acnames[] = {
109 1.19 dyoung "WME_AC_BE",
110 1.19 dyoung "WME_AC_BK",
111 1.19 dyoung "WME_AC_VI",
112 1.19 dyoung "WME_AC_VO",
113 1.19 dyoung "WME_UPSD",
114 1.19 dyoung };
115 1.1 dyoung
116 1.1 dyoung static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int);
117 1.1 dyoung
118 1.29.4.1 skrll static void
119 1.29.4.1 skrll null_update_beacon(struct ieee80211com *ic, int item)
120 1.29.4.1 skrll {
121 1.29.4.1 skrll }
122 1.29.4.1 skrll
123 1.1 dyoung void
124 1.19 dyoung ieee80211_proto_attach(struct ieee80211com *ic)
125 1.1 dyoung {
126 1.19 dyoung struct ifnet *ifp = ic->ic_ifp;
127 1.1 dyoung
128 1.19 dyoung /* XXX room for crypto */
129 1.19 dyoung ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4);
130 1.1 dyoung
131 1.1 dyoung ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
132 1.23 skrll ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT;
133 1.23 skrll ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
134 1.24 dyoung ic->ic_bmiss_max = IEEE80211_BMISS_MAX;
135 1.29.4.1 skrll callout_init(&ic->ic_swbmiss, CALLOUT_MPSAFE);
136 1.29.4.1 skrll callout_init(&ic->ic_mgtsend, CALLOUT_MPSAFE);
137 1.24 dyoung ic->ic_mcast_rate = IEEE80211_MCAST_RATE_DEFAULT;
138 1.8 dyoung ic->ic_protmode = IEEE80211_PROT_CTSONLY;
139 1.19 dyoung ic->ic_roaming = IEEE80211_ROAMING_AUTO;
140 1.1 dyoung
141 1.19 dyoung ic->ic_wme.wme_hipri_switch_hysteresis =
142 1.19 dyoung AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
143 1.1 dyoung
144 1.1 dyoung /* protocol state change handler */
145 1.1 dyoung ic->ic_newstate = ieee80211_newstate;
146 1.29.4.1 skrll ic->ic_update_beacon = null_update_beacon;
147 1.1 dyoung
148 1.1 dyoung /* initialize management frame handlers */
149 1.1 dyoung ic->ic_recv_mgmt = ieee80211_recv_mgmt;
150 1.1 dyoung ic->ic_send_mgmt = ieee80211_send_mgmt;
151 1.29.4.1 skrll ic->ic_raw_xmit = ieee80211_raw_xmit;
152 1.1 dyoung }
153 1.1 dyoung
154 1.1 dyoung void
155 1.19 dyoung ieee80211_proto_detach(struct ieee80211com *ic)
156 1.1 dyoung {
157 1.1 dyoung
158 1.19 dyoung /*
159 1.19 dyoung * This should not be needed as we detach when reseting
160 1.19 dyoung * the state but be conservative here since the
161 1.19 dyoung * authenticator may do things like spawn kernel threads.
162 1.19 dyoung */
163 1.19 dyoung if (ic->ic_auth->ia_detach)
164 1.19 dyoung ic->ic_auth->ia_detach(ic);
165 1.19 dyoung
166 1.29 degroote ieee80211_drain_ifq(&ic->ic_mgtq);
167 1.19 dyoung
168 1.19 dyoung /*
169 1.19 dyoung * Detach any ACL'ator.
170 1.19 dyoung */
171 1.19 dyoung if (ic->ic_acl != NULL)
172 1.19 dyoung ic->ic_acl->iac_detach(ic);
173 1.19 dyoung }
174 1.19 dyoung
175 1.19 dyoung /*
176 1.19 dyoung * Simple-minded authenticator module support.
177 1.19 dyoung */
178 1.19 dyoung
179 1.19 dyoung #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1)
180 1.19 dyoung /* XXX well-known names */
181 1.19 dyoung static const char *auth_modnames[IEEE80211_AUTH_MAX] = {
182 1.19 dyoung "wlan_internal", /* IEEE80211_AUTH_NONE */
183 1.19 dyoung "wlan_internal", /* IEEE80211_AUTH_OPEN */
184 1.19 dyoung "wlan_internal", /* IEEE80211_AUTH_SHARED */
185 1.19 dyoung "wlan_xauth", /* IEEE80211_AUTH_8021X */
186 1.19 dyoung "wlan_internal", /* IEEE80211_AUTH_AUTO */
187 1.19 dyoung "wlan_xauth", /* IEEE80211_AUTH_WPA */
188 1.19 dyoung };
189 1.19 dyoung static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX];
190 1.19 dyoung
191 1.19 dyoung static const struct ieee80211_authenticator auth_internal = {
192 1.19 dyoung .ia_name = "wlan_internal",
193 1.19 dyoung .ia_attach = NULL,
194 1.19 dyoung .ia_detach = NULL,
195 1.19 dyoung .ia_node_join = NULL,
196 1.19 dyoung .ia_node_leave = NULL,
197 1.19 dyoung };
198 1.19 dyoung
199 1.19 dyoung /*
200 1.19 dyoung * Setup internal authenticators once; they are never unregistered.
201 1.19 dyoung */
202 1.19 dyoung static void
203 1.19 dyoung ieee80211_auth_setup(void)
204 1.19 dyoung {
205 1.19 dyoung ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal);
206 1.19 dyoung ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal);
207 1.19 dyoung ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal);
208 1.19 dyoung }
209 1.19 dyoung
210 1.19 dyoung const struct ieee80211_authenticator *
211 1.19 dyoung ieee80211_authenticator_get(int auth)
212 1.19 dyoung {
213 1.19 dyoung static int initialized = 0;
214 1.19 dyoung if (!initialized) {
215 1.19 dyoung ieee80211_auth_setup();
216 1.19 dyoung initialized = 1;
217 1.19 dyoung }
218 1.19 dyoung if (auth >= IEEE80211_AUTH_MAX)
219 1.19 dyoung return NULL;
220 1.19 dyoung if (authenticators[auth] == NULL)
221 1.19 dyoung ieee80211_load_module(auth_modnames[auth]);
222 1.19 dyoung return authenticators[auth];
223 1.19 dyoung }
224 1.19 dyoung
225 1.19 dyoung void
226 1.19 dyoung ieee80211_authenticator_register(int type,
227 1.19 dyoung const struct ieee80211_authenticator *auth)
228 1.19 dyoung {
229 1.19 dyoung if (type >= IEEE80211_AUTH_MAX)
230 1.19 dyoung return;
231 1.19 dyoung authenticators[type] = auth;
232 1.19 dyoung }
233 1.19 dyoung
234 1.19 dyoung void
235 1.19 dyoung ieee80211_authenticator_unregister(int type)
236 1.19 dyoung {
237 1.19 dyoung
238 1.19 dyoung if (type >= IEEE80211_AUTH_MAX)
239 1.19 dyoung return;
240 1.19 dyoung authenticators[type] = NULL;
241 1.19 dyoung }
242 1.19 dyoung
243 1.19 dyoung /*
244 1.19 dyoung * Very simple-minded ACL module support.
245 1.19 dyoung */
246 1.19 dyoung /* XXX just one for now */
247 1.19 dyoung static const struct ieee80211_aclator *acl = NULL;
248 1.19 dyoung
249 1.19 dyoung void
250 1.19 dyoung ieee80211_aclator_register(const struct ieee80211_aclator *iac)
251 1.19 dyoung {
252 1.19 dyoung printf("wlan: %s acl policy registered\n", iac->iac_name);
253 1.19 dyoung acl = iac;
254 1.19 dyoung }
255 1.19 dyoung
256 1.19 dyoung void
257 1.19 dyoung ieee80211_aclator_unregister(const struct ieee80211_aclator *iac)
258 1.19 dyoung {
259 1.19 dyoung if (acl == iac)
260 1.19 dyoung acl = NULL;
261 1.19 dyoung printf("wlan: %s acl policy unregistered\n", iac->iac_name);
262 1.19 dyoung }
263 1.19 dyoung
264 1.19 dyoung const struct ieee80211_aclator *
265 1.19 dyoung ieee80211_aclator_get(const char *name)
266 1.19 dyoung {
267 1.19 dyoung if (acl == NULL)
268 1.19 dyoung ieee80211_load_module("wlan_acl");
269 1.19 dyoung return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL;
270 1.1 dyoung }
271 1.1 dyoung
272 1.1 dyoung void
273 1.29.4.1 skrll ieee80211_print_essid(const uint8_t *essid, int len)
274 1.1 dyoung {
275 1.29.4.1 skrll const uint8_t *p;
276 1.1 dyoung int i;
277 1.1 dyoung
278 1.1 dyoung if (len > IEEE80211_NWID_LEN)
279 1.1 dyoung len = IEEE80211_NWID_LEN;
280 1.1 dyoung /* determine printable or not */
281 1.1 dyoung for (i = 0, p = essid; i < len; i++, p++) {
282 1.1 dyoung if (*p < ' ' || *p > 0x7e)
283 1.1 dyoung break;
284 1.1 dyoung }
285 1.1 dyoung if (i == len) {
286 1.1 dyoung printf("\"");
287 1.1 dyoung for (i = 0, p = essid; i < len; i++, p++)
288 1.1 dyoung printf("%c", *p);
289 1.1 dyoung printf("\"");
290 1.1 dyoung } else {
291 1.1 dyoung printf("0x");
292 1.1 dyoung for (i = 0, p = essid; i < len; i++, p++)
293 1.1 dyoung printf("%02x", *p);
294 1.1 dyoung }
295 1.1 dyoung }
296 1.1 dyoung
297 1.1 dyoung void
298 1.29.4.1 skrll ieee80211_dump_pkt(struct ieee80211com *ic,
299 1.29.4.1 skrll const uint8_t *buf, int len, int rate, int rssi)
300 1.1 dyoung {
301 1.19 dyoung const struct ieee80211_frame *wh;
302 1.1 dyoung int i;
303 1.1 dyoung
304 1.19 dyoung wh = (const struct ieee80211_frame *)buf;
305 1.1 dyoung switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
306 1.1 dyoung case IEEE80211_FC1_DIR_NODS:
307 1.1 dyoung printf("NODS %s", ether_sprintf(wh->i_addr2));
308 1.1 dyoung printf("->%s", ether_sprintf(wh->i_addr1));
309 1.1 dyoung printf("(%s)", ether_sprintf(wh->i_addr3));
310 1.1 dyoung break;
311 1.1 dyoung case IEEE80211_FC1_DIR_TODS:
312 1.1 dyoung printf("TODS %s", ether_sprintf(wh->i_addr2));
313 1.1 dyoung printf("->%s", ether_sprintf(wh->i_addr3));
314 1.1 dyoung printf("(%s)", ether_sprintf(wh->i_addr1));
315 1.1 dyoung break;
316 1.1 dyoung case IEEE80211_FC1_DIR_FROMDS:
317 1.1 dyoung printf("FRDS %s", ether_sprintf(wh->i_addr3));
318 1.1 dyoung printf("->%s", ether_sprintf(wh->i_addr1));
319 1.1 dyoung printf("(%s)", ether_sprintf(wh->i_addr2));
320 1.1 dyoung break;
321 1.1 dyoung case IEEE80211_FC1_DIR_DSTODS:
322 1.29.4.1 skrll printf("DSDS %s", ether_sprintf((const uint8_t *)&wh[1]));
323 1.1 dyoung printf("->%s", ether_sprintf(wh->i_addr3));
324 1.1 dyoung printf("(%s", ether_sprintf(wh->i_addr2));
325 1.1 dyoung printf("->%s)", ether_sprintf(wh->i_addr1));
326 1.1 dyoung break;
327 1.1 dyoung }
328 1.1 dyoung switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
329 1.1 dyoung case IEEE80211_FC0_TYPE_DATA:
330 1.1 dyoung printf(" data");
331 1.1 dyoung break;
332 1.1 dyoung case IEEE80211_FC0_TYPE_MGT:
333 1.1 dyoung printf(" %s", ieee80211_mgt_subtype_name[
334 1.1 dyoung (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
335 1.1 dyoung >> IEEE80211_FC0_SUBTYPE_SHIFT]);
336 1.1 dyoung break;
337 1.1 dyoung default:
338 1.1 dyoung printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
339 1.1 dyoung break;
340 1.1 dyoung }
341 1.29.4.1 skrll if (IEEE80211_QOS_HAS_SEQ(wh)) {
342 1.29.4.1 skrll const struct ieee80211_qosframe *qwh =
343 1.29.4.1 skrll (const struct ieee80211_qosframe *)buf;
344 1.29.4.1 skrll printf(" QoS [TID %u%s]", qwh->i_qos[0] & IEEE80211_QOS_TID,
345 1.29.4.1 skrll qwh->i_qos[0] & IEEE80211_QOS_ACKPOLICY ? " ACM" : "");
346 1.29.4.1 skrll }
347 1.19 dyoung if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
348 1.29.4.1 skrll int off;
349 1.29.4.1 skrll
350 1.29.4.1 skrll off = ieee80211_anyhdrspace(ic, wh);
351 1.29.4.1 skrll printf(" WEP [IV %.02x %.02x %.02x",
352 1.29.4.1 skrll buf[off+0], buf[off+1], buf[off+2]);
353 1.29.4.1 skrll if (buf[off+IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)
354 1.29.4.1 skrll printf(" %.02x %.02x %.02x",
355 1.29.4.1 skrll buf[off+4], buf[off+5], buf[off+6]);
356 1.29.4.1 skrll printf(" KID %u]", buf[off+IEEE80211_WEP_IVLEN] >> 6);
357 1.19 dyoung }
358 1.1 dyoung if (rate >= 0)
359 1.1 dyoung printf(" %dM", rate / 2);
360 1.1 dyoung if (rssi >= 0)
361 1.1 dyoung printf(" +%d", rssi);
362 1.1 dyoung printf("\n");
363 1.1 dyoung if (len > 0) {
364 1.1 dyoung for (i = 0; i < len; i++) {
365 1.1 dyoung if ((i & 1) == 0)
366 1.1 dyoung printf(" ");
367 1.1 dyoung printf("%02x", buf[i]);
368 1.1 dyoung }
369 1.1 dyoung printf("\n");
370 1.1 dyoung }
371 1.1 dyoung }
372 1.1 dyoung
373 1.29.4.1 skrll static __inline int
374 1.29.4.1 skrll findrix(const struct ieee80211_rateset *rs, int r)
375 1.29.4.1 skrll {
376 1.29.4.1 skrll int i;
377 1.29.4.1 skrll
378 1.29.4.1 skrll for (i = 0; i < rs->rs_nrates; i++)
379 1.29.4.1 skrll if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == r)
380 1.29.4.1 skrll return i;
381 1.29.4.1 skrll return -1;
382 1.29.4.1 skrll }
383 1.29.4.1 skrll
384 1.1 dyoung int
385 1.29.4.1 skrll ieee80211_fix_rate(struct ieee80211_node *ni,
386 1.29.4.1 skrll struct ieee80211_rateset *nrs, int flags)
387 1.1 dyoung {
388 1.1 dyoung #define RV(v) ((v) & IEEE80211_RATE_VAL)
389 1.23 skrll struct ieee80211com *ic = ni->ni_ic;
390 1.29.4.1 skrll int i, j, rix, error;
391 1.19 dyoung int okrate, badrate, fixedrate;
392 1.29.4.1 skrll const struct ieee80211_rateset *srs;
393 1.29.4.1 skrll uint8_t r;
394 1.1 dyoung
395 1.1 dyoung error = 0;
396 1.29.4.1 skrll okrate = badrate = 0;
397 1.29.4.1 skrll fixedrate = IEEE80211_FIXED_RATE_NONE;
398 1.29.4.1 skrll srs = ieee80211_get_suprates(ic, ni->ni_chan);
399 1.6 dyoung for (i = 0; i < nrs->rs_nrates; ) {
400 1.1 dyoung if (flags & IEEE80211_F_DOSORT) {
401 1.1 dyoung /*
402 1.1 dyoung * Sort rates.
403 1.1 dyoung */
404 1.1 dyoung for (j = i + 1; j < nrs->rs_nrates; j++) {
405 1.1 dyoung if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) {
406 1.1 dyoung r = nrs->rs_rates[i];
407 1.1 dyoung nrs->rs_rates[i] = nrs->rs_rates[j];
408 1.1 dyoung nrs->rs_rates[j] = r;
409 1.1 dyoung }
410 1.1 dyoung }
411 1.1 dyoung }
412 1.1 dyoung r = nrs->rs_rates[i] & IEEE80211_RATE_VAL;
413 1.1 dyoung badrate = r;
414 1.29.4.1 skrll /*
415 1.29.4.1 skrll * Check for fixed rate.
416 1.29.4.1 skrll */
417 1.29.4.1 skrll if (r == ic->ic_fixed_rate)
418 1.29.4.1 skrll fixedrate = r;
419 1.29.4.1 skrll /*
420 1.29.4.1 skrll * Check against supported rates.
421 1.29.4.1 skrll */
422 1.29.4.1 skrll rix = findrix(srs, r);
423 1.1 dyoung if (flags & IEEE80211_F_DONEGO) {
424 1.29.4.1 skrll if (rix < 0) {
425 1.6 dyoung /*
426 1.6 dyoung * A rate in the node's rate set is not
427 1.6 dyoung * supported. If this is a basic rate and we
428 1.29.4.1 skrll * are operating as a STA then this is an error.
429 1.6 dyoung * Otherwise we just discard/ignore the rate.
430 1.6 dyoung */
431 1.29.4.1 skrll if ((flags & IEEE80211_F_JOIN) &&
432 1.6 dyoung (nrs->rs_rates[i] & IEEE80211_RATE_BASIC))
433 1.1 dyoung error++;
434 1.29.4.1 skrll } else if ((flags & IEEE80211_F_JOIN) == 0) {
435 1.29.4.1 skrll /*
436 1.29.4.1 skrll * Overwrite with the supported rate
437 1.29.4.1 skrll * value so any basic rate bit is set.
438 1.29.4.1 skrll */
439 1.29.4.1 skrll nrs->rs_rates[i] = srs->rs_rates[rix];
440 1.1 dyoung }
441 1.1 dyoung }
442 1.29.4.1 skrll if ((flags & IEEE80211_F_DODEL) && rix < 0) {
443 1.1 dyoung /*
444 1.1 dyoung * Delete unacceptable rates.
445 1.1 dyoung */
446 1.29.4.1 skrll nrs->rs_nrates--;
447 1.29.4.1 skrll for (j = i; j < nrs->rs_nrates; j++)
448 1.29.4.1 skrll nrs->rs_rates[j] = nrs->rs_rates[j + 1];
449 1.29.4.1 skrll nrs->rs_rates[j] = 0;
450 1.29.4.1 skrll continue;
451 1.1 dyoung }
452 1.29.4.1 skrll if (rix >= 0) {
453 1.1 dyoung okrate = nrs->rs_rates[i];
454 1.29.4.1 skrll ni->ni_txrate = i; /* XXXNH */
455 1.10 mycroft }
456 1.1 dyoung i++;
457 1.1 dyoung }
458 1.19 dyoung if (okrate == 0 || error != 0 ||
459 1.29.4.1 skrll ((flags & IEEE80211_F_DOFRATE) && fixedrate != ic->ic_fixed_rate))
460 1.1 dyoung return badrate | IEEE80211_RATE_BASIC;
461 1.1 dyoung else
462 1.1 dyoung return RV(okrate);
463 1.1 dyoung #undef RV
464 1.1 dyoung }
465 1.1 dyoung
466 1.19 dyoung /*
467 1.19 dyoung * Reset 11g-related state.
468 1.19 dyoung */
469 1.19 dyoung void
470 1.19 dyoung ieee80211_reset_erp(struct ieee80211com *ic)
471 1.19 dyoung {
472 1.19 dyoung ic->ic_flags &= ~IEEE80211_F_USEPROT;
473 1.19 dyoung ic->ic_nonerpsta = 0;
474 1.19 dyoung ic->ic_longslotsta = 0;
475 1.19 dyoung /*
476 1.19 dyoung * Short slot time is enabled only when operating in 11g
477 1.19 dyoung * and not in an IBSS. We must also honor whether or not
478 1.19 dyoung * the driver is capable of doing it.
479 1.19 dyoung */
480 1.19 dyoung ieee80211_set_shortslottime(ic,
481 1.29.4.1 skrll IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
482 1.29.4.1 skrll IEEE80211_IS_CHAN_HT(ic->ic_curchan) ||
483 1.29.4.1 skrll (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
484 1.19 dyoung ic->ic_opmode == IEEE80211_M_HOSTAP &&
485 1.19 dyoung (ic->ic_caps & IEEE80211_C_SHSLOT)));
486 1.19 dyoung /*
487 1.19 dyoung * Set short preamble and ERP barker-preamble flags.
488 1.19 dyoung */
489 1.29.4.1 skrll if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
490 1.19 dyoung (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) {
491 1.19 dyoung ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
492 1.19 dyoung ic->ic_flags &= ~IEEE80211_F_USEBARKER;
493 1.19 dyoung } else {
494 1.19 dyoung ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
495 1.19 dyoung ic->ic_flags |= IEEE80211_F_USEBARKER;
496 1.19 dyoung }
497 1.19 dyoung }
498 1.19 dyoung
499 1.19 dyoung /*
500 1.19 dyoung * Set the short slot time state and notify the driver.
501 1.19 dyoung */
502 1.19 dyoung void
503 1.19 dyoung ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff)
504 1.19 dyoung {
505 1.19 dyoung if (onoff)
506 1.19 dyoung ic->ic_flags |= IEEE80211_F_SHSLOT;
507 1.19 dyoung else
508 1.19 dyoung ic->ic_flags &= ~IEEE80211_F_SHSLOT;
509 1.19 dyoung /* notify driver */
510 1.19 dyoung if (ic->ic_updateslot != NULL)
511 1.19 dyoung ic->ic_updateslot(ic->ic_ifp);
512 1.19 dyoung }
513 1.19 dyoung
514 1.19 dyoung /*
515 1.19 dyoung * Check if the specified rate set supports ERP.
516 1.19 dyoung * NB: the rate set is assumed to be sorted.
517 1.19 dyoung */
518 1.19 dyoung int
519 1.28 christos ieee80211_iserp_rateset(struct ieee80211com *ic,
520 1.27 christos struct ieee80211_rateset *rs)
521 1.19 dyoung {
522 1.19 dyoung #define N(a) (sizeof(a) / sizeof(a[0]))
523 1.19 dyoung static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 };
524 1.19 dyoung int i, j;
525 1.19 dyoung
526 1.19 dyoung if (rs->rs_nrates < N(rates))
527 1.19 dyoung return 0;
528 1.19 dyoung for (i = 0; i < N(rates); i++) {
529 1.19 dyoung for (j = 0; j < rs->rs_nrates; j++) {
530 1.19 dyoung int r = rs->rs_rates[j] & IEEE80211_RATE_VAL;
531 1.19 dyoung if (rates[i] == r)
532 1.19 dyoung goto next;
533 1.19 dyoung if (r > rates[i])
534 1.19 dyoung return 0;
535 1.19 dyoung }
536 1.19 dyoung return 0;
537 1.19 dyoung next:
538 1.19 dyoung ;
539 1.19 dyoung }
540 1.19 dyoung return 1;
541 1.19 dyoung #undef N
542 1.19 dyoung }
543 1.19 dyoung
544 1.19 dyoung /*
545 1.19 dyoung * Mark the basic rates for the 11g rate table based on the
546 1.19 dyoung * operating mode. For real 11g we mark all the 11b rates
547 1.19 dyoung * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
548 1.19 dyoung * 11b rates. There's also a pseudo 11a-mode used to mark only
549 1.19 dyoung * the basic OFDM rates.
550 1.19 dyoung */
551 1.19 dyoung void
552 1.19 dyoung ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode)
553 1.19 dyoung {
554 1.29.4.1 skrll static const struct ieee80211_rateset basic[IEEE80211_MODE_MAX] = {
555 1.26 christos { .rs_nrates = 0 }, /* IEEE80211_MODE_AUTO */
556 1.19 dyoung { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
557 1.19 dyoung { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */
558 1.19 dyoung { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */
559 1.26 christos { .rs_nrates = 0 }, /* IEEE80211_MODE_FH */
560 1.19 dyoung /* IEEE80211_MODE_PUREG (not yet) */
561 1.19 dyoung { 7, { 2, 4, 11, 22, 12, 24, 48 } },
562 1.29.4.1 skrll { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11NA */
563 1.29.4.1 skrll /* IEEE80211_MODE_11NG (mixed b/g) */
564 1.29.4.1 skrll { 7, { 2, 4, 11, 22, 12, 24, 48 } },
565 1.19 dyoung };
566 1.19 dyoung int i, j;
567 1.19 dyoung
568 1.19 dyoung for (i = 0; i < rs->rs_nrates; i++) {
569 1.19 dyoung rs->rs_rates[i] &= IEEE80211_RATE_VAL;
570 1.19 dyoung for (j = 0; j < basic[mode].rs_nrates; j++)
571 1.19 dyoung if (basic[mode].rs_rates[j] == rs->rs_rates[i]) {
572 1.19 dyoung rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
573 1.19 dyoung break;
574 1.19 dyoung }
575 1.19 dyoung }
576 1.19 dyoung }
577 1.19 dyoung
578 1.19 dyoung /*
579 1.19 dyoung * WME protocol support. The following parameters come from the spec.
580 1.19 dyoung */
581 1.19 dyoung typedef struct phyParamType {
582 1.29.4.1 skrll uint8_t aifsn;
583 1.29.4.1 skrll uint8_t logcwmin;
584 1.29.4.1 skrll uint8_t logcwmax;
585 1.29.4.1 skrll uint16_t txopLimit;
586 1.29.4.1 skrll uint8_t acm;
587 1.19 dyoung } paramType;
588 1.19 dyoung
589 1.19 dyoung static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = {
590 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_AUTO */
591 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11A */
592 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11B */
593 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11G */
594 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_FH */
595 1.29.4.1 skrll { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
596 1.29.4.1 skrll { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
597 1.29.4.1 skrll { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
598 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NA */
599 1.29.4.1 skrll { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NG */
600 1.19 dyoung };
601 1.19 dyoung static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = {
602 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
603 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
604 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
605 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
606 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
607 1.29.4.1 skrll { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
608 1.29.4.1 skrll { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
609 1.29.4.1 skrll { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
610 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
611 1.29.4.1 skrll { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
612 1.19 dyoung };
613 1.19 dyoung static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = {
614 1.29.4.1 skrll { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
615 1.29.4.1 skrll { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
616 1.29.4.1 skrll { 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
617 1.29.4.1 skrll { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
618 1.29.4.1 skrll { 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
619 1.29.4.1 skrll { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
620 1.29.4.1 skrll { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
621 1.29.4.1 skrll { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
622 1.29.4.1 skrll { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
623 1.29.4.1 skrll { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
624 1.19 dyoung };
625 1.19 dyoung static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = {
626 1.29.4.1 skrll { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
627 1.29.4.1 skrll { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
628 1.29.4.1 skrll { 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
629 1.29.4.1 skrll { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
630 1.29.4.1 skrll { 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
631 1.29.4.1 skrll { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
632 1.29.4.1 skrll { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
633 1.29.4.1 skrll { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
634 1.29.4.1 skrll { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
635 1.29.4.1 skrll { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
636 1.19 dyoung };
637 1.19 dyoung
638 1.19 dyoung static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = {
639 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
640 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
641 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
642 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
643 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
644 1.29.4.1 skrll { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
645 1.29.4.1 skrll { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
646 1.29.4.1 skrll { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
647 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
648 1.29.4.1 skrll { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
649 1.19 dyoung };
650 1.19 dyoung static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = {
651 1.29.4.1 skrll { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
652 1.29.4.1 skrll { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
653 1.29.4.1 skrll { 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
654 1.29.4.1 skrll { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
655 1.29.4.1 skrll { 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
656 1.29.4.1 skrll { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
657 1.29.4.1 skrll { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
658 1.29.4.1 skrll { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
659 1.29.4.1 skrll { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
660 1.29.4.1 skrll { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
661 1.19 dyoung };
662 1.19 dyoung static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = {
663 1.29.4.1 skrll { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
664 1.29.4.1 skrll { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
665 1.29.4.1 skrll { 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
666 1.29.4.1 skrll { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
667 1.29.4.1 skrll { 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
668 1.29.4.1 skrll { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
669 1.29.4.1 skrll { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
670 1.29.4.1 skrll { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
671 1.29.4.1 skrll { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
672 1.29.4.1 skrll { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
673 1.19 dyoung };
674 1.19 dyoung
675 1.19 dyoung void
676 1.19 dyoung ieee80211_wme_initparams(struct ieee80211com *ic)
677 1.19 dyoung {
678 1.19 dyoung struct ieee80211_wme_state *wme = &ic->ic_wme;
679 1.19 dyoung const paramType *pPhyParam, *pBssPhyParam;
680 1.19 dyoung struct wmeParams *wmep;
681 1.29.4.1 skrll enum ieee80211_phymode mode;
682 1.19 dyoung int i;
683 1.19 dyoung
684 1.19 dyoung if ((ic->ic_caps & IEEE80211_C_WME) == 0)
685 1.19 dyoung return;
686 1.19 dyoung
687 1.29.4.1 skrll /*
688 1.29.4.1 skrll * Select mode; we can be called early in which case we
689 1.29.4.1 skrll * always use auto mode. We know we'll be called when
690 1.29.4.1 skrll * entering the RUN state with bsschan setup properly
691 1.29.4.1 skrll * so state will eventually get set correctly
692 1.29.4.1 skrll */
693 1.29.4.1 skrll if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)
694 1.29.4.1 skrll mode = ieee80211_chan2mode(ic->ic_bsschan);
695 1.29.4.1 skrll else
696 1.29.4.1 skrll mode = IEEE80211_MODE_AUTO;
697 1.19 dyoung for (i = 0; i < WME_NUM_AC; i++) {
698 1.19 dyoung switch (i) {
699 1.19 dyoung case WME_AC_BK:
700 1.29.4.1 skrll pPhyParam = &phyParamForAC_BK[mode];
701 1.29.4.1 skrll pBssPhyParam = &phyParamForAC_BK[mode];
702 1.19 dyoung break;
703 1.19 dyoung case WME_AC_VI:
704 1.29.4.1 skrll pPhyParam = &phyParamForAC_VI[mode];
705 1.29.4.1 skrll pBssPhyParam = &bssPhyParamForAC_VI[mode];
706 1.19 dyoung break;
707 1.19 dyoung case WME_AC_VO:
708 1.29.4.1 skrll pPhyParam = &phyParamForAC_VO[mode];
709 1.29.4.1 skrll pBssPhyParam = &bssPhyParamForAC_VO[mode];
710 1.19 dyoung break;
711 1.19 dyoung case WME_AC_BE:
712 1.19 dyoung default:
713 1.29.4.1 skrll pPhyParam = &phyParamForAC_BE[mode];
714 1.29.4.1 skrll pBssPhyParam = &bssPhyParamForAC_BE[mode];
715 1.19 dyoung break;
716 1.19 dyoung }
717 1.19 dyoung
718 1.19 dyoung wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
719 1.19 dyoung if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
720 1.19 dyoung wmep->wmep_acm = pPhyParam->acm;
721 1.19 dyoung wmep->wmep_aifsn = pPhyParam->aifsn;
722 1.19 dyoung wmep->wmep_logcwmin = pPhyParam->logcwmin;
723 1.19 dyoung wmep->wmep_logcwmax = pPhyParam->logcwmax;
724 1.19 dyoung wmep->wmep_txopLimit = pPhyParam->txopLimit;
725 1.19 dyoung } else {
726 1.19 dyoung wmep->wmep_acm = pBssPhyParam->acm;
727 1.19 dyoung wmep->wmep_aifsn = pBssPhyParam->aifsn;
728 1.19 dyoung wmep->wmep_logcwmin = pBssPhyParam->logcwmin;
729 1.19 dyoung wmep->wmep_logcwmax = pBssPhyParam->logcwmax;
730 1.19 dyoung wmep->wmep_txopLimit = pBssPhyParam->txopLimit;
731 1.19 dyoung
732 1.19 dyoung }
733 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
734 1.19 dyoung "%s: %s chan [acm %u aifsn %u log2(cwmin) %u "
735 1.19 dyoung "log2(cwmax) %u txpoLimit %u]\n", __func__
736 1.19 dyoung , ieee80211_wme_acnames[i]
737 1.19 dyoung , wmep->wmep_acm
738 1.19 dyoung , wmep->wmep_aifsn
739 1.19 dyoung , wmep->wmep_logcwmin
740 1.19 dyoung , wmep->wmep_logcwmax
741 1.19 dyoung , wmep->wmep_txopLimit
742 1.19 dyoung );
743 1.19 dyoung
744 1.19 dyoung wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
745 1.19 dyoung wmep->wmep_acm = pBssPhyParam->acm;
746 1.19 dyoung wmep->wmep_aifsn = pBssPhyParam->aifsn;
747 1.19 dyoung wmep->wmep_logcwmin = pBssPhyParam->logcwmin;
748 1.19 dyoung wmep->wmep_logcwmax = pBssPhyParam->logcwmax;
749 1.19 dyoung wmep->wmep_txopLimit = pBssPhyParam->txopLimit;
750 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
751 1.19 dyoung "%s: %s bss [acm %u aifsn %u log2(cwmin) %u "
752 1.19 dyoung "log2(cwmax) %u txpoLimit %u]\n", __func__
753 1.19 dyoung , ieee80211_wme_acnames[i]
754 1.19 dyoung , wmep->wmep_acm
755 1.19 dyoung , wmep->wmep_aifsn
756 1.19 dyoung , wmep->wmep_logcwmin
757 1.19 dyoung , wmep->wmep_logcwmax
758 1.19 dyoung , wmep->wmep_txopLimit
759 1.19 dyoung );
760 1.19 dyoung }
761 1.19 dyoung /* NB: check ic_bss to avoid NULL deref on initial attach */
762 1.19 dyoung if (ic->ic_bss != NULL) {
763 1.19 dyoung /*
764 1.19 dyoung * Calculate agressive mode switching threshold based
765 1.19 dyoung * on beacon interval. This doesn't need locking since
766 1.19 dyoung * we're only called before entering the RUN state at
767 1.19 dyoung * which point we start sending beacon frames.
768 1.19 dyoung */
769 1.19 dyoung wme->wme_hipri_switch_thresh =
770 1.19 dyoung (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->ni_intval) / 100;
771 1.19 dyoung ieee80211_wme_updateparams(ic);
772 1.19 dyoung }
773 1.19 dyoung }
774 1.19 dyoung
775 1.19 dyoung /*
776 1.19 dyoung * Update WME parameters for ourself and the BSS.
777 1.19 dyoung */
778 1.19 dyoung void
779 1.19 dyoung ieee80211_wme_updateparams_locked(struct ieee80211com *ic)
780 1.19 dyoung {
781 1.19 dyoung static const paramType phyParam[IEEE80211_MODE_MAX] = {
782 1.29.4.1 skrll { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_AUTO */
783 1.29.4.1 skrll { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11A */
784 1.29.4.1 skrll { 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_11B */
785 1.29.4.1 skrll { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11G */
786 1.29.4.1 skrll { 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_FH */
787 1.29.4.1 skrll { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_A */
788 1.29.4.1 skrll { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_G */
789 1.29.4.1 skrll { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_STURBO_A */
790 1.29.4.1 skrll { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NA */ /*XXXcheck*/
791 1.29.4.1 skrll { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NG */ /*XXXcheck*/
792 1.19 dyoung };
793 1.19 dyoung struct ieee80211_wme_state *wme = &ic->ic_wme;
794 1.19 dyoung const struct wmeParams *wmep;
795 1.19 dyoung struct wmeParams *chanp, *bssp;
796 1.29.4.1 skrll enum ieee80211_phymode mode;
797 1.19 dyoung int i;
798 1.19 dyoung
799 1.19 dyoung /* set up the channel access parameters for the physical device */
800 1.19 dyoung for (i = 0; i < WME_NUM_AC; i++) {
801 1.19 dyoung chanp = &wme->wme_chanParams.cap_wmeParams[i];
802 1.19 dyoung wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
803 1.19 dyoung chanp->wmep_aifsn = wmep->wmep_aifsn;
804 1.19 dyoung chanp->wmep_logcwmin = wmep->wmep_logcwmin;
805 1.19 dyoung chanp->wmep_logcwmax = wmep->wmep_logcwmax;
806 1.19 dyoung chanp->wmep_txopLimit = wmep->wmep_txopLimit;
807 1.19 dyoung
808 1.19 dyoung chanp = &wme->wme_bssChanParams.cap_wmeParams[i];
809 1.19 dyoung wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
810 1.19 dyoung chanp->wmep_aifsn = wmep->wmep_aifsn;
811 1.19 dyoung chanp->wmep_logcwmin = wmep->wmep_logcwmin;
812 1.19 dyoung chanp->wmep_logcwmax = wmep->wmep_logcwmax;
813 1.19 dyoung chanp->wmep_txopLimit = wmep->wmep_txopLimit;
814 1.19 dyoung }
815 1.19 dyoung
816 1.19 dyoung /*
817 1.29.4.1 skrll * Select mode; we can be called early in which case we
818 1.29.4.1 skrll * always use auto mode. We know we'll be called when
819 1.29.4.1 skrll * entering the RUN state with bsschan setup properly
820 1.29.4.1 skrll * so state will eventually get set correctly
821 1.29.4.1 skrll */
822 1.29.4.1 skrll if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)
823 1.29.4.1 skrll mode = ieee80211_chan2mode(ic->ic_bsschan);
824 1.29.4.1 skrll else
825 1.29.4.1 skrll mode = IEEE80211_MODE_AUTO;
826 1.29.4.1 skrll
827 1.29.4.1 skrll /*
828 1.19 dyoung * This implements agressive mode as found in certain
829 1.19 dyoung * vendors' AP's. When there is significant high
830 1.19 dyoung * priority (VI/VO) traffic in the BSS throttle back BE
831 1.19 dyoung * traffic by using conservative parameters. Otherwise
832 1.19 dyoung * BE uses agressive params to optimize performance of
833 1.19 dyoung * legacy/non-QoS traffic.
834 1.19 dyoung */
835 1.19 dyoung if ((ic->ic_opmode == IEEE80211_M_HOSTAP &&
836 1.29.4.1 skrll (wme->wme_flags & WME_F_AGGRMODE) != 0) ||
837 1.29.4.1 skrll (ic->ic_opmode == IEEE80211_M_STA &&
838 1.19 dyoung (ic->ic_bss->ni_flags & IEEE80211_NODE_QOS) == 0) ||
839 1.19 dyoung (ic->ic_flags & IEEE80211_F_WME) == 0) {
840 1.19 dyoung chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
841 1.19 dyoung bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
842 1.19 dyoung
843 1.29.4.1 skrll chanp->wmep_aifsn = bssp->wmep_aifsn = phyParam[mode].aifsn;
844 1.19 dyoung chanp->wmep_logcwmin = bssp->wmep_logcwmin =
845 1.29.4.1 skrll phyParam[mode].logcwmin;
846 1.19 dyoung chanp->wmep_logcwmax = bssp->wmep_logcwmax =
847 1.29.4.1 skrll phyParam[mode].logcwmax;
848 1.19 dyoung chanp->wmep_txopLimit = bssp->wmep_txopLimit =
849 1.29.4.1 skrll (ic->ic_flags & IEEE80211_F_BURST) ?
850 1.29.4.1 skrll phyParam[mode].txopLimit : 0;
851 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
852 1.19 dyoung "%s: %s [acm %u aifsn %u log2(cwmin) %u "
853 1.19 dyoung "log2(cwmax) %u txpoLimit %u]\n", __func__
854 1.19 dyoung , ieee80211_wme_acnames[WME_AC_BE]
855 1.19 dyoung , chanp->wmep_acm
856 1.19 dyoung , chanp->wmep_aifsn
857 1.19 dyoung , chanp->wmep_logcwmin
858 1.19 dyoung , chanp->wmep_logcwmax
859 1.19 dyoung , chanp->wmep_txopLimit
860 1.19 dyoung );
861 1.19 dyoung }
862 1.19 dyoung
863 1.20 dyoung #ifndef IEEE80211_NO_HOSTAP
864 1.19 dyoung if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
865 1.29.4.1 skrll ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) {
866 1.29.4.1 skrll static const uint8_t logCwMin[IEEE80211_MODE_MAX] = {
867 1.19 dyoung 3, /* IEEE80211_MODE_AUTO */
868 1.19 dyoung 3, /* IEEE80211_MODE_11A */
869 1.19 dyoung 4, /* IEEE80211_MODE_11B */
870 1.19 dyoung 3, /* IEEE80211_MODE_11G */
871 1.19 dyoung 4, /* IEEE80211_MODE_FH */
872 1.19 dyoung 3, /* IEEE80211_MODE_TURBO_A */
873 1.19 dyoung 3, /* IEEE80211_MODE_TURBO_G */
874 1.29.4.1 skrll 3, /* IEEE80211_MODE_STURBO_A */
875 1.29.4.1 skrll 3, /* IEEE80211_MODE_11NA */
876 1.29.4.1 skrll 3, /* IEEE80211_MODE_11NG */
877 1.19 dyoung };
878 1.19 dyoung chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
879 1.19 dyoung bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
880 1.19 dyoung
881 1.29.4.1 skrll chanp->wmep_logcwmin = bssp->wmep_logcwmin = logCwMin[mode];
882 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
883 1.19 dyoung "%s: %s log2(cwmin) %u\n", __func__
884 1.19 dyoung , ieee80211_wme_acnames[WME_AC_BE]
885 1.19 dyoung , chanp->wmep_logcwmin
886 1.19 dyoung );
887 1.19 dyoung }
888 1.19 dyoung if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */
889 1.19 dyoung /*
890 1.19 dyoung * Arrange for a beacon update and bump the parameter
891 1.19 dyoung * set number so associated stations load the new values.
892 1.19 dyoung */
893 1.19 dyoung wme->wme_bssChanParams.cap_info =
894 1.19 dyoung (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT;
895 1.29.4.1 skrll ieee80211_beacon_notify(ic, IEEE80211_BEACON_WME);
896 1.19 dyoung }
897 1.20 dyoung #endif /* !IEEE80211_NO_HOSTAP */
898 1.19 dyoung
899 1.19 dyoung wme->wme_update(ic);
900 1.19 dyoung
901 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
902 1.19 dyoung "%s: WME params updated, cap_info 0x%x\n", __func__,
903 1.19 dyoung ic->ic_opmode == IEEE80211_M_STA ?
904 1.19 dyoung wme->wme_wmeChanParams.cap_info :
905 1.19 dyoung wme->wme_bssChanParams.cap_info);
906 1.19 dyoung }
907 1.19 dyoung
908 1.19 dyoung void
909 1.19 dyoung ieee80211_wme_updateparams(struct ieee80211com *ic)
910 1.19 dyoung {
911 1.19 dyoung
912 1.19 dyoung if (ic->ic_caps & IEEE80211_C_WME) {
913 1.19 dyoung IEEE80211_BEACON_LOCK(ic);
914 1.19 dyoung ieee80211_wme_updateparams_locked(ic);
915 1.19 dyoung IEEE80211_BEACON_UNLOCK(ic);
916 1.19 dyoung }
917 1.19 dyoung }
918 1.19 dyoung
919 1.29.4.1 skrll /*
920 1.29.4.1 skrll * Start a device. If this is the first vap running on the
921 1.29.4.1 skrll * underlying device then we first bring it up.
922 1.29.4.1 skrll */
923 1.29.4.1 skrll int
924 1.29.4.1 skrll ieee80211_init(struct ieee80211com *ic, int forcescan)
925 1.29.4.1 skrll {
926 1.29.4.1 skrll
927 1.29.4.1 skrll IEEE80211_DPRINTF(ic,
928 1.29.4.1 skrll IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
929 1.29.4.1 skrll "%s\n", "start running");
930 1.29.4.1 skrll
931 1.29.4.1 skrll /*
932 1.29.4.1 skrll * Kick the 802.11 state machine as appropriate.
933 1.29.4.1 skrll */
934 1.29.4.1 skrll if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) {
935 1.29.4.1 skrll if (ic->ic_opmode == IEEE80211_M_STA) {
936 1.29.4.1 skrll ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
937 1.29.4.1 skrll } else {
938 1.29.4.1 skrll /*
939 1.29.4.1 skrll * For monitor+wds modes there's nothing to do but
940 1.29.4.1 skrll * start running. Otherwise, if this is the first
941 1.29.4.1 skrll * vap to be brought up, start a scan which may be
942 1.29.4.1 skrll * preempted if the station is locked to a particular
943 1.29.4.1 skrll * channel.
944 1.29.4.1 skrll */
945 1.29.4.1 skrll if (ic->ic_opmode == IEEE80211_M_MONITOR ||
946 1.29.4.1 skrll ic->ic_opmode == IEEE80211_M_WDS) {
947 1.29.4.1 skrll ic->ic_state = IEEE80211_S_INIT; /* XXX*/
948 1.29.4.1 skrll ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
949 1.29.4.1 skrll } else
950 1.29.4.1 skrll ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
951 1.29.4.1 skrll }
952 1.29.4.1 skrll }
953 1.29.4.1 skrll return 0;
954 1.29.4.1 skrll }
955 1.29.4.1 skrll
956 1.29.4.1 skrll /*
957 1.29.4.1 skrll * Switch between turbo and non-turbo operating modes.
958 1.29.4.1 skrll * Use the specified channel flags to locate the new
959 1.29.4.1 skrll * channel, update 802.11 state, and then call back into
960 1.29.4.1 skrll * the driver to effect the change.
961 1.29.4.1 skrll */
962 1.29.4.1 skrll void
963 1.29.4.1 skrll ieee80211_dturbo_switch(struct ieee80211com *ic, int newflags)
964 1.29.4.1 skrll {
965 1.29.4.1 skrll struct ieee80211_channel *chan;
966 1.29.4.1 skrll
967 1.29.4.1 skrll chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags);
968 1.29.4.1 skrll if (chan == NULL) { /* XXX should not happen */
969 1.29.4.1 skrll IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
970 1.29.4.1 skrll "%s: no channel with freq %u flags 0x%x\n",
971 1.29.4.1 skrll __func__, ic->ic_bsschan->ic_freq, newflags);
972 1.29.4.1 skrll return;
973 1.29.4.1 skrll }
974 1.29.4.1 skrll
975 1.29.4.1 skrll IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
976 1.29.4.1 skrll "%s: %s -> %s (freq %u flags 0x%x)\n", __func__,
977 1.29.4.1 skrll ieee80211_phymode_name[ieee80211_chan2mode(ic->ic_bsschan)],
978 1.29.4.1 skrll ieee80211_phymode_name[ieee80211_chan2mode(chan)],
979 1.29.4.1 skrll chan->ic_freq, chan->ic_flags);
980 1.29.4.1 skrll
981 1.29.4.1 skrll ic->ic_bsschan = chan;
982 1.29.4.1 skrll ic->ic_prevchan = ic->ic_curchan;
983 1.29.4.1 skrll ic->ic_curchan = chan;
984 1.29.4.1 skrll ic->ic_set_channel(ic);
985 1.29.4.1 skrll /* NB: do not need to reset ERP state 'cuz we're in sta mode */
986 1.29.4.1 skrll }
987 1.29.4.1 skrll
988 1.22 dyoung #ifndef IEEE80211_NO_HOSTAP
989 1.21 dyoung static void
990 1.21 dyoung sta_disassoc(void *arg, struct ieee80211_node *ni)
991 1.21 dyoung {
992 1.21 dyoung struct ieee80211com *ic = arg;
993 1.21 dyoung
994 1.21 dyoung if (ni->ni_associd != 0) {
995 1.21 dyoung IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC,
996 1.21 dyoung IEEE80211_REASON_ASSOC_LEAVE);
997 1.21 dyoung ieee80211_node_leave(ic, ni);
998 1.21 dyoung }
999 1.21 dyoung }
1000 1.24 dyoung #endif /* !IEEE80211_NO_HOSTAP */
1001 1.24 dyoung
1002 1.24 dyoung void
1003 1.24 dyoung ieee80211_beacon_miss(struct ieee80211com *ic)
1004 1.24 dyoung {
1005 1.24 dyoung
1006 1.24 dyoung if (ic->ic_flags & IEEE80211_F_SCAN) {
1007 1.24 dyoung /* XXX check ic_curchan != ic_bsschan? */
1008 1.24 dyoung return;
1009 1.24 dyoung }
1010 1.29.4.1 skrll IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
1011 1.24 dyoung "%s\n", "beacon miss");
1012 1.24 dyoung
1013 1.24 dyoung /*
1014 1.24 dyoung * Our handling is only meaningful for stations that are
1015 1.24 dyoung * associated; any other conditions else will be handled
1016 1.24 dyoung * through different means (e.g. the tx timeout on mgt frames).
1017 1.24 dyoung */
1018 1.24 dyoung if (ic->ic_opmode != IEEE80211_M_STA || ic->ic_state != IEEE80211_S_RUN)
1019 1.24 dyoung return;
1020 1.21 dyoung
1021 1.24 dyoung if (++ic->ic_bmiss_count < ic->ic_bmiss_max) {
1022 1.24 dyoung /*
1023 1.24 dyoung * Send a directed probe req before falling back to a scan;
1024 1.24 dyoung * if we receive a response ic_bmiss_count will be reset.
1025 1.24 dyoung * Some cards mistakenly report beacon miss so this avoids
1026 1.24 dyoung * the expensive scan if the ap is still there.
1027 1.24 dyoung */
1028 1.24 dyoung ieee80211_send_probereq(ic->ic_bss, ic->ic_myaddr,
1029 1.24 dyoung ic->ic_bss->ni_bssid, ic->ic_bss->ni_bssid,
1030 1.24 dyoung ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen,
1031 1.24 dyoung ic->ic_opt_ie, ic->ic_opt_ie_len);
1032 1.24 dyoung return;
1033 1.24 dyoung }
1034 1.24 dyoung ic->ic_bmiss_count = 0;
1035 1.29.4.1 skrll if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
1036 1.29.4.1 skrll /*
1037 1.29.4.1 skrll * If we receive a beacon miss interrupt when using
1038 1.29.4.1 skrll * dynamic turbo, attempt to switch modes before
1039 1.29.4.1 skrll * reassociating.
1040 1.29.4.1 skrll */
1041 1.29.4.1 skrll if (IEEE80211_ATH_CAP(ic, ic->ic_bss, IEEE80211_NODE_TURBOP))
1042 1.29.4.1 skrll ieee80211_dturbo_switch(ic,
1043 1.29.4.1 skrll ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO);
1044 1.29.4.1 skrll /*
1045 1.29.4.1 skrll * Try to reassociate before scanning for a new ap.
1046 1.29.4.1 skrll */
1047 1.29.4.1 skrll ieee80211_new_state(ic, IEEE80211_S_ASSOC, 1);
1048 1.29.4.1 skrll } else {
1049 1.29.4.1 skrll /*
1050 1.29.4.1 skrll * Somebody else is controlling state changes (e.g.
1051 1.29.4.1 skrll * a user-mode app) don't do anything that would
1052 1.29.4.1 skrll * confuse them; just drop into scan mode so they'll
1053 1.29.4.1 skrll * notified of the state change and given control.
1054 1.29.4.1 skrll */
1055 1.29.4.1 skrll ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
1056 1.29.4.1 skrll }
1057 1.29.4.1 skrll }
1058 1.29.4.1 skrll
1059 1.29.4.1 skrll /*
1060 1.29.4.1 skrll * Software beacon miss handling. Check if any beacons
1061 1.29.4.1 skrll * were received in the last period. If not post a
1062 1.29.4.1 skrll * beacon miss; otherwise reset the counter.
1063 1.29.4.1 skrll */
1064 1.29.4.1 skrll static void
1065 1.29.4.1 skrll ieee80211_swbmiss(void *arg)
1066 1.29.4.1 skrll {
1067 1.29.4.1 skrll struct ieee80211com *ic = arg;
1068 1.29.4.1 skrll
1069 1.29.4.1 skrll if (ic->ic_swbmiss_count == 0) {
1070 1.29.4.1 skrll ieee80211_beacon_miss(ic);
1071 1.29.4.1 skrll if (ic->ic_bmiss_count == 0) /* don't re-arm timer */
1072 1.29.4.1 skrll return;
1073 1.29.4.1 skrll } else
1074 1.29.4.1 skrll ic->ic_swbmiss_count = 0;
1075 1.29.4.1 skrll callout_reset(&ic->ic_swbmiss, ic->ic_swbmiss_period,
1076 1.29.4.1 skrll ieee80211_swbmiss, ic);
1077 1.24 dyoung }
1078 1.24 dyoung
1079 1.24 dyoung #ifndef IEEE80211_NO_HOSTAP
1080 1.21 dyoung static void
1081 1.21 dyoung sta_deauth(void *arg, struct ieee80211_node *ni)
1082 1.21 dyoung {
1083 1.21 dyoung struct ieee80211com *ic = arg;
1084 1.21 dyoung
1085 1.21 dyoung IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
1086 1.21 dyoung IEEE80211_REASON_ASSOC_LEAVE);
1087 1.21 dyoung }
1088 1.22 dyoung #endif /* !IEEE80211_NO_HOSTAP */
1089 1.21 dyoung
1090 1.29.4.1 skrll /*
1091 1.29.4.1 skrll * Handle deauth with reason. We retry only for
1092 1.29.4.1 skrll * the cases where we might succeed. Otherwise
1093 1.29.4.1 skrll * we downgrade the ap and scan.
1094 1.29.4.1 skrll */
1095 1.29.4.1 skrll static void
1096 1.29.4.1 skrll sta_authretry(struct ieee80211com *ic, struct ieee80211_node *ni, int reason)
1097 1.29.4.1 skrll {
1098 1.29.4.1 skrll switch (reason) {
1099 1.29.4.1 skrll case IEEE80211_STATUS_SUCCESS:
1100 1.29.4.1 skrll case IEEE80211_STATUS_TIMEOUT:
1101 1.29.4.1 skrll case IEEE80211_REASON_ASSOC_EXPIRE:
1102 1.29.4.1 skrll case IEEE80211_REASON_NOT_AUTHED:
1103 1.29.4.1 skrll case IEEE80211_REASON_NOT_ASSOCED:
1104 1.29.4.1 skrll case IEEE80211_REASON_ASSOC_LEAVE:
1105 1.29.4.1 skrll case IEEE80211_REASON_ASSOC_NOT_AUTHED:
1106 1.29.4.1 skrll IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 1);
1107 1.29.4.1 skrll break;
1108 1.29.4.1 skrll default:
1109 1.29.4.1 skrll ieee80211_scan_assoc_fail(ic, ic->ic_bss->ni_macaddr, reason);
1110 1.29.4.1 skrll if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
1111 1.29.4.1 skrll ieee80211_check_scan(ic,
1112 1.29.4.1 skrll IEEE80211_SCAN_ACTIVE,
1113 1.29.4.1 skrll IEEE80211_SCAN_FOREVER,
1114 1.29.4.1 skrll ic->ic_des_nssid, ic->ic_des_ssid);
1115 1.29.4.1 skrll break;
1116 1.29.4.1 skrll }
1117 1.29.4.1 skrll }
1118 1.29.4.1 skrll
1119 1.1 dyoung static int
1120 1.19 dyoung ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1121 1.1 dyoung {
1122 1.19 dyoung struct ifnet *ifp = ic->ic_ifp;
1123 1.1 dyoung struct ieee80211_node *ni;
1124 1.1 dyoung enum ieee80211_state ostate;
1125 1.1 dyoung
1126 1.1 dyoung ostate = ic->ic_state;
1127 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__,
1128 1.19 dyoung ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
1129 1.1 dyoung ic->ic_state = nstate; /* state transition */
1130 1.29.4.1 skrll callout_stop(&ic->ic_mgtsend); /* XXX callout_drain */
1131 1.29.4.1 skrll if (ostate != IEEE80211_S_SCAN)
1132 1.29.4.1 skrll ieee80211_cancel_scan(ic); /* background scan */
1133 1.1 dyoung ni = ic->ic_bss; /* NB: no reference held */
1134 1.29.4.1 skrll if (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS)
1135 1.29.4.1 skrll callout_stop(&ic->ic_swbmiss);
1136 1.1 dyoung switch (nstate) {
1137 1.1 dyoung case IEEE80211_S_INIT:
1138 1.1 dyoung switch (ostate) {
1139 1.1 dyoung case IEEE80211_S_INIT:
1140 1.1 dyoung break;
1141 1.1 dyoung case IEEE80211_S_RUN:
1142 1.1 dyoung switch (ic->ic_opmode) {
1143 1.1 dyoung case IEEE80211_M_STA:
1144 1.1 dyoung IEEE80211_SEND_MGMT(ic, ni,
1145 1.1 dyoung IEEE80211_FC0_SUBTYPE_DISASSOC,
1146 1.1 dyoung IEEE80211_REASON_ASSOC_LEAVE);
1147 1.19 dyoung ieee80211_sta_leave(ic, ni);
1148 1.1 dyoung break;
1149 1.1 dyoung case IEEE80211_M_HOSTAP:
1150 1.20 dyoung #ifndef IEEE80211_NO_HOSTAP
1151 1.21 dyoung ieee80211_iterate_nodes(&ic->ic_sta,
1152 1.21 dyoung sta_disassoc, ic);
1153 1.20 dyoung #endif /* !IEEE80211_NO_HOSTAP */
1154 1.1 dyoung break;
1155 1.1 dyoung default:
1156 1.1 dyoung break;
1157 1.1 dyoung }
1158 1.29.4.1 skrll break;
1159 1.1 dyoung case IEEE80211_S_ASSOC:
1160 1.1 dyoung switch (ic->ic_opmode) {
1161 1.1 dyoung case IEEE80211_M_STA:
1162 1.1 dyoung IEEE80211_SEND_MGMT(ic, ni,
1163 1.1 dyoung IEEE80211_FC0_SUBTYPE_DEAUTH,
1164 1.1 dyoung IEEE80211_REASON_AUTH_LEAVE);
1165 1.1 dyoung break;
1166 1.1 dyoung case IEEE80211_M_HOSTAP:
1167 1.20 dyoung #ifndef IEEE80211_NO_HOSTAP
1168 1.21 dyoung ieee80211_iterate_nodes(&ic->ic_sta,
1169 1.21 dyoung sta_deauth, ic);
1170 1.20 dyoung #endif /* !IEEE80211_NO_HOSTAP */
1171 1.1 dyoung break;
1172 1.1 dyoung default:
1173 1.1 dyoung break;
1174 1.1 dyoung }
1175 1.29.4.1 skrll break;
1176 1.19 dyoung case IEEE80211_S_SCAN:
1177 1.19 dyoung ieee80211_cancel_scan(ic);
1178 1.29.4.1 skrll break;
1179 1.1 dyoung case IEEE80211_S_AUTH:
1180 1.29.4.1 skrll break;
1181 1.29.4.1 skrll default:
1182 1.29.4.1 skrll break;
1183 1.29.4.1 skrll }
1184 1.29.4.1 skrll if (ostate != IEEE80211_S_INIT) {
1185 1.29.4.1 skrll /* NB: optimize INIT -> INIT case */
1186 1.29 degroote ieee80211_drain_ifq(&ic->ic_mgtq);
1187 1.19 dyoung ieee80211_reset_bss(ic);
1188 1.29.4.1 skrll ieee80211_scan_flush(ic);
1189 1.1 dyoung }
1190 1.19 dyoung if (ic->ic_auth->ia_detach != NULL)
1191 1.19 dyoung ic->ic_auth->ia_detach(ic);
1192 1.1 dyoung break;
1193 1.1 dyoung case IEEE80211_S_SCAN:
1194 1.1 dyoung switch (ostate) {
1195 1.1 dyoung case IEEE80211_S_INIT:
1196 1.29.4.1 skrll createibss:
1197 1.19 dyoung if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
1198 1.19 dyoung ic->ic_opmode == IEEE80211_M_IBSS ||
1199 1.19 dyoung ic->ic_opmode == IEEE80211_M_AHDEMO) &&
1200 1.1 dyoung ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
1201 1.1 dyoung /*
1202 1.29.4.1 skrll * Already have a channel; bypass the
1203 1.29.4.1 skrll * scan and startup immediately. Because
1204 1.29.4.1 skrll * of this explicitly sync the scanner state.
1205 1.1 dyoung */
1206 1.29.4.1 skrll ieee80211_scan_update(ic);
1207 1.1 dyoung ieee80211_create_ibss(ic, ic->ic_des_chan);
1208 1.1 dyoung } else {
1209 1.29.4.1 skrll ieee80211_check_scan(ic,
1210 1.29.4.1 skrll IEEE80211_SCAN_ACTIVE |
1211 1.29.4.1 skrll IEEE80211_SCAN_FLUSH,
1212 1.29.4.1 skrll IEEE80211_SCAN_FOREVER,
1213 1.29.4.1 skrll ic->ic_des_nssid, ic->ic_des_ssid);
1214 1.1 dyoung }
1215 1.1 dyoung break;
1216 1.1 dyoung case IEEE80211_S_SCAN:
1217 1.29.4.1 skrll case IEEE80211_S_AUTH:
1218 1.29.4.1 skrll case IEEE80211_S_ASSOC:
1219 1.19 dyoung /*
1220 1.29.4.1 skrll * These can happen either because of a timeout
1221 1.29.4.1 skrll * on an assoc/auth response or because of a
1222 1.29.4.1 skrll * change in state that requires a reset. For
1223 1.29.4.1 skrll * the former we're called with a non-zero arg
1224 1.29.4.1 skrll * that is the cause for the failure; pass this
1225 1.29.4.1 skrll * to the scan code so it can update state.
1226 1.29.4.1 skrll * Otherwise trigger a new scan unless we're in
1227 1.29.4.1 skrll * manual roaming mode in which case an application
1228 1.29.4.1 skrll * must issue an explicit scan request.
1229 1.19 dyoung */
1230 1.29.4.1 skrll if (arg != 0)
1231 1.29.4.1 skrll ieee80211_scan_assoc_fail(ic,
1232 1.29.4.1 skrll ic->ic_bss->ni_macaddr, arg);
1233 1.29.4.1 skrll if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
1234 1.29.4.1 skrll ieee80211_check_scan(ic,
1235 1.29.4.1 skrll IEEE80211_SCAN_ACTIVE,
1236 1.29.4.1 skrll IEEE80211_SCAN_FOREVER,
1237 1.29.4.1 skrll ic->ic_des_nssid, ic->ic_des_ssid);
1238 1.1 dyoung break;
1239 1.29.4.1 skrll case IEEE80211_S_RUN: /* beacon miss */
1240 1.29.4.1 skrll if (ic->ic_opmode == IEEE80211_M_STA) {
1241 1.29.4.1 skrll ieee80211_sta_leave(ic, ni);
1242 1.29.4.1 skrll ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */
1243 1.29.4.1 skrll if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
1244 1.29.4.1 skrll ieee80211_check_scan(ic,
1245 1.29.4.1 skrll IEEE80211_SCAN_ACTIVE,
1246 1.29.4.1 skrll IEEE80211_SCAN_FOREVER,
1247 1.29.4.1 skrll ic->ic_des_nssid,
1248 1.29.4.1 skrll ic->ic_des_ssid);
1249 1.29.4.1 skrll } else {
1250 1.29.4.1 skrll ieee80211_iterate_nodes(&ic->ic_sta,
1251 1.29.4.1 skrll sta_disassoc, ic);
1252 1.29.4.1 skrll goto createibss;
1253 1.1 dyoung }
1254 1.29.4.1 skrll break;
1255 1.29.4.1 skrll default:
1256 1.1 dyoung break;
1257 1.1 dyoung }
1258 1.1 dyoung break;
1259 1.1 dyoung case IEEE80211_S_AUTH:
1260 1.29.4.1 skrll IASSERT(ic->ic_opmode == IEEE80211_M_STA,
1261 1.29.4.1 skrll ("switch to %s state when operating in mode %u",
1262 1.29.4.1 skrll ieee80211_state_name[nstate], ic->ic_opmode));
1263 1.1 dyoung switch (ostate) {
1264 1.1 dyoung case IEEE80211_S_INIT:
1265 1.1 dyoung case IEEE80211_S_SCAN:
1266 1.1 dyoung IEEE80211_SEND_MGMT(ic, ni,
1267 1.1 dyoung IEEE80211_FC0_SUBTYPE_AUTH, 1);
1268 1.1 dyoung break;
1269 1.1 dyoung case IEEE80211_S_AUTH:
1270 1.1 dyoung case IEEE80211_S_ASSOC:
1271 1.29.4.1 skrll switch (arg & 0xff) {
1272 1.1 dyoung case IEEE80211_FC0_SUBTYPE_AUTH:
1273 1.1 dyoung /* ??? */
1274 1.1 dyoung IEEE80211_SEND_MGMT(ic, ni,
1275 1.1 dyoung IEEE80211_FC0_SUBTYPE_AUTH, 2);
1276 1.1 dyoung break;
1277 1.1 dyoung case IEEE80211_FC0_SUBTYPE_DEAUTH:
1278 1.29.4.1 skrll sta_authretry(ic, ni, arg>>8);
1279 1.1 dyoung break;
1280 1.1 dyoung }
1281 1.1 dyoung break;
1282 1.1 dyoung case IEEE80211_S_RUN:
1283 1.29.4.1 skrll switch (arg & 0xff) {
1284 1.1 dyoung case IEEE80211_FC0_SUBTYPE_AUTH:
1285 1.1 dyoung IEEE80211_SEND_MGMT(ic, ni,
1286 1.1 dyoung IEEE80211_FC0_SUBTYPE_AUTH, 2);
1287 1.1 dyoung ic->ic_state = ostate; /* stay RUN */
1288 1.1 dyoung break;
1289 1.1 dyoung case IEEE80211_FC0_SUBTYPE_DEAUTH:
1290 1.19 dyoung ieee80211_sta_leave(ic, ni);
1291 1.21 dyoung if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
1292 1.21 dyoung /* try to reauth */
1293 1.21 dyoung IEEE80211_SEND_MGMT(ic, ni,
1294 1.21 dyoung IEEE80211_FC0_SUBTYPE_AUTH, 1);
1295 1.21 dyoung }
1296 1.1 dyoung break;
1297 1.1 dyoung }
1298 1.1 dyoung break;
1299 1.29.4.1 skrll default:
1300 1.29.4.1 skrll break;
1301 1.1 dyoung }
1302 1.1 dyoung break;
1303 1.1 dyoung case IEEE80211_S_ASSOC:
1304 1.29.4.1 skrll IASSERT(ic->ic_opmode == IEEE80211_M_STA,
1305 1.29.4.1 skrll ("switch to %s state when operating in mode %u",
1306 1.29.4.1 skrll ieee80211_state_name[nstate], ic->ic_opmode));
1307 1.1 dyoung switch (ostate) {
1308 1.1 dyoung case IEEE80211_S_INIT:
1309 1.1 dyoung case IEEE80211_S_SCAN:
1310 1.11 mycroft IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
1311 1.19 dyoung "%s: invalid transition\n", __func__);
1312 1.1 dyoung break;
1313 1.1 dyoung case IEEE80211_S_AUTH:
1314 1.29.4.1 skrll case IEEE80211_S_ASSOC:
1315 1.1 dyoung IEEE80211_SEND_MGMT(ic, ni,
1316 1.1 dyoung IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
1317 1.1 dyoung break;
1318 1.1 dyoung case IEEE80211_S_RUN:
1319 1.19 dyoung ieee80211_sta_leave(ic, ni);
1320 1.21 dyoung if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
1321 1.29.4.1 skrll IEEE80211_SEND_MGMT(ic, ni, arg ?
1322 1.29.4.1 skrll IEEE80211_FC0_SUBTYPE_REASSOC_REQ :
1323 1.29.4.1 skrll IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
1324 1.21 dyoung }
1325 1.1 dyoung break;
1326 1.29.4.1 skrll default:
1327 1.29.4.1 skrll break;
1328 1.1 dyoung }
1329 1.1 dyoung break;
1330 1.1 dyoung case IEEE80211_S_RUN:
1331 1.19 dyoung if (ic->ic_flags & IEEE80211_F_WPA) {
1332 1.19 dyoung /* XXX validate prerequisites */
1333 1.19 dyoung }
1334 1.1 dyoung switch (ostate) {
1335 1.1 dyoung case IEEE80211_S_INIT:
1336 1.29.4.1 skrll if (ic->ic_opmode == IEEE80211_M_MONITOR ||
1337 1.29.4.1 skrll ic->ic_opmode == IEEE80211_M_WDS ||
1338 1.29.4.1 skrll ic->ic_opmode == IEEE80211_M_HOSTAP) {
1339 1.29.4.1 skrll /*
1340 1.29.4.1 skrll * Already have a channel; bypass the
1341 1.29.4.1 skrll * scan and startup immediately. Because
1342 1.29.4.1 skrll * of this explicitly sync the scanner state.
1343 1.29.4.1 skrll */
1344 1.29.4.1 skrll ieee80211_scan_update(ic);
1345 1.29.4.1 skrll ieee80211_create_ibss(ic,
1346 1.29.4.1 skrll ieee80211_ht_adjust_channel(ic,
1347 1.29.4.1 skrll ic->ic_curchan, ic->ic_flags_ext));
1348 1.19 dyoung break;
1349 1.29.4.1 skrll }
1350 1.19 dyoung /* fall thru... */
1351 1.1 dyoung case IEEE80211_S_AUTH:
1352 1.19 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
1353 1.19 dyoung "%s: invalid transition\n", __func__);
1354 1.19 dyoung /* fall thru... */
1355 1.1 dyoung case IEEE80211_S_RUN:
1356 1.1 dyoung break;
1357 1.1 dyoung case IEEE80211_S_SCAN: /* adhoc/hostap mode */
1358 1.1 dyoung case IEEE80211_S_ASSOC: /* infra mode */
1359 1.7 dyoung IASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates,
1360 1.19 dyoung ("%s: bogus xmit rate %u setup\n", __func__,
1361 1.1 dyoung ni->ni_txrate));
1362 1.14 mycroft #ifdef IEEE80211_DEBUG
1363 1.13 mycroft if (ieee80211_msg_debug(ic)) {
1364 1.1 dyoung if (ic->ic_opmode == IEEE80211_M_STA)
1365 1.19 dyoung if_printf(ifp, "associated ");
1366 1.1 dyoung else
1367 1.19 dyoung if_printf(ifp, "synchronized ");
1368 1.1 dyoung printf("with %s ssid ",
1369 1.1 dyoung ether_sprintf(ni->ni_bssid));
1370 1.1 dyoung ieee80211_print_essid(ic->ic_bss->ni_essid,
1371 1.1 dyoung ni->ni_esslen);
1372 1.1 dyoung printf(" channel %d start %uMb\n",
1373 1.23 skrll ieee80211_chan2ieee(ic, ic->ic_curchan),
1374 1.1 dyoung IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate]));
1375 1.1 dyoung }
1376 1.14 mycroft #endif
1377 1.29.4.1 skrll if (ic->ic_opmode == IEEE80211_M_STA) {
1378 1.29.4.1 skrll ieee80211_scan_assoc_success(ic,
1379 1.29.4.1 skrll ni->ni_macaddr);
1380 1.19 dyoung ieee80211_notify_node_join(ic, ni,
1381 1.19 dyoung arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
1382 1.29.4.1 skrll }
1383 1.19 dyoung (*ifp->if_start)(ifp); /* XXX not authorized yet */
1384 1.1 dyoung break;
1385 1.29.4.1 skrll default:
1386 1.29.4.1 skrll break;
1387 1.29.4.1 skrll }
1388 1.29.4.1 skrll if (ostate != IEEE80211_S_RUN &&
1389 1.29.4.1 skrll ic->ic_opmode == IEEE80211_M_STA &&
1390 1.29.4.1 skrll (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS)) {
1391 1.29.4.1 skrll /*
1392 1.29.4.1 skrll * Start s/w beacon miss timer for devices w/o
1393 1.29.4.1 skrll * hardware support. We fudge a bit here since
1394 1.29.4.1 skrll * we're doing this in software.
1395 1.29.4.1 skrll */
1396 1.29.4.1 skrll ic->ic_swbmiss_period = IEEE80211_TU_TO_TICKS(
1397 1.29.4.1 skrll 2 * ic->ic_bmissthreshold * ni->ni_intval);
1398 1.29.4.1 skrll ic->ic_swbmiss_count = 0;
1399 1.29.4.1 skrll callout_reset(&ic->ic_swbmiss, ic->ic_swbmiss_period,
1400 1.29.4.1 skrll ieee80211_swbmiss, ic);
1401 1.1 dyoung }
1402 1.19 dyoung /*
1403 1.19 dyoung * Start/stop the authenticator when operating as an
1404 1.19 dyoung * AP. We delay until here to allow configuration to
1405 1.19 dyoung * happen out of order.
1406 1.19 dyoung */
1407 1.19 dyoung if (ic->ic_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */
1408 1.19 dyoung ic->ic_auth->ia_attach != NULL) {
1409 1.19 dyoung /* XXX check failure */
1410 1.19 dyoung ic->ic_auth->ia_attach(ic);
1411 1.19 dyoung } else if (ic->ic_auth->ia_detach != NULL) {
1412 1.19 dyoung ic->ic_auth->ia_detach(ic);
1413 1.19 dyoung }
1414 1.19 dyoung /*
1415 1.19 dyoung * When 802.1x is not in use mark the port authorized
1416 1.19 dyoung * at this point so traffic can flow.
1417 1.19 dyoung */
1418 1.19 dyoung if (ni->ni_authmode != IEEE80211_AUTH_8021X)
1419 1.23 skrll ieee80211_node_authorize(ni);
1420 1.19 dyoung /*
1421 1.19 dyoung * Enable inactivity processing.
1422 1.19 dyoung * XXX
1423 1.19 dyoung */
1424 1.29.4.1 skrll callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
1425 1.29.4.1 skrll ieee80211_node_timeout, ic);
1426 1.29.4.1 skrll break;
1427 1.29.4.1 skrll default:
1428 1.1 dyoung break;
1429 1.1 dyoung }
1430 1.1 dyoung return 0;
1431 1.1 dyoung }
1432