2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
11 * Copyright (c) 2001 Atsushi Onoe
12 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. The name of the author may not be used to endorse or promote products
24 * derived from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
33 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 * IEEE 802.11 protocol support
46 #include "net80211_impl.h"
49 #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */
50 #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */
52 #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
54 const char *ieee80211_mgt_subtype_name
[] = {
55 "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
56 "probe_req", "probe_resp", "reserved#6", "reserved#7",
57 "beacon", "atim", "disassoc", "auth",
58 "deauth", "reserved#13", "reserved#14", "reserved#15"
60 const char *ieee80211_ctl_subtype_name
[] = {
61 "reserved#0", "reserved#1", "reserved#2", "reserved#3",
62 "reserved#3", "reserved#5", "reserved#6", "reserved#7",
63 "reserved#8", "reserved#9", "ps_poll", "rts",
64 "cts", "ack", "cf_end", "cf_end_ack"
66 const char *ieee80211_state_name
[IEEE80211_S_MAX
] = {
67 "INIT", /* IEEE80211_S_INIT */
68 "SCAN", /* IEEE80211_S_SCAN */
69 "AUTH", /* IEEE80211_S_AUTH */
70 "ASSOC", /* IEEE80211_S_ASSOC */
71 "RUN" /* IEEE80211_S_RUN */
73 const char *ieee80211_wme_acnames
[] = {
81 static int ieee80211_newstate(ieee80211com_t
*, enum ieee80211_state
, int);
84 * Initialize the interface softc, ic, with protocol management
85 * related data structures and functions.
88 ieee80211_proto_attach(ieee80211com_t
*ic
)
90 struct ieee80211_impl
*im
= ic
->ic_private
;
92 ic
->ic_rtsthreshold
= IEEE80211_RTS_DEFAULT
;
93 ic
->ic_fragthreshold
= IEEE80211_FRAG_DEFAULT
;
94 ic
->ic_fixed_rate
= IEEE80211_FIXED_RATE_NONE
;
95 ic
->ic_protmode
= IEEE80211_PROT_CTSONLY
;
96 im
->im_bmiss_max
= IEEE80211_BMISS_MAX
;
98 ic
->ic_wme
.wme_hipri_switch_hysteresis
=
99 AGGRESSIVE_MODE_SWITCH_HYSTERESIS
;
101 /* protocol state change handler */
102 ic
->ic_newstate
= ieee80211_newstate
;
104 /* initialize management frame handlers */
105 ic
->ic_recv_mgmt
= ieee80211_recv_mgmt
;
106 ic
->ic_send_mgmt
= ieee80211_send_mgmt
;
110 * Print a 802.11 frame header
113 ieee80211_dump_pkt(const uint8_t *buf
, int32_t len
, int32_t rate
, int32_t rssi
)
115 struct ieee80211_frame
*wh
;
120 bzero(buf1
, sizeof (buf1
));
121 bzero(buf2
, sizeof (buf2
));
122 wh
= (struct ieee80211_frame
*)buf
;
123 switch (wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
) {
124 case IEEE80211_FC1_DIR_NODS
:
125 (void) snprintf(buf2
, sizeof (buf2
), "NODS %s",
126 ieee80211_macaddr_sprintf(wh
->i_addr2
));
127 (void) strncat(buf1
, buf2
, sizeof (buf2
));
128 (void) snprintf(buf2
, sizeof (buf2
), "->%s",
129 ieee80211_macaddr_sprintf(wh
->i_addr1
));
130 (void) strncat(buf1
, buf2
, sizeof (buf2
));
131 (void) snprintf(buf2
, sizeof (buf2
), "(%s)",
132 ieee80211_macaddr_sprintf(wh
->i_addr3
));
133 (void) strncat(buf1
, buf2
, sizeof (buf2
));
135 case IEEE80211_FC1_DIR_TODS
:
136 (void) snprintf(buf2
, sizeof (buf2
), "TODS %s",
137 ieee80211_macaddr_sprintf(wh
->i_addr2
));
138 (void) strncat(buf1
, buf2
, sizeof (buf2
));
139 (void) snprintf(buf2
, sizeof (buf2
), "->%s",
140 ieee80211_macaddr_sprintf(wh
->i_addr3
));
141 (void) strncat(buf1
, buf2
, sizeof (buf2
));
142 (void) snprintf(buf2
, sizeof (buf2
), "(%s)",
143 ieee80211_macaddr_sprintf(wh
->i_addr1
));
144 (void) strncat(buf1
, buf2
, sizeof (buf2
));
146 case IEEE80211_FC1_DIR_FROMDS
:
147 (void) snprintf(buf2
, sizeof (buf2
), "FRDS %s",
148 ieee80211_macaddr_sprintf(wh
->i_addr3
));
149 (void) strncat(buf1
, buf2
, sizeof (buf2
));
150 (void) snprintf(buf2
, sizeof (buf2
), "->%s",
151 ieee80211_macaddr_sprintf(wh
->i_addr1
));
152 (void) strncat(buf1
, buf2
, sizeof (buf2
));
153 (void) snprintf(buf2
, sizeof (buf2
), "(%s)",
154 ieee80211_macaddr_sprintf(wh
->i_addr2
));
155 (void) strncat(buf1
, buf2
, sizeof (buf2
));
157 case IEEE80211_FC1_DIR_DSTODS
:
158 (void) snprintf(buf2
, sizeof (buf2
), "DSDS %s",
159 ieee80211_macaddr_sprintf((uint8_t *)&wh
[1]));
160 (void) strncat(buf1
, buf2
, sizeof (buf2
));
161 (void) snprintf(buf2
, sizeof (buf2
), "->%s ",
162 ieee80211_macaddr_sprintf(wh
->i_addr3
));
163 (void) strncat(buf1
, buf2
, sizeof (buf2
));
164 (void) snprintf(buf2
, sizeof (buf2
), "%s",
165 ieee80211_macaddr_sprintf(wh
->i_addr2
));
166 (void) strncat(buf1
, buf2
, sizeof (buf2
));
167 (void) snprintf(buf2
, sizeof (buf2
), "->%s",
168 ieee80211_macaddr_sprintf(wh
->i_addr1
));
169 (void) strncat(buf1
, buf2
, sizeof (buf2
));
172 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_dump_pkt(): %s", buf1
);
173 bzero(buf1
, sizeof (buf1
));
175 switch (wh
->i_fc
[0] & IEEE80211_FC0_TYPE_MASK
) {
176 case IEEE80211_FC0_TYPE_DATA
:
177 (void) sprintf(buf2
, "data");
179 case IEEE80211_FC0_TYPE_MGT
:
180 (void) snprintf(buf2
, sizeof (buf2
), "%s",
181 ieee80211_mgt_subtype_name
[
182 (wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
)
183 >> IEEE80211_FC0_SUBTYPE_SHIFT
]);
186 (void) snprintf(buf2
, sizeof (buf2
), "type#%d",
187 wh
->i_fc
[0] & IEEE80211_FC0_TYPE_MASK
);
190 (void) strncat(buf1
, buf2
, sizeof (buf2
));
191 if (wh
->i_fc
[1] & IEEE80211_FC1_WEP
) {
192 (void) sprintf(buf2
, " WEP");
193 (void) strcat(buf1
, buf2
);
196 (void) snprintf(buf2
, sizeof (buf2
), " %dM", rate
/ 2);
197 (void) strncat(buf1
, buf2
, sizeof (buf2
));
200 (void) snprintf(buf2
, sizeof (buf2
), " +%d", rssi
);
201 (void) strncat(buf1
, buf2
, sizeof (buf2
));
203 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_dump_pkt(): %s", buf1
);
204 bzero(buf1
, sizeof (buf1
));
207 for (i
= 0; i
< (len
> 40 ? 40 : len
); i
++) {
209 (void) strcat(buf1
, " ");
210 (void) snprintf(buf2
, 3, "%02x", buf
[i
]);
211 (void) strncat(buf1
, buf2
, 3);
213 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_dump_pkt(): %s",
219 * Adjust/Fix the specified node's rate table
222 * flag IEEE80211_F_DOSORT : sort the node's rate table
223 * IEEE80211_F_DONEGO : mark a rate as basic rate if it is
224 * a device's basic rate
225 * IEEE80211_F_DODEL : delete rates not supported by the device
226 * IEEE80211_F_DOFRATE: check if the fixed rate is supported by
229 * The highest bit of returned rate value is set to 1 on failure.
232 ieee80211_fix_rate(ieee80211_node_t
*in
,
233 struct ieee80211_rateset
*nrs
, int flags
)
235 ieee80211com_t
*ic
= in
->in_ic
;
236 struct ieee80211_rateset
*srs
;
245 * If the fixed rate check was requested but no
246 * fixed has been defined then just remove it.
248 if ((flags
& IEEE80211_F_DOFRATE
) &&
249 (ic
->ic_fixed_rate
== IEEE80211_FIXED_RATE_NONE
)) {
250 flags
&= ~IEEE80211_F_DOFRATE
;
252 if (in
->in_chan
== IEEE80211_CHAN_ANYC
) {
253 return (IEEE80211_RATE_BASIC
);
255 okrate
= badrate
= fixedrate
= 0;
256 srs
= &ic
->ic_sup_rates
[ieee80211_chan2mode(ic
, in
->in_chan
)];
257 for (i
= 0; i
< nrs
->ir_nrates
; ) {
261 if (flags
& IEEE80211_F_DOSORT
) {
265 for (j
= i
+ 1; j
< nrs
->ir_nrates
; j
++) {
266 if (IEEE80211_RV(nrs
->ir_rates
[i
]) >
267 IEEE80211_RV(nrs
->ir_rates
[j
])) {
268 r
= nrs
->ir_rates
[i
];
269 nrs
->ir_rates
[i
] = nrs
->ir_rates
[j
];
270 nrs
->ir_rates
[j
] = r
;
274 r
= IEEE80211_RV(nrs
->ir_rates
[i
]);
278 * Check against supported rates.
280 for (j
= 0; j
< srs
->ir_nrates
; j
++) {
281 if (r
== IEEE80211_RV(srs
->ir_rates
[j
])) {
283 * Overwrite with the supported rate
284 * value so any basic rate bit is set.
285 * This insures that response we send
286 * to stations have the necessary basic
289 if (flags
& IEEE80211_F_DONEGO
)
290 nrs
->ir_rates
[i
] = srs
->ir_rates
[j
];
294 if (j
== srs
->ir_nrates
) {
296 * A rate in the node's rate set is not
297 * supported. We just discard/ignore the rate.
298 * Note that this is important for 11b stations
299 * when they want to associate with an 11g AP.
304 if (flags
& IEEE80211_F_DODEL
) {
306 * Delete unacceptable rates.
310 for (j
= i
; j
< nrs
->ir_nrates
; j
++)
311 nrs
->ir_rates
[j
] = nrs
->ir_rates
[j
+ 1];
312 nrs
->ir_rates
[j
] = 0;
316 if (flags
& IEEE80211_F_DOFRATE
) {
318 * Check any fixed rate is included.
320 if (r
== ic
->ic_fixed_rate
)
324 okrate
= nrs
->ir_rates
[i
];
327 if (okrate
== 0 || ((flags
& IEEE80211_F_DOFRATE
) && fixedrate
== 0))
328 return (badrate
| IEEE80211_RATE_BASIC
);
330 return (IEEE80211_RV(okrate
));
334 * Reset 11g-related state.
337 ieee80211_reset_erp(ieee80211com_t
*ic
)
339 ic
->ic_flags
&= ~IEEE80211_F_USEPROT
;
341 * Short slot time is enabled only when operating in 11g
342 * and not in an IBSS. We must also honor whether or not
343 * the driver is capable of doing it.
345 ieee80211_set_shortslottime(ic
,
346 ic
->ic_curmode
== IEEE80211_MODE_11A
);
348 * Set short preamble and ERP barker-preamble flags.
350 if (ic
->ic_curmode
== IEEE80211_MODE_11A
||
351 (ic
->ic_caps
& IEEE80211_C_SHPREAMBLE
)) {
352 ic
->ic_flags
|= IEEE80211_F_SHPREAMBLE
;
353 ic
->ic_flags
&= ~IEEE80211_F_USEBARKER
;
355 ic
->ic_flags
&= ~IEEE80211_F_SHPREAMBLE
;
356 ic
->ic_flags
|= IEEE80211_F_USEBARKER
;
361 * Change current channel to be the next available channel
364 ieee80211_reset_chan(ieee80211com_t
*ic
)
366 struct ieee80211_channel
*ch
= ic
->ic_curchan
;
370 if (++ch
> &ic
->ic_sup_channels
[IEEE80211_CHAN_MAX
])
371 ch
= &ic
->ic_sup_channels
[0];
372 if (ieee80211_isset(ic
->ic_chan_active
,
373 ieee80211_chan2ieee(ic
, ch
))) {
376 } while (ch
!= ic
->ic_curchan
);
378 IEEE80211_UNLOCK(ic
);
382 * Set the short slot time state and notify the driver.
385 ieee80211_set_shortslottime(ieee80211com_t
*ic
, boolean_t on
)
388 ic
->ic_flags
|= IEEE80211_F_SHSLOT
;
390 ic
->ic_flags
&= ~IEEE80211_F_SHSLOT
;
392 if (ic
->ic_set_shortslot
!= NULL
)
393 ic
->ic_set_shortslot(ic
, on
);
397 * Mark the basic rates for the 11g rate table based on the
398 * operating mode. For real 11g we mark all the 11b rates
399 * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
400 * 11b rates. There's also a pseudo 11a-mode used to mark only
401 * the basic OFDM rates.
404 ieee80211_setbasicrates(struct ieee80211_rateset
*rs
,
405 enum ieee80211_phymode mode
)
407 static const struct ieee80211_rateset basic
[] = {
408 { 0 }, /* IEEE80211_MODE_AUTO */
409 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
410 { 2, { 2, 4} }, /* IEEE80211_MODE_11B */
411 { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G mixed b/g */
412 { 0 }, /* IEEE80211_MODE_FH */
413 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_TURBO_A */
414 { 4, { 2, 4, 11, 22 } },
415 /* IEEE80211_MODE_TURBO_G (mixed b/g) */
416 { 0 }, /* IEEE80211_MODE_STURBO_A */
417 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11NA */
418 /* IEEE80211_MODE_11NG (mixed b/g) */
419 { 7, { 2, 4, 11, 22, 12, 24, 48 } }
423 ASSERT(mode
< IEEE80211_MODE_MAX
);
424 for (i
= 0; i
< rs
->ir_nrates
; i
++) {
425 rs
->ir_rates
[i
] &= IEEE80211_RATE_VAL
;
426 for (j
= 0; j
< basic
[mode
].ir_nrates
; j
++) {
427 if (basic
[mode
].ir_rates
[j
] == rs
->ir_rates
[i
]) {
428 rs
->ir_rates
[i
] |= IEEE80211_RATE_BASIC
;
436 * WME protocol support. The following parameters come from the spec.
438 typedef struct phyParamType
{
446 static const paramType phyParamForAC_BE
[IEEE80211_MODE_MAX
] = {
447 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_AUTO */
448 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11A */
449 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11B */
450 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11G */
451 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_FH */
452 { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
453 { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
454 { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
455 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NA */
456 { 3, 4, 6, 0, 0 } /* IEEE80211_MODE_11NG */
458 static const struct phyParamType phyParamForAC_BK
[IEEE80211_MODE_MAX
] = {
459 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
460 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
461 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
462 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
463 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
464 { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
465 { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
466 { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
467 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
468 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
470 static const struct phyParamType phyParamForAC_VI
[IEEE80211_MODE_MAX
] = {
471 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
472 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
473 { 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
474 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
475 { 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
476 { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
477 { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
478 { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
479 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
480 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
482 static const struct phyParamType phyParamForAC_VO
[IEEE80211_MODE_MAX
] = {
483 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
484 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
485 { 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
486 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
487 { 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
488 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
489 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
490 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
491 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
492 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
495 static const struct phyParamType bssPhyParamForAC_BE
[IEEE80211_MODE_MAX
] = {
496 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
497 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
498 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
499 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
500 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
501 { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
502 { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
503 { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
504 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
505 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
507 static const struct phyParamType bssPhyParamForAC_VI
[IEEE80211_MODE_MAX
] = {
508 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
509 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
510 { 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
511 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
512 { 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
513 { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
514 { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
515 { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
516 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
517 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
519 static const struct phyParamType bssPhyParamForAC_VO
[IEEE80211_MODE_MAX
] = {
520 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
521 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
522 { 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
523 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
524 { 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
525 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
526 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
527 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
528 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
529 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
533 ieee80211_wme_initparams(struct ieee80211com
*ic
)
535 struct ieee80211_wme_state
*wme
= &ic
->ic_wme
;
536 const paramType
*pPhyParam
, *pBssPhyParam
;
537 struct wmeParams
*wmep
;
538 enum ieee80211_phymode mode
;
541 if ((ic
->ic_caps
& IEEE80211_C_WME
) == 0)
545 * Select mode; we can be called early in which case we
546 * always use auto mode. We know we'll be called when
547 * entering the RUN state with bsschan setup properly
548 * so state will eventually get set correctly
550 if (ic
->ic_curchan
!= IEEE80211_CHAN_ANYC
)
551 mode
= ieee80211_chan2mode(ic
, ic
->ic_curchan
);
553 mode
= IEEE80211_MODE_AUTO
;
554 for (i
= 0; i
< WME_NUM_AC
; i
++) {
557 pPhyParam
= &phyParamForAC_BK
[mode
];
558 pBssPhyParam
= &phyParamForAC_BK
[mode
];
561 pPhyParam
= &phyParamForAC_VI
[mode
];
562 pBssPhyParam
= &bssPhyParamForAC_VI
[mode
];
565 pPhyParam
= &phyParamForAC_VO
[mode
];
566 pBssPhyParam
= &bssPhyParamForAC_VO
[mode
];
570 pPhyParam
= &phyParamForAC_BE
[mode
];
571 pBssPhyParam
= &bssPhyParamForAC_BE
[mode
];
575 wmep
= &wme
->wme_wmeChanParams
.cap_wmeParams
[i
];
576 if (ic
->ic_opmode
== IEEE80211_M_HOSTAP
) {
577 wmep
->wmep_acm
= pPhyParam
->acm
;
578 wmep
->wmep_aifsn
= pPhyParam
->aifsn
;
579 wmep
->wmep_logcwmin
= pPhyParam
->logcwmin
;
580 wmep
->wmep_logcwmax
= pPhyParam
->logcwmax
;
581 wmep
->wmep_txopLimit
= pPhyParam
->txopLimit
;
583 wmep
->wmep_acm
= pBssPhyParam
->acm
;
584 wmep
->wmep_aifsn
= pBssPhyParam
->aifsn
;
585 wmep
->wmep_logcwmin
= pBssPhyParam
->logcwmin
;
586 wmep
->wmep_logcwmax
= pBssPhyParam
->logcwmax
;
587 wmep
->wmep_txopLimit
= pBssPhyParam
->txopLimit
;
590 ieee80211_dbg(IEEE80211_MSG_WME
, "ieee80211_wme_initparams: "
591 "%s chan [acm %u aifsn %u log2(cwmin) %u "
592 "log2(cwmax) %u txpoLimit %u]\n",
593 ieee80211_wme_acnames
[i
],
598 wmep
->wmep_txopLimit
);
600 wmep
= &wme
->wme_wmeBssChanParams
.cap_wmeParams
[i
];
601 wmep
->wmep_acm
= pBssPhyParam
->acm
;
602 wmep
->wmep_aifsn
= pBssPhyParam
->aifsn
;
603 wmep
->wmep_logcwmin
= pBssPhyParam
->logcwmin
;
604 wmep
->wmep_logcwmax
= pBssPhyParam
->logcwmax
;
605 wmep
->wmep_txopLimit
= pBssPhyParam
->txopLimit
;
606 ieee80211_dbg(IEEE80211_MSG_WME
, "ieee80211_wme_initparams: "
607 "%s bss [acm %u aifsn %u log2(cwmin) %u "
608 "log2(cwmax) %u txpoLimit %u]\n",
609 ieee80211_wme_acnames
[i
],
614 wmep
->wmep_txopLimit
);
616 /* NB: check ic_bss to avoid NULL deref on initial attach */
617 if (ic
->ic_bss
!= NULL
) {
619 * Calculate agressive mode switching threshold based
620 * on beacon interval. This doesn't need locking since
621 * we're only called before entering the RUN state at
622 * which point we start sending beacon frames.
624 wme
->wme_hipri_switch_thresh
=
625 (HIGH_PRI_SWITCH_THRESH
* ic
->ic_bss
->in_intval
) / 100;
626 ieee80211_wme_updateparams(ic
);
631 * Update WME parameters for ourself and the BSS.
634 ieee80211_wme_updateparams(struct ieee80211com
*ic
)
636 static const paramType phyParam
[IEEE80211_MODE_MAX
] = {
637 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_AUTO */
638 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11A */
639 { 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_11B */
640 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11G */
641 { 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_FH */
642 { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_A */
643 { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_G */
644 { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_STURBO_A */
645 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NA */
646 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NG */
648 struct ieee80211_wme_state
*wme
= &ic
->ic_wme
;
649 const struct wmeParams
*wmep
;
650 struct wmeParams
*chanp
, *bssp
;
651 enum ieee80211_phymode mode
;
654 if ((ic
->ic_caps
& IEEE80211_C_WME
) == 0)
657 /* set up the channel access parameters for the physical device */
658 for (i
= 0; i
< WME_NUM_AC
; i
++) {
659 chanp
= &wme
->wme_chanParams
.cap_wmeParams
[i
];
660 wmep
= &wme
->wme_wmeChanParams
.cap_wmeParams
[i
];
661 chanp
->wmep_aifsn
= wmep
->wmep_aifsn
;
662 chanp
->wmep_logcwmin
= wmep
->wmep_logcwmin
;
663 chanp
->wmep_logcwmax
= wmep
->wmep_logcwmax
;
664 chanp
->wmep_txopLimit
= wmep
->wmep_txopLimit
;
666 chanp
= &wme
->wme_bssChanParams
.cap_wmeParams
[i
];
667 wmep
= &wme
->wme_wmeBssChanParams
.cap_wmeParams
[i
];
668 chanp
->wmep_aifsn
= wmep
->wmep_aifsn
;
669 chanp
->wmep_logcwmin
= wmep
->wmep_logcwmin
;
670 chanp
->wmep_logcwmax
= wmep
->wmep_logcwmax
;
671 chanp
->wmep_txopLimit
= wmep
->wmep_txopLimit
;
675 * Select mode; we can be called early in which case we
676 * always use auto mode. We know we'll be called when
677 * entering the RUN state with bsschan setup properly
678 * so state will eventually get set correctly
680 if (ic
->ic_curchan
!= IEEE80211_CHAN_ANYC
)
681 mode
= ieee80211_chan2mode(ic
, ic
->ic_curchan
);
683 mode
= IEEE80211_MODE_AUTO
;
686 * This implements agressive mode as found in certain
687 * vendors' AP's. When there is significant high
688 * priority (VI/VO) traffic in the BSS throttle back BE
689 * traffic by using conservative parameters. Otherwise
690 * BE uses agressive params to optimize performance of
691 * legacy/non-QoS traffic.
693 if ((ic
->ic_opmode
== IEEE80211_M_HOSTAP
&&
694 (wme
->wme_flags
& WME_F_AGGRMODE
) != 0) ||
695 (ic
->ic_opmode
== IEEE80211_M_STA
&&
696 (ic
->ic_bss
->in_flags
& IEEE80211_NODE_QOS
) == 0) ||
697 (ic
->ic_flags
& IEEE80211_F_WME
) == 0) {
698 chanp
= &wme
->wme_chanParams
.cap_wmeParams
[WME_AC_BE
];
699 bssp
= &wme
->wme_bssChanParams
.cap_wmeParams
[WME_AC_BE
];
701 chanp
->wmep_aifsn
= bssp
->wmep_aifsn
= phyParam
[mode
].aifsn
;
702 chanp
->wmep_logcwmin
= bssp
->wmep_logcwmin
=
703 phyParam
[mode
].logcwmin
;
704 chanp
->wmep_logcwmax
= bssp
->wmep_logcwmax
=
705 phyParam
[mode
].logcwmax
;
706 chanp
->wmep_txopLimit
= bssp
->wmep_txopLimit
=
707 (ic
->ic_flags
& IEEE80211_F_BURST
) ?
708 phyParam
[mode
].txopLimit
: 0;
709 ieee80211_dbg(IEEE80211_MSG_WME
,
710 "ieee80211_wme_updateparams_locked: "
711 "%s [acm %u aifsn %u log2(cwmin) %u "
712 "log2(cwmax) %u txpoLimit %u]\n",
713 ieee80211_wme_acnames
[WME_AC_BE
],
716 chanp
->wmep_logcwmin
,
717 chanp
->wmep_logcwmax
,
718 chanp
->wmep_txopLimit
);
723 ieee80211_dbg(IEEE80211_MSG_WME
, "ieee80211_wme_updateparams(): "
724 "WME params updated, cap_info 0x%x\n",
725 ic
->ic_opmode
== IEEE80211_M_STA
?
726 wme
->wme_wmeChanParams
.cap_info
:
727 wme
->wme_bssChanParams
.cap_info
);
731 * Process STA mode beacon miss events. Send a direct probe request
732 * frame to the current ap bmiss_max times (w/o answer) before
733 * scanning for a new ap.
736 ieee80211_beacon_miss(ieee80211com_t
*ic
)
738 ieee80211_impl_t
*im
= ic
->ic_private
;
740 if (ic
->ic_flags
& IEEE80211_F_SCAN
)
742 ieee80211_dbg(IEEE80211_MSG_STATE
| IEEE80211_MSG_DEBUG
,
743 "%s\n", "beacon miss");
746 * Our handling is only meaningful for stations that are
747 * associated; any other conditions else will be handled
748 * through different means (e.g. the tx timeout on mgt frames).
750 if (ic
->ic_opmode
!= IEEE80211_M_STA
||
751 ic
->ic_state
!= IEEE80211_S_RUN
) {
756 if (++im
->im_bmiss_count
< im
->im_bmiss_max
) {
758 * Send a directed probe req before falling back to a scan;
759 * if we receive a response ic_bmiss_count will be reset.
760 * Some cards mistakenly report beacon miss so this avoids
761 * the expensive scan if the ap is still there.
763 IEEE80211_UNLOCK(ic
);
764 (void) ieee80211_send_probereq(ic
->ic_bss
, ic
->ic_macaddr
,
765 ic
->ic_bss
->in_bssid
, ic
->ic_bss
->in_bssid
,
766 ic
->ic_bss
->in_essid
, ic
->ic_bss
->in_esslen
,
767 ic
->ic_opt_ie
, ic
->ic_opt_ie_len
);
770 im
->im_bmiss_count
= 0;
771 IEEE80211_UNLOCK(ic
);
772 ieee80211_new_state(ic
, IEEE80211_S_SCAN
, 0);
776 * Manage state transition between INIT | AUTH | ASSOC | RUN.
779 ieee80211_newstate(ieee80211com_t
*ic
, enum ieee80211_state nstate
, int arg
)
781 struct ieee80211_impl
*im
= ic
->ic_private
;
782 ieee80211_node_t
*in
;
783 enum ieee80211_state ostate
;
784 wifi_data_t wd
= { 0 };
787 ostate
= ic
->ic_state
;
788 ieee80211_dbg(IEEE80211_MSG_STATE
, "ieee80211_newstate(): "
790 ieee80211_state_name
[ostate
], ieee80211_state_name
[nstate
]);
791 ic
->ic_state
= nstate
;
793 im
->im_swbmiss_period
= 0; /* Reset software beacon miss period */
796 case IEEE80211_S_INIT
:
797 IEEE80211_UNLOCK(ic
);
799 case IEEE80211_S_INIT
:
801 case IEEE80211_S_SCAN
:
802 ieee80211_cancel_scan(ic
);
804 case IEEE80211_S_AUTH
:
806 case IEEE80211_S_ASSOC
:
807 if (ic
->ic_opmode
== IEEE80211_M_STA
) {
808 IEEE80211_SEND_MGMT(ic
, in
,
809 IEEE80211_FC0_SUBTYPE_DEAUTH
,
810 IEEE80211_REASON_AUTH_LEAVE
);
813 case IEEE80211_S_RUN
:
814 switch (ic
->ic_opmode
) {
815 case IEEE80211_M_STA
:
816 IEEE80211_SEND_MGMT(ic
, in
,
817 IEEE80211_FC0_SUBTYPE_DEAUTH
,
818 IEEE80211_REASON_AUTH_LEAVE
);
819 ieee80211_sta_leave(ic
, in
);
821 case IEEE80211_M_IBSS
:
822 ieee80211_notify_node_leave(ic
, in
);
830 im
->im_mgt_timer
= 0;
831 ieee80211_reset_bss(ic
);
833 case IEEE80211_S_SCAN
:
835 case IEEE80211_S_INIT
:
836 IEEE80211_UNLOCK(ic
);
837 ieee80211_begin_scan(ic
, (arg
== 0) ? B_FALSE
: B_TRUE
);
839 case IEEE80211_S_SCAN
:
841 * Scan next. If doing an active scan and the
842 * channel is not marked passive-only then send
843 * a probe request. Otherwise just listen for
844 * beacons on the channel.
846 if ((ic
->ic_flags
& IEEE80211_F_ASCAN
) &&
847 !IEEE80211_IS_CHAN_PASSIVE(ic
->ic_curchan
)) {
848 IEEE80211_UNLOCK(ic
);
849 (void) ieee80211_send_probereq(in
,
850 ic
->ic_macaddr
, wifi_bcastaddr
,
852 ic
->ic_des_essid
, ic
->ic_des_esslen
,
853 ic
->ic_opt_ie
, ic
->ic_opt_ie_len
);
857 case IEEE80211_S_RUN
:
859 ieee80211_dbg(IEEE80211_MSG_STATE
,
860 "no recent beacons from %s, rescanning\n",
861 ieee80211_macaddr_sprintf(in
->in_macaddr
));
862 IEEE80211_UNLOCK(ic
);
863 ieee80211_sta_leave(ic
, in
);
865 ic
->ic_flags
&= ~IEEE80211_F_SIBSS
;
867 case IEEE80211_S_AUTH
:
868 case IEEE80211_S_ASSOC
:
869 /* timeout restart scan */
870 in
= ieee80211_find_node(&ic
->ic_scan
,
871 ic
->ic_bss
->in_macaddr
);
874 ieee80211_unref_node(&in
);
879 case IEEE80211_S_AUTH
:
880 ASSERT(ic
->ic_opmode
== IEEE80211_M_STA
);
882 case IEEE80211_S_INIT
:
883 case IEEE80211_S_SCAN
:
884 IEEE80211_UNLOCK(ic
);
885 IEEE80211_SEND_MGMT(ic
, in
, IEEE80211_FC0_SUBTYPE_AUTH
,
888 case IEEE80211_S_AUTH
:
889 case IEEE80211_S_ASSOC
:
891 case IEEE80211_FC0_SUBTYPE_AUTH
:
892 IEEE80211_UNLOCK(ic
);
893 IEEE80211_SEND_MGMT(ic
, in
,
894 IEEE80211_FC0_SUBTYPE_AUTH
, 2);
896 case IEEE80211_FC0_SUBTYPE_DEAUTH
:
897 /* ignore and retry scan on timeout */
901 case IEEE80211_S_RUN
:
903 case IEEE80211_FC0_SUBTYPE_AUTH
:
904 ic
->ic_state
= ostate
; /* stay RUN */
905 IEEE80211_UNLOCK(ic
);
906 IEEE80211_SEND_MGMT(ic
, in
,
907 IEEE80211_FC0_SUBTYPE_AUTH
, 2);
909 case IEEE80211_FC0_SUBTYPE_DEAUTH
:
910 IEEE80211_UNLOCK(ic
);
911 ieee80211_sta_leave(ic
, in
);
913 IEEE80211_SEND_MGMT(ic
, in
,
914 IEEE80211_FC0_SUBTYPE_AUTH
, 1);
920 case IEEE80211_S_ASSOC
:
921 ASSERT(ic
->ic_opmode
== IEEE80211_M_STA
||
922 ic
->ic_opmode
== IEEE80211_M_IBSS
);
924 case IEEE80211_S_INIT
:
925 case IEEE80211_S_SCAN
:
926 case IEEE80211_S_ASSOC
:
927 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_newstate: "
928 "invalid transition\n");
930 case IEEE80211_S_AUTH
:
931 IEEE80211_UNLOCK(ic
);
932 IEEE80211_SEND_MGMT(ic
, in
,
933 IEEE80211_FC0_SUBTYPE_ASSOC_REQ
, 0);
935 case IEEE80211_S_RUN
:
936 IEEE80211_UNLOCK(ic
);
937 ieee80211_sta_leave(ic
, in
);
938 IEEE80211_SEND_MGMT(ic
, in
,
939 IEEE80211_FC0_SUBTYPE_ASSOC_REQ
, 1);
943 case IEEE80211_S_RUN
:
945 case IEEE80211_S_INIT
:
946 ieee80211_err("ieee80211_newstate: "
947 "invalid transition\n");
949 case IEEE80211_S_AUTH
:
950 ieee80211_err("ieee80211_newstate: "
951 "invalid transition\n");
953 case IEEE80211_S_SCAN
: /* adhoc/hostap mode */
954 case IEEE80211_S_ASSOC
: /* infra mode */
955 ASSERT(in
->in_txrate
< in
->in_rates
.ir_nrates
);
956 im
->im_mgt_timer
= 0;
957 ieee80211_notify_node_join(ic
, in
);
960 * We can send data now; update the fastpath with our
961 * current associated BSSID and other relevant settings.
963 wd
.wd_secalloc
= ieee80211_crypto_getciphertype(ic
);
964 wd
.wd_opmode
= ic
->ic_opmode
;
965 IEEE80211_ADDR_COPY(wd
.wd_bssid
, in
->in_bssid
);
968 (IEEE80211_NODE_QOS
|IEEE80211_NODE_HT
)) {
970 if (ic
->ic_flags
& IEEE80211_F_DATAPAD
) {
971 wd
.wd_qospad
= roundup(wd
.wd_qospad
,
975 (void) mac_pdata_update(ic
->ic_mach
, &wd
, sizeof (wd
));
980 * When 802.1x is not in use mark the port authorized
981 * at this point so traffic can flow.
983 if (in
->in_authmode
!= IEEE80211_AUTH_8021X
)
984 ieee80211_node_authorize(in
);
986 * Enable inactivity processing.
988 ic
->ic_scan
.nt_inact_timer
= IEEE80211_INACT_WAIT
;
989 ic
->ic_sta
.nt_inact_timer
= IEEE80211_INACT_WAIT
;
990 break; /* IEEE80211_S_RUN */
991 } /* switch nstate */
992 IEEE80211_UNLOCK(ic
);