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