1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * IEEE 802.11 protocol support
40 */
41
42 #include "net80211_impl.h"
43
44 /* tunables */
45 #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */
46 #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */
47
48 #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
49
50 const char *ieee80211_mgt_subtype_name[] = {
51 "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
52 "probe_req", "probe_resp", "reserved#6", "reserved#7",
53 "beacon", "atim", "disassoc", "auth",
54 "deauth", "reserved#13", "reserved#14", "reserved#15"
55 };
56 const char *ieee80211_ctl_subtype_name[] = {
57 "reserved#0", "reserved#1", "reserved#2", "reserved#3",
58 "reserved#3", "reserved#5", "reserved#6", "reserved#7",
59 "reserved#8", "reserved#9", "ps_poll", "rts",
60 "cts", "ack", "cf_end", "cf_end_ack"
61 };
62 const char *ieee80211_state_name[IEEE80211_S_MAX] = {
63 "INIT", /* IEEE80211_S_INIT */
64 "SCAN", /* IEEE80211_S_SCAN */
65 "AUTH", /* IEEE80211_S_AUTH */
66 "ASSOC", /* IEEE80211_S_ASSOC */
67 "RUN" /* IEEE80211_S_RUN */
68 };
69 const char *ieee80211_wme_acnames[] = {
70 "WME_AC_BE",
71 "WME_AC_BK",
72 "WME_AC_VI",
73 "WME_AC_VO",
74 "WME_UPSD",
75 };
76
77 static int ieee80211_newstate(ieee80211com_t *, enum ieee80211_state, int);
78
79 /*
80 * Initialize the interface softc, ic, with protocol management
81 * related data structures and functions.
82 */
83 void
ieee80211_proto_attach(ieee80211com_t * ic)84 ieee80211_proto_attach(ieee80211com_t *ic)
85 {
86 struct ieee80211_impl *im = ic->ic_private;
87
88 ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
89 ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT;
90 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
91 ic->ic_protmode = IEEE80211_PROT_CTSONLY;
92 im->im_bmiss_max = IEEE80211_BMISS_MAX;
93
94 ic->ic_wme.wme_hipri_switch_hysteresis =
95 AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
96
97 /* protocol state change handler */
98 ic->ic_newstate = ieee80211_newstate;
99
100 /* initialize management frame handlers */
101 ic->ic_recv_mgmt = ieee80211_recv_mgmt;
102 ic->ic_send_mgmt = ieee80211_send_mgmt;
103 }
104
105 /*
106 * Print a 802.11 frame header
107 */
108 void
ieee80211_dump_pkt(const uint8_t * buf,int32_t len,int32_t rate,int32_t rssi)109 ieee80211_dump_pkt(const uint8_t *buf, int32_t len, int32_t rate, int32_t rssi)
110 {
111 struct ieee80211_frame *wh;
112 int8_t buf1[100];
113 int8_t buf2[25];
114 int i;
115
116 bzero(buf1, sizeof (buf1));
117 bzero(buf2, sizeof (buf2));
118 wh = (struct ieee80211_frame *)buf;
119 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
120 case IEEE80211_FC1_DIR_NODS:
121 (void) snprintf(buf2, sizeof (buf2), "NODS %s",
122 ieee80211_macaddr_sprintf(wh->i_addr2));
123 (void) strncat(buf1, buf2, sizeof (buf2));
124 (void) snprintf(buf2, sizeof (buf2), "->%s",
125 ieee80211_macaddr_sprintf(wh->i_addr1));
126 (void) strncat(buf1, buf2, sizeof (buf2));
127 (void) snprintf(buf2, sizeof (buf2), "(%s)",
128 ieee80211_macaddr_sprintf(wh->i_addr3));
129 (void) strncat(buf1, buf2, sizeof (buf2));
130 break;
131 case IEEE80211_FC1_DIR_TODS:
132 (void) snprintf(buf2, sizeof (buf2), "TODS %s",
133 ieee80211_macaddr_sprintf(wh->i_addr2));
134 (void) strncat(buf1, buf2, sizeof (buf2));
135 (void) snprintf(buf2, sizeof (buf2), "->%s",
136 ieee80211_macaddr_sprintf(wh->i_addr3));
137 (void) strncat(buf1, buf2, sizeof (buf2));
138 (void) snprintf(buf2, sizeof (buf2), "(%s)",
139 ieee80211_macaddr_sprintf(wh->i_addr1));
140 (void) strncat(buf1, buf2, sizeof (buf2));
141 break;
142 case IEEE80211_FC1_DIR_FROMDS:
143 (void) snprintf(buf2, sizeof (buf2), "FRDS %s",
144 ieee80211_macaddr_sprintf(wh->i_addr3));
145 (void) strncat(buf1, buf2, sizeof (buf2));
146 (void) snprintf(buf2, sizeof (buf2), "->%s",
147 ieee80211_macaddr_sprintf(wh->i_addr1));
148 (void) strncat(buf1, buf2, sizeof (buf2));
149 (void) snprintf(buf2, sizeof (buf2), "(%s)",
150 ieee80211_macaddr_sprintf(wh->i_addr2));
151 (void) strncat(buf1, buf2, sizeof (buf2));
152 break;
153 case IEEE80211_FC1_DIR_DSTODS:
154 (void) snprintf(buf2, sizeof (buf2), "DSDS %s",
155 ieee80211_macaddr_sprintf((uint8_t *)&wh[1]));
156 (void) strncat(buf1, buf2, sizeof (buf2));
157 (void) snprintf(buf2, sizeof (buf2), "->%s ",
158 ieee80211_macaddr_sprintf(wh->i_addr3));
159 (void) strncat(buf1, buf2, sizeof (buf2));
160 (void) snprintf(buf2, sizeof (buf2), "%s",
161 ieee80211_macaddr_sprintf(wh->i_addr2));
162 (void) strncat(buf1, buf2, sizeof (buf2));
163 (void) snprintf(buf2, sizeof (buf2), "->%s",
164 ieee80211_macaddr_sprintf(wh->i_addr1));
165 (void) strncat(buf1, buf2, sizeof (buf2));
166 break;
167 }
168 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", buf1);
169 bzero(buf1, sizeof (buf1));
170
171 switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
172 case IEEE80211_FC0_TYPE_DATA:
173 (void) sprintf(buf2, "data");
174 break;
175 case IEEE80211_FC0_TYPE_MGT:
176 (void) snprintf(buf2, sizeof (buf2), "%s",
177 ieee80211_mgt_subtype_name[
178 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
179 >> IEEE80211_FC0_SUBTYPE_SHIFT]);
180 break;
181 default:
182 (void) snprintf(buf2, sizeof (buf2), "type#%d",
183 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
184 break;
185 }
186 (void) strncat(buf1, buf2, sizeof (buf2));
187 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
188 (void) sprintf(buf2, " WEP");
189 (void) strcat(buf1, buf2);
190 }
191 if (rate >= 0) {
192 (void) snprintf(buf2, sizeof (buf2), " %dM", rate / 2);
193 (void) strncat(buf1, buf2, sizeof (buf2));
194 }
195 if (rssi >= 0) {
196 (void) snprintf(buf2, sizeof (buf2), " +%d", rssi);
197 (void) strncat(buf1, buf2, sizeof (buf2));
198 }
199 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", buf1);
200 bzero(buf1, sizeof (buf1));
201
202 if (len > 0) {
203 for (i = 0; i < (len > 40 ? 40 : len); i++) {
204 if ((i & 0x03) == 0)
205 (void) strcat(buf1, " ");
206 (void) snprintf(buf2, 3, "%02x", buf[i]);
207 (void) strncat(buf1, buf2, 3);
208 }
209 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s",
210 buf1);
211 }
212 }
213
214 /*
215 * Adjust/Fix the specified node's rate table
216 *
217 * in node
218 * flag IEEE80211_F_DOSORT : sort the node's rate table
219 * IEEE80211_F_DONEGO : mark a rate as basic rate if it is
220 * a device's basic rate
221 * IEEE80211_F_DODEL : delete rates not supported by the device
222 * IEEE80211_F_DOFRATE: check if the fixed rate is supported by
223 * the device
224 *
225 * The highest bit of returned rate value is set to 1 on failure.
226 */
227 int
ieee80211_fix_rate(ieee80211_node_t * in,struct ieee80211_rateset * nrs,int flags)228 ieee80211_fix_rate(ieee80211_node_t *in,
229 struct ieee80211_rateset *nrs, int flags)
230 {
231 ieee80211com_t *ic = in->in_ic;
232 struct ieee80211_rateset *srs;
233 boolean_t ignore;
234 int i;
235 int okrate;
236 int badrate;
237 int fixedrate;
238 uint8_t r;
239
240 /*
241 * If the fixed rate check was requested but no
242 * fixed has been defined then just remove it.
243 */
244 if ((flags & IEEE80211_F_DOFRATE) &&
245 (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)) {
246 flags &= ~IEEE80211_F_DOFRATE;
247 }
248 if (in->in_chan == IEEE80211_CHAN_ANYC) {
249 return (IEEE80211_RATE_BASIC);
250 }
251 okrate = badrate = fixedrate = 0;
252 srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, in->in_chan)];
253 for (i = 0; i < nrs->ir_nrates; ) {
254 int j;
255
256 ignore = B_FALSE;
257 if (flags & IEEE80211_F_DOSORT) {
258 /*
259 * Sort rates.
260 */
261 for (j = i + 1; j < nrs->ir_nrates; j++) {
262 if (IEEE80211_RV(nrs->ir_rates[i]) >
263 IEEE80211_RV(nrs->ir_rates[j])) {
264 r = nrs->ir_rates[i];
265 nrs->ir_rates[i] = nrs->ir_rates[j];
266 nrs->ir_rates[j] = r;
267 }
268 }
269 }
270 r = IEEE80211_RV(nrs->ir_rates[i]);
271 badrate = r;
272
273 /*
274 * Check against supported rates.
275 */
276 for (j = 0; j < srs->ir_nrates; j++) {
277 if (r == IEEE80211_RV(srs->ir_rates[j])) {
278 /*
279 * Overwrite with the supported rate
280 * value so any basic rate bit is set.
281 * This insures that response we send
282 * to stations have the necessary basic
283 * rate bit set.
284 */
285 if (flags & IEEE80211_F_DONEGO)
286 nrs->ir_rates[i] = srs->ir_rates[j];
287 break;
288 }
289 }
290 if (j == srs->ir_nrates) {
291 /*
292 * A rate in the node's rate set is not
293 * supported. We just discard/ignore the rate.
294 * Note that this is important for 11b stations
295 * when they want to associate with an 11g AP.
296 */
297 ignore = B_TRUE;
298 }
299
300 if (flags & IEEE80211_F_DODEL) {
301 /*
302 * Delete unacceptable rates.
303 */
304 if (ignore) {
305 nrs->ir_nrates--;
306 for (j = i; j < nrs->ir_nrates; j++)
307 nrs->ir_rates[j] = nrs->ir_rates[j + 1];
308 nrs->ir_rates[j] = 0;
309 continue;
310 }
311 }
312 if (flags & IEEE80211_F_DOFRATE) {
313 /*
314 * Check any fixed rate is included.
315 */
316 if (r == ic->ic_fixed_rate)
317 fixedrate = r;
318 }
319 if (!ignore)
320 okrate = nrs->ir_rates[i];
321 i++;
322 }
323 if (okrate == 0 || ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0))
324 return (badrate | IEEE80211_RATE_BASIC);
325 else
326 return (IEEE80211_RV(okrate));
327 }
328
329 /*
330 * Reset 11g-related state.
331 */
332 void
ieee80211_reset_erp(ieee80211com_t * ic)333 ieee80211_reset_erp(ieee80211com_t *ic)
334 {
335 ic->ic_flags &= ~IEEE80211_F_USEPROT;
336 /*
337 * Short slot time is enabled only when operating in 11g
338 * and not in an IBSS. We must also honor whether or not
339 * the driver is capable of doing it.
340 */
341 ieee80211_set_shortslottime(ic,
342 ic->ic_curmode == IEEE80211_MODE_11A);
343 /*
344 * Set short preamble and ERP barker-preamble flags.
345 */
346 if (ic->ic_curmode == IEEE80211_MODE_11A ||
347 (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) {
348 ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
349 ic->ic_flags &= ~IEEE80211_F_USEBARKER;
350 } else {
351 ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
352 ic->ic_flags |= IEEE80211_F_USEBARKER;
353 }
354 }
355
356 /*
357 * Change current channel to be the next available channel
358 */
359 void
ieee80211_reset_chan(ieee80211com_t * ic)360 ieee80211_reset_chan(ieee80211com_t *ic)
361 {
362 struct ieee80211_channel *ch = ic->ic_curchan;
363
364 IEEE80211_LOCK(ic);
365 do {
366 if (++ch > &ic->ic_sup_channels[IEEE80211_CHAN_MAX])
367 ch = &ic->ic_sup_channels[0];
368 if (ieee80211_isset(ic->ic_chan_active,
369 ieee80211_chan2ieee(ic, ch))) {
370 break;
371 }
372 } while (ch != ic->ic_curchan);
373 ic->ic_curchan = ch;
374 IEEE80211_UNLOCK(ic);
375 }
376
377 /*
378 * Set the short slot time state and notify the driver.
379 */
380 void
ieee80211_set_shortslottime(ieee80211com_t * ic,boolean_t on)381 ieee80211_set_shortslottime(ieee80211com_t *ic, boolean_t on)
382 {
383 if (on)
384 ic->ic_flags |= IEEE80211_F_SHSLOT;
385 else
386 ic->ic_flags &= ~IEEE80211_F_SHSLOT;
387 /* notify driver */
388 if (ic->ic_set_shortslot != NULL)
389 ic->ic_set_shortslot(ic, on);
390 }
391
392 /*
393 * Mark the basic rates for the 11g rate table based on the
394 * operating mode. For real 11g we mark all the 11b rates
395 * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
396 * 11b rates. There's also a pseudo 11a-mode used to mark only
397 * the basic OFDM rates.
398 */
399 void
ieee80211_setbasicrates(struct ieee80211_rateset * rs,enum ieee80211_phymode mode)400 ieee80211_setbasicrates(struct ieee80211_rateset *rs,
401 enum ieee80211_phymode mode)
402 {
403 static const struct ieee80211_rateset basic[] = {
404 { 0 }, /* IEEE80211_MODE_AUTO */
405 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
406 { 2, { 2, 4} }, /* IEEE80211_MODE_11B */
407 { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G mixed b/g */
408 { 0 }, /* IEEE80211_MODE_FH */
409 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_TURBO_A */
410 { 4, { 2, 4, 11, 22 } },
411 /* IEEE80211_MODE_TURBO_G (mixed b/g) */
412 { 0 }, /* IEEE80211_MODE_STURBO_A */
413 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11NA */
414 /* IEEE80211_MODE_11NG (mixed b/g) */
415 { 7, { 2, 4, 11, 22, 12, 24, 48 } }
416 };
417 int i, j;
418
419 ASSERT(mode < IEEE80211_MODE_MAX);
420 for (i = 0; i < rs->ir_nrates; i++) {
421 rs->ir_rates[i] &= IEEE80211_RATE_VAL;
422 for (j = 0; j < basic[mode].ir_nrates; j++) {
423 if (basic[mode].ir_rates[j] == rs->ir_rates[i]) {
424 rs->ir_rates[i] |= IEEE80211_RATE_BASIC;
425 break;
426 }
427 }
428 }
429 }
430
431 /*
432 * WME protocol support. The following parameters come from the spec.
433 */
434 typedef struct phyParamType {
435 uint8_t aifsn;
436 uint8_t logcwmin;
437 uint8_t logcwmax;
438 uint16_t txopLimit;
439 uint8_t acm;
440 } paramType;
441
442 static const paramType phyParamForAC_BE[IEEE80211_MODE_MAX] = {
443 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_AUTO */
444 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11A */
445 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11B */
446 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11G */
447 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_FH */
448 { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
449 { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
450 { 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
451 { 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NA */
452 { 3, 4, 6, 0, 0 } /* IEEE80211_MODE_11NG */
453 };
454 static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = {
455 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
456 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
457 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
458 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
459 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
460 { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
461 { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
462 { 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
463 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
464 { 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
465 };
466 static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = {
467 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
468 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
469 { 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
470 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
471 { 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
472 { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
473 { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
474 { 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
475 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
476 { 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
477 };
478 static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = {
479 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
480 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
481 { 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
482 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
483 { 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
484 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
485 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
486 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
487 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
488 { 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
489 };
490
491 static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = {
492 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
493 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
494 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
495 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
496 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
497 { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
498 { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
499 { 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
500 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
501 { 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
502 };
503 static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = {
504 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
505 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
506 { 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
507 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
508 { 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
509 { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
510 { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
511 { 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
512 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
513 { 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
514 };
515 static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = {
516 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
517 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
518 { 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
519 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
520 { 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
521 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
522 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
523 { 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
524 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
525 { 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
526 };
527
528 void
ieee80211_wme_initparams(struct ieee80211com * ic)529 ieee80211_wme_initparams(struct ieee80211com *ic)
530 {
531 struct ieee80211_wme_state *wme = &ic->ic_wme;
532 const paramType *pPhyParam, *pBssPhyParam;
533 struct wmeParams *wmep;
534 enum ieee80211_phymode mode;
535 int i;
536
537 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
538 return;
539
540 /*
541 * Select mode; we can be called early in which case we
542 * always use auto mode. We know we'll be called when
543 * entering the RUN state with bsschan setup properly
544 * so state will eventually get set correctly
545 */
546 if (ic->ic_curchan != IEEE80211_CHAN_ANYC)
547 mode = ieee80211_chan2mode(ic, ic->ic_curchan);
548 else
549 mode = IEEE80211_MODE_AUTO;
550 for (i = 0; i < WME_NUM_AC; i++) {
551 switch (i) {
552 case WME_AC_BK:
553 pPhyParam = &phyParamForAC_BK[mode];
554 pBssPhyParam = &phyParamForAC_BK[mode];
555 break;
556 case WME_AC_VI:
557 pPhyParam = &phyParamForAC_VI[mode];
558 pBssPhyParam = &bssPhyParamForAC_VI[mode];
559 break;
560 case WME_AC_VO:
561 pPhyParam = &phyParamForAC_VO[mode];
562 pBssPhyParam = &bssPhyParamForAC_VO[mode];
563 break;
564 case WME_AC_BE:
565 default:
566 pPhyParam = &phyParamForAC_BE[mode];
567 pBssPhyParam = &bssPhyParamForAC_BE[mode];
568 break;
569 }
570
571 wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
572 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
573 wmep->wmep_acm = pPhyParam->acm;
574 wmep->wmep_aifsn = pPhyParam->aifsn;
575 wmep->wmep_logcwmin = pPhyParam->logcwmin;
576 wmep->wmep_logcwmax = pPhyParam->logcwmax;
577 wmep->wmep_txopLimit = pPhyParam->txopLimit;
578 } else {
579 wmep->wmep_acm = pBssPhyParam->acm;
580 wmep->wmep_aifsn = pBssPhyParam->aifsn;
581 wmep->wmep_logcwmin = pBssPhyParam->logcwmin;
582 wmep->wmep_logcwmax = pBssPhyParam->logcwmax;
583 wmep->wmep_txopLimit = pBssPhyParam->txopLimit;
584
585 }
586 ieee80211_dbg(IEEE80211_MSG_WME, "ieee80211_wme_initparams: "
587 "%s chan [acm %u aifsn %u log2(cwmin) %u "
588 "log2(cwmax) %u txpoLimit %u]\n",
589 ieee80211_wme_acnames[i],
590 wmep->wmep_acm,
591 wmep->wmep_aifsn,
592 wmep->wmep_logcwmin,
593 wmep->wmep_logcwmax,
594 wmep->wmep_txopLimit);
595
596 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
597 wmep->wmep_acm = pBssPhyParam->acm;
598 wmep->wmep_aifsn = pBssPhyParam->aifsn;
599 wmep->wmep_logcwmin = pBssPhyParam->logcwmin;
600 wmep->wmep_logcwmax = pBssPhyParam->logcwmax;
601 wmep->wmep_txopLimit = pBssPhyParam->txopLimit;
602 ieee80211_dbg(IEEE80211_MSG_WME, "ieee80211_wme_initparams: "
603 "%s bss [acm %u aifsn %u log2(cwmin) %u "
604 "log2(cwmax) %u txpoLimit %u]\n",
605 ieee80211_wme_acnames[i],
606 wmep->wmep_acm,
607 wmep->wmep_aifsn,
608 wmep->wmep_logcwmin,
609 wmep->wmep_logcwmax,
610 wmep->wmep_txopLimit);
611 }
612 /* NB: check ic_bss to avoid NULL deref on initial attach */
613 if (ic->ic_bss != NULL) {
614 /*
615 * Calculate agressive mode switching threshold based
616 * on beacon interval. This doesn't need locking since
617 * we're only called before entering the RUN state at
618 * which point we start sending beacon frames.
619 */
620 wme->wme_hipri_switch_thresh =
621 (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->in_intval) / 100;
622 ieee80211_wme_updateparams(ic);
623 }
624 }
625
626 /*
627 * Update WME parameters for ourself and the BSS.
628 */
629 void
ieee80211_wme_updateparams(struct ieee80211com * ic)630 ieee80211_wme_updateparams(struct ieee80211com *ic)
631 {
632 static const paramType phyParam[IEEE80211_MODE_MAX] = {
633 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_AUTO */
634 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11A */
635 { 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_11B */
636 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11G */
637 { 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_FH */
638 { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_A */
639 { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_G */
640 { 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_STURBO_A */
641 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NA */
642 { 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NG */
643 };
644 struct ieee80211_wme_state *wme = &ic->ic_wme;
645 const struct wmeParams *wmep;
646 struct wmeParams *chanp, *bssp;
647 enum ieee80211_phymode mode;
648 int i;
649
650 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
651 return;
652
653 /* set up the channel access parameters for the physical device */
654 for (i = 0; i < WME_NUM_AC; i++) {
655 chanp = &wme->wme_chanParams.cap_wmeParams[i];
656 wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
657 chanp->wmep_aifsn = wmep->wmep_aifsn;
658 chanp->wmep_logcwmin = wmep->wmep_logcwmin;
659 chanp->wmep_logcwmax = wmep->wmep_logcwmax;
660 chanp->wmep_txopLimit = wmep->wmep_txopLimit;
661
662 chanp = &wme->wme_bssChanParams.cap_wmeParams[i];
663 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
664 chanp->wmep_aifsn = wmep->wmep_aifsn;
665 chanp->wmep_logcwmin = wmep->wmep_logcwmin;
666 chanp->wmep_logcwmax = wmep->wmep_logcwmax;
667 chanp->wmep_txopLimit = wmep->wmep_txopLimit;
668 }
669
670 /*
671 * Select mode; we can be called early in which case we
672 * always use auto mode. We know we'll be called when
673 * entering the RUN state with bsschan setup properly
674 * so state will eventually get set correctly
675 */
676 if (ic->ic_curchan != IEEE80211_CHAN_ANYC)
677 mode = ieee80211_chan2mode(ic, ic->ic_curchan);
678 else
679 mode = IEEE80211_MODE_AUTO;
680
681 /*
682 * This implements agressive mode as found in certain
683 * vendors' AP's. When there is significant high
684 * priority (VI/VO) traffic in the BSS throttle back BE
685 * traffic by using conservative parameters. Otherwise
686 * BE uses agressive params to optimize performance of
687 * legacy/non-QoS traffic.
688 */
689 if ((ic->ic_opmode == IEEE80211_M_HOSTAP &&
690 (wme->wme_flags & WME_F_AGGRMODE) != 0) ||
691 (ic->ic_opmode == IEEE80211_M_STA &&
692 (ic->ic_bss->in_flags & IEEE80211_NODE_QOS) == 0) ||
693 (ic->ic_flags & IEEE80211_F_WME) == 0) {
694 chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
695 bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
696
697 chanp->wmep_aifsn = bssp->wmep_aifsn = phyParam[mode].aifsn;
698 chanp->wmep_logcwmin = bssp->wmep_logcwmin =
699 phyParam[mode].logcwmin;
700 chanp->wmep_logcwmax = bssp->wmep_logcwmax =
701 phyParam[mode].logcwmax;
702 chanp->wmep_txopLimit = bssp->wmep_txopLimit =
703 (ic->ic_flags & IEEE80211_F_BURST) ?
704 phyParam[mode].txopLimit : 0;
705 ieee80211_dbg(IEEE80211_MSG_WME,
706 "ieee80211_wme_updateparams_locked: "
707 "%s [acm %u aifsn %u log2(cwmin) %u "
708 "log2(cwmax) %u txpoLimit %u]\n",
709 ieee80211_wme_acnames[WME_AC_BE],
710 chanp->wmep_acm,
711 chanp->wmep_aifsn,
712 chanp->wmep_logcwmin,
713 chanp->wmep_logcwmax,
714 chanp->wmep_txopLimit);
715 }
716
717 wme->wme_update(ic);
718
719 ieee80211_dbg(IEEE80211_MSG_WME, "ieee80211_wme_updateparams(): "
720 "%s: WME params updated, cap_info 0x%x\n",
721 ic->ic_opmode == IEEE80211_M_STA ?
722 wme->wme_wmeChanParams.cap_info :
723 wme->wme_bssChanParams.cap_info);
724 }
725
726 /*
727 * Process STA mode beacon miss events. Send a direct probe request
728 * frame to the current ap bmiss_max times (w/o answer) before
729 * scanning for a new ap.
730 */
731 void
ieee80211_beacon_miss(ieee80211com_t * ic)732 ieee80211_beacon_miss(ieee80211com_t *ic)
733 {
734 ieee80211_impl_t *im = ic->ic_private;
735
736 if (ic->ic_flags & IEEE80211_F_SCAN)
737 return;
738 ieee80211_dbg(IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
739 "%s\n", "beacon miss");
740
741 /*
742 * Our handling is only meaningful for stations that are
743 * associated; any other conditions else will be handled
744 * through different means (e.g. the tx timeout on mgt frames).
745 */
746 if (ic->ic_opmode != IEEE80211_M_STA ||
747 ic->ic_state != IEEE80211_S_RUN) {
748 return;
749 }
750
751 IEEE80211_LOCK(ic);
752 if (++im->im_bmiss_count < im->im_bmiss_max) {
753 /*
754 * Send a directed probe req before falling back to a scan;
755 * if we receive a response ic_bmiss_count will be reset.
756 * Some cards mistakenly report beacon miss so this avoids
757 * the expensive scan if the ap is still there.
758 */
759 IEEE80211_UNLOCK(ic);
760 (void) ieee80211_send_probereq(ic->ic_bss, ic->ic_macaddr,
761 ic->ic_bss->in_bssid, ic->ic_bss->in_bssid,
762 ic->ic_bss->in_essid, ic->ic_bss->in_esslen,
763 ic->ic_opt_ie, ic->ic_opt_ie_len);
764 return;
765 }
766 im->im_bmiss_count = 0;
767 IEEE80211_UNLOCK(ic);
768 ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
769 }
770
771 /*
772 * Manage state transition between INIT | AUTH | ASSOC | RUN.
773 */
774 static int
ieee80211_newstate(ieee80211com_t * ic,enum ieee80211_state nstate,int arg)775 ieee80211_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
776 {
777 struct ieee80211_impl *im = ic->ic_private;
778 ieee80211_node_t *in;
779 enum ieee80211_state ostate;
780 wifi_data_t wd = { 0 };
781
782 IEEE80211_LOCK(ic);
783 ostate = ic->ic_state;
784 ieee80211_dbg(IEEE80211_MSG_STATE, "ieee80211_newstate(): "
785 "%s -> %s\n",
786 ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
787 ic->ic_state = nstate;
788 in = ic->ic_bss;
789 im->im_swbmiss_period = 0; /* Reset software beacon miss period */
790
791 switch (nstate) {
792 case IEEE80211_S_INIT:
793 IEEE80211_UNLOCK(ic);
794 switch (ostate) {
795 case IEEE80211_S_INIT:
796 return (0);
797 case IEEE80211_S_SCAN:
798 ieee80211_cancel_scan(ic);
799 break;
800 case IEEE80211_S_AUTH:
801 break;
802 case IEEE80211_S_ASSOC:
803 if (ic->ic_opmode == IEEE80211_M_STA) {
804 IEEE80211_SEND_MGMT(ic, in,
805 IEEE80211_FC0_SUBTYPE_DEAUTH,
806 IEEE80211_REASON_AUTH_LEAVE);
807 }
808 break;
809 case IEEE80211_S_RUN:
810 switch (ic->ic_opmode) {
811 case IEEE80211_M_STA:
812 IEEE80211_SEND_MGMT(ic, in,
813 IEEE80211_FC0_SUBTYPE_DEAUTH,
814 IEEE80211_REASON_AUTH_LEAVE);
815 ieee80211_sta_leave(ic, in);
816 break;
817 case IEEE80211_M_IBSS:
818 ieee80211_notify_node_leave(ic, in);
819 break;
820 default:
821 break;
822 }
823 break;
824 }
825 IEEE80211_LOCK(ic);
826 im->im_mgt_timer = 0;
827 ieee80211_reset_bss(ic);
828 break;
829 case IEEE80211_S_SCAN:
830 switch (ostate) {
831 case IEEE80211_S_INIT:
832 IEEE80211_UNLOCK(ic);
833 ieee80211_begin_scan(ic, (arg == 0) ? B_FALSE : B_TRUE);
834 return (0);
835 case IEEE80211_S_SCAN:
836 /*
837 * Scan next. If doing an active scan and the
838 * channel is not marked passive-only then send
839 * a probe request. Otherwise just listen for
840 * beacons on the channel.
841 */
842 if ((ic->ic_flags & IEEE80211_F_ASCAN) &&
843 !IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) {
844 IEEE80211_UNLOCK(ic);
845 (void) ieee80211_send_probereq(in,
846 ic->ic_macaddr, wifi_bcastaddr,
847 wifi_bcastaddr,
848 ic->ic_des_essid, ic->ic_des_esslen,
849 ic->ic_opt_ie, ic->ic_opt_ie_len);
850 return (0);
851 }
852 break;
853 case IEEE80211_S_RUN:
854 /* beacon miss */
855 ieee80211_dbg(IEEE80211_MSG_STATE,
856 "no recent beacons from %s, rescanning\n",
857 ieee80211_macaddr_sprintf(in->in_macaddr));
858 IEEE80211_UNLOCK(ic);
859 ieee80211_sta_leave(ic, in);
860 IEEE80211_LOCK(ic);
861 ic->ic_flags &= ~IEEE80211_F_SIBSS;
862 /* FALLTHRU */
863 case IEEE80211_S_AUTH:
864 case IEEE80211_S_ASSOC:
865 /* timeout restart scan */
866 in = ieee80211_find_node(&ic->ic_scan,
867 ic->ic_bss->in_macaddr);
868 if (in != NULL) {
869 in->in_fails++;
870 ieee80211_unref_node(&in);
871 }
872 break;
873 }
874 break;
875 case IEEE80211_S_AUTH:
876 ASSERT(ic->ic_opmode == IEEE80211_M_STA);
877 switch (ostate) {
878 case IEEE80211_S_INIT:
879 case IEEE80211_S_SCAN:
880 IEEE80211_UNLOCK(ic);
881 IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH,
882 1);
883 return (0);
884 case IEEE80211_S_AUTH:
885 case IEEE80211_S_ASSOC:
886 switch (arg) {
887 case IEEE80211_FC0_SUBTYPE_AUTH:
888 IEEE80211_UNLOCK(ic);
889 IEEE80211_SEND_MGMT(ic, in,
890 IEEE80211_FC0_SUBTYPE_AUTH, 2);
891 return (0);
892 case IEEE80211_FC0_SUBTYPE_DEAUTH:
893 /* ignore and retry scan on timeout */
894 break;
895 }
896 break;
897 case IEEE80211_S_RUN:
898 switch (arg) {
899 case IEEE80211_FC0_SUBTYPE_AUTH:
900 ic->ic_state = ostate; /* stay RUN */
901 IEEE80211_UNLOCK(ic);
902 IEEE80211_SEND_MGMT(ic, in,
903 IEEE80211_FC0_SUBTYPE_AUTH, 2);
904 return (0);
905 case IEEE80211_FC0_SUBTYPE_DEAUTH:
906 IEEE80211_UNLOCK(ic);
907 ieee80211_sta_leave(ic, in);
908 /* try to re-auth */
909 IEEE80211_SEND_MGMT(ic, in,
910 IEEE80211_FC0_SUBTYPE_AUTH, 1);
911 return (0);
912 }
913 break;
914 }
915 break;
916 case IEEE80211_S_ASSOC:
917 ASSERT(ic->ic_opmode == IEEE80211_M_STA);
918 switch (ostate) {
919 case IEEE80211_S_INIT:
920 case IEEE80211_S_SCAN:
921 case IEEE80211_S_ASSOC:
922 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_newstate: "
923 "invalid transition\n");
924 break;
925 case IEEE80211_S_AUTH:
926 IEEE80211_UNLOCK(ic);
927 IEEE80211_SEND_MGMT(ic, in,
928 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
929 return (0);
930 case IEEE80211_S_RUN:
931 IEEE80211_UNLOCK(ic);
932 ieee80211_sta_leave(ic, in);
933 IEEE80211_SEND_MGMT(ic, in,
934 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
935 return (0);
936 }
937 break;
938 case IEEE80211_S_RUN:
939 switch (ostate) {
940 case IEEE80211_S_INIT:
941 ieee80211_err("ieee80211_newstate: "
942 "invalid transition\n");
943 break;
944 case IEEE80211_S_AUTH:
945 ieee80211_err("ieee80211_newstate: "
946 "invalid transition\n");
947 break;
948 case IEEE80211_S_SCAN: /* adhoc/hostap mode */
949 case IEEE80211_S_ASSOC: /* infra mode */
950 ASSERT(in->in_txrate < in->in_rates.ir_nrates);
951 im->im_mgt_timer = 0;
952 ieee80211_notify_node_join(ic, in);
953
954 /*
955 * We can send data now; update the fastpath with our
956 * current associated BSSID and other relevant settings.
957 */
958 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic);
959 wd.wd_opmode = ic->ic_opmode;
960 IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid);
961 wd.wd_qospad = 0;
962 if (in->in_flags &
963 (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) {
964 wd.wd_qospad = 2;
965 if (ic->ic_flags & IEEE80211_F_DATAPAD) {
966 wd.wd_qospad = roundup(wd.wd_qospad,
967 sizeof (uint32_t));
968 }
969 }
970 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
971 break;
972 }
973
974 /*
975 * When 802.1x is not in use mark the port authorized
976 * at this point so traffic can flow.
977 */
978 if (in->in_authmode != IEEE80211_AUTH_8021X)
979 ieee80211_node_authorize(in);
980 /*
981 * Enable inactivity processing.
982 */
983 ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT;
984 ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT;
985 break; /* IEEE80211_S_RUN */
986 } /* switch nstate */
987 IEEE80211_UNLOCK(ic);
988
989 return (0);
990 }
991