Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/net80211/net80211.c
+++ new/usr/src/uts/common/io/net80211/net80211.c
1 1 /*
2 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 3 * Use is subject to license terms.
4 4 */
5 5
6 6 /*
7 7 * Copyright (c) 2001 Atsushi Onoe
8 8 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
9 9 * All rights reserved.
10 10 *
11 11 * Redistribution and use in source and binary forms, with or without
12 12 * modification, are permitted provided that the following conditions
13 13 * are met:
14 14 * 1. Redistributions of source code must retain the above copyright
15 15 * notice, this list of conditions and the following disclaimer.
16 16 * 2. Redistributions in binary form must reproduce the above copyright
17 17 * notice, this list of conditions and the following disclaimer in the
18 18 * documentation and/or other materials provided with the distribution.
19 19 * 3. The name of the author may not be used to endorse or promote products
20 20 * derived from this software without specific prior written permission.
21 21 *
22 22 * Alternatively, this software may be distributed under the terms of the
23 23 * GNU General Public License ("GPL") version 2 as published by the Free
24 24 * Software Foundation.
25 25 *
26 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 36 */
37 37
38 38 /*
39 39 * IEEE 802.11 generic handler
40 40 */
41 41
42 42 #include <sys/param.h>
43 43 #include <sys/types.h>
44 44 #include <sys/cmn_err.h>
45 45 #include <sys/modctl.h>
46 46 #include <sys/stropts.h>
47 47 #include <sys/door.h>
48 48 #include <sys/mac_provider.h>
49 49 #include "net80211_impl.h"
50 50
51 51 uint32_t ieee80211_debug = 0x0; /* debug msg flags */
52 52
53 53 const char *ieee80211_phymode_name[] = {
54 54 "auto", /* IEEE80211_MODE_AUTO */
55 55 "11a", /* IEEE80211_MODE_11A */
56 56 "11b", /* IEEE80211_MODE_11B */
57 57 "11g", /* IEEE80211_MODE_11G */
58 58 "FH", /* IEEE80211_MODE_FH */
59 59 "turboA", /* IEEE80211_MODE_TURBO_A */
60 60 "turboG", /* IEEE80211_MODE_TURBO_G */
61 61 "sturboA", /* IEEE80211_MODE_STURBO_A */
62 62 "11na", /* IEEE80211_MODE_11NA */
63 63 "11ng", /* IEEE80211_MODE_11NG */
64 64 };
65 65
66 66 #define IEEE80211_DPRINT(_level, _fmt) do { \
67 67 _NOTE(CONSTCOND) \
68 68 va_list ap; \
69 69 va_start(ap, (_fmt)); \
70 70 vcmn_err((_level), (_fmt), ap); \
71 71 va_end(ap); \
72 72 _NOTE(CONSTCOND) \
73 73 } while (0)
74 74
75 75 /*
76 76 * Print error messages
77 77 */
78 78 void
79 79 ieee80211_err(const int8_t *fmt, ...)
80 80 {
81 81 IEEE80211_DPRINT(CE_WARN, fmt);
82 82 }
83 83
84 84 /*
85 85 * Print debug messages
86 86 */
87 87 void
88 88 ieee80211_dbg(uint32_t flag, const int8_t *fmt, ...)
89 89 {
90 90 if (flag & ieee80211_debug)
91 91 IEEE80211_DPRINT(CE_CONT, fmt);
92 92 }
93 93
94 94 /*
95 95 * Alloc memory, and save the size
96 96 */
97 97 void *
98 98 ieee80211_malloc(size_t size)
99 99 {
100 100 void *p = kmem_zalloc((size + 4), KM_SLEEP);
101 101 *(int *)p = size;
102 102 p = (char *)p + 4;
103 103
104 104 return (p);
105 105 }
106 106
107 107 void
108 108 ieee80211_free(void *p)
109 109 {
110 110 void *tp = (char *)p - 4;
111 111 kmem_free((char *)p - 4, *(int *)tp + 4);
112 112 }
113 113
114 114 void
115 115 ieee80211_mac_update(ieee80211com_t *ic)
116 116 {
117 117 wifi_data_t wd = { 0 };
118 118 ieee80211_node_t *in;
119 119
120 120 /*
121 121 * We can send data now; update the fastpath with our
122 122 * current associated BSSID and other relevant settings.
123 123 */
124 124 in = ic->ic_bss;
125 125 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic);
126 126 wd.wd_opmode = ic->ic_opmode;
127 127 IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid);
128 128 wd.wd_qospad = 0;
129 129 if (in->in_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) {
130 130 wd.wd_qospad = 2;
131 131 if (ic->ic_flags & IEEE80211_F_DATAPAD)
132 132 wd.wd_qospad = roundup(wd.wd_qospad, sizeof (uint32_t));
133 133 }
134 134 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
135 135 mac_tx_update(ic->ic_mach);
136 136 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_mac_update"
137 137 "(cipher = %d)\n", wd.wd_secalloc);
138 138 }
139 139
140 140 /*
141 141 * ieee80211_event_thread
142 142 * open door of wpa, send event to wpad service
143 143 */
144 144 static void
145 145 ieee80211_event_thread(void *arg)
146 146 {
147 147 ieee80211com_t *ic = arg;
148 148 door_handle_t event_door = NULL; /* Door for upcalls */
149 149 wl_events_t ev;
150 150 door_arg_t darg;
151 151
152 152 mutex_enter(&ic->ic_doorlock);
153 153
154 154 ev.event = ic->ic_eventq[ic->ic_evq_head];
155 155 ic->ic_evq_head ++;
156 156 if (ic->ic_evq_head >= MAX_EVENT)
157 157 ic->ic_evq_head = 0;
158 158
159 159 ieee80211_dbg(IEEE80211_MSG_DEBUG, "ieee80211_event(%d)\n", ev.event);
160 160 /*
161 161 * Locate the door used for upcalls
162 162 */
163 163 if (door_ki_open(ic->ic_wpadoor, &event_door) != 0) {
164 164 ieee80211_err("ieee80211_event: door_ki_open(%s) failed\n",
165 165 ic->ic_wpadoor);
166 166 goto out;
167 167 }
168 168
169 169 darg.data_ptr = (char *)&ev;
170 170 darg.data_size = sizeof (wl_events_t);
171 171 darg.desc_ptr = NULL;
172 172 darg.desc_num = 0;
173 173 darg.rbuf = NULL;
174 174 darg.rsize = 0;
175 175
176 176 if (door_ki_upcall_limited(event_door, &darg, NULL, SIZE_MAX, 0) != 0) {
177 177 ieee80211_err("ieee80211_event: door_ki_upcall() failed\n");
178 178 }
179 179
180 180 if (event_door) { /* release our hold (if any) */
181 181 door_ki_rele(event_door);
182 182 }
183 183
184 184 out:
185 185 mutex_exit(&ic->ic_doorlock);
186 186 }
187 187
188 188 /*
189 189 * Notify state transition event message to WPA daemon
190 190 */
191 191 void
192 192 ieee80211_notify(ieee80211com_t *ic, wpa_event_type event)
193 193 {
194 194 if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
195 195 return; /* Not running on WPA mode */
196 196
197 197 ic->ic_eventq[ic->ic_evq_tail] = event;
198 198 ic->ic_evq_tail ++;
199 199 if (ic->ic_evq_tail >= MAX_EVENT) ic->ic_evq_tail = 0;
200 200
201 201 /* async */
202 202 (void) timeout(ieee80211_event_thread, (void *)ic, 0);
203 203 }
204 204
205 205 /*
206 206 * Register WPA door
207 207 */
208 208 void
209 209 ieee80211_register_door(ieee80211com_t *ic, const char *drvname, int inst)
210 210 {
211 211 (void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d",
212 212 WPA_DOOR, drvname, inst);
213 213 }
214 214
215 215 /*
216 216 * Default reset method for use with the ioctl support. This
217 217 * method is invoked after any state change in the 802.11
218 218 * layer that should be propagated to the hardware but not
219 219 * require re-initialization of the 802.11 state machine (e.g
220 220 * rescanning for an ap). We always return ENETRESET which
221 221 * should cause the driver to re-initialize the device. Drivers
222 222 * can override this method to implement more optimized support.
223 223 */
224 224 /* ARGSUSED */
225 225 static int
226 226 ieee80211_default_reset(ieee80211com_t *ic)
227 227 {
228 228 return (ENETRESET);
229 229 }
230 230
231 231 /*
232 232 * Convert channel to IEEE channel number.
233 233 */
234 234 uint32_t
235 235 ieee80211_chan2ieee(ieee80211com_t *ic, struct ieee80211_channel *ch)
236 236 {
237 237 if ((ic->ic_sup_channels <= ch) &&
238 238 (ch <= &ic->ic_sup_channels[IEEE80211_CHAN_MAX])) {
239 239 return (ch - ic->ic_sup_channels);
240 240 } else if (ch == IEEE80211_CHAN_ANYC) {
241 241 return (IEEE80211_CHAN_ANY);
242 242 } else if (ch != NULL) {
243 243 ieee80211_err("invalid channel freq %u flags %x\n",
244 244 ch->ich_freq, ch->ich_flags);
245 245 return (0);
246 246 }
247 247 ieee80211_err("invalid channel (NULL)\n"); /* ch == NULL */
248 248 return (0);
249 249 }
250 250
251 251 /*
252 252 * Convert IEEE channel number to MHz frequency.
253 253 * chan IEEE channel number
254 254 * flags specify whether the frequency is in the 2GHz ISM
255 255 * band or the 5GHz band
256 256 *
257 257 * 802.11b 2GHz: 14 channels, each 5 MHz wide. Channel 1 is placed
258 258 * at 2.412 GHz, channel 2 at 2.417 GHz, and so on up to channel 13
259 259 * at 2.472 GHz. Channel 14 was defined especially for operation in
260 260 * Japan, and has a center frequency 2.484 GHz.
261 261 * 802.11g 2GHz: adopts the frequency plan of 802.11b. Japan only
262 262 * allows 802.11g operation in channels 1-13
263 263 * 802.11a 5GHz: starting every 5 MHz
264 264 * 802.11b/g channels 15-24 (2512-2692) are used by some implementation
265 265 * (Atheros etc.)
266 266 */
267 267 uint32_t
268 268 ieee80211_ieee2mhz(uint32_t chan, uint32_t flags)
269 269 {
270 270 if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
271 271 if (chan == 14)
272 272 return (2484);
273 273 if (chan < 14)
274 274 return (2412 + (chan - 1) * 5);
275 275 else
276 276 return (2512 + ((chan - 15) * 20));
277 277 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */
278 278 return (5000 + (chan * 5)); /* OFDM */
279 279 } else { /* either, guess */
280 280 if (chan == 14)
281 281 return (2484);
282 282 if (chan < 14) /* 0-13 */
283 283 return (2412 + (chan - 1) * 5);
284 284 if (chan < 27) /* 15-26 */
285 285 return (2512 + ((chan - 15) * 20));
286 286 return (5000 + (chan * 5));
287 287 }
288 288 }
289 289
290 290 /*
291 291 * Do late attach work. It must be called by the driver after
292 292 * calling ieee80211_attach() and before calling most ieee80211
293 293 * functions.
294 294 */
295 295 void
296 296 ieee80211_media_init(ieee80211com_t *ic)
297 297 {
298 298 /*
299 299 * Do late attach work that must wait for any subclass
300 300 * (i.e. driver) work such as overriding methods.
301 301 */
302 302 ieee80211_node_lateattach(ic);
303 303 }
304 304
305 305 /*
306 306 * Start Watchdog timer. After count down timer(s), ic_watchdog
307 307 * will be called
308 308 */
309 309 void
310 310 ieee80211_start_watchdog(ieee80211com_t *ic, uint32_t timer)
311 311 {
312 312 if (ic->ic_watchdog_timer == 0 && ic->ic_watchdog != NULL) {
313 313 ic->ic_watchdog_timer = timeout(ic->ic_watchdog, ic,
314 314 drv_usectohz(1000000 * timer));
315 315 }
316 316 }
317 317
318 318 /*
319 319 * Stop watchdog timer.
320 320 */
321 321 void
322 322 ieee80211_stop_watchdog(ieee80211com_t *ic)
323 323 {
324 324 if (ic->ic_watchdog_timer != 0) {
325 325 if (ic->ic_watchdog != NULL)
326 326 (void) untimeout(ic->ic_watchdog_timer);
327 327 ic->ic_watchdog_timer = 0;
328 328 }
329 329 }
330 330
331 331 /*
332 332 * Called from a driver's xxx_watchdog routine. It is used to
333 333 * perform periodic cleanup of state for net80211, as well as
334 334 * timeout scans.
335 335 */
336 336 void
337 337 ieee80211_watchdog(void *arg)
338 338 {
339 339 ieee80211com_t *ic = arg;
340 340 struct ieee80211_impl *im = ic->ic_private;
341 341 ieee80211_node_table_t *nt;
342 342 int inact_timer = 0;
343 343
344 344 if (ic->ic_state == IEEE80211_S_INIT)
345 345 return;
346 346
347 347 IEEE80211_LOCK(ic);
348 348 if ((im->im_mgt_timer != 0) && (--im->im_mgt_timer == 0)) {
349 349 IEEE80211_UNLOCK(ic);
350 350 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
351 351 IEEE80211_LOCK(ic);
352 352 }
353 353
354 354 nt = &ic->ic_scan;
355 355 if (nt->nt_inact_timer != 0) {
356 356 if (--nt->nt_inact_timer == 0)
357 357 nt->nt_timeout(nt);
358 358 inact_timer += nt->nt_inact_timer;
359 359 }
360 360 nt = &ic->ic_sta;
361 361 if (nt->nt_inact_timer != 0) {
362 362 if (--nt->nt_inact_timer == 0)
363 363 nt->nt_timeout(nt);
364 364 inact_timer += nt->nt_inact_timer;
365 365 }
366 366
367 367 IEEE80211_UNLOCK(ic);
368 368
369 369 if (im->im_mgt_timer != 0 || inact_timer > 0)
370 370 ieee80211_start_watchdog(ic, 1);
371 371 }
372 372
373 373 /*
374 374 * Set the current phy mode and recalculate the active channel
375 375 * set and supported rates based on the available channels for
376 376 * this mode. Also select a new BSS channel if the current one
377 377 * is inappropriate for this mode.
378 378 * This function is called by net80211, and not intended to be
379 379 * called directly.
380 380 */
381 381 static int
382 382 ieee80211_setmode(ieee80211com_t *ic, enum ieee80211_phymode mode)
383 383 {
384 384 static const uint32_t chanflags[] = {
385 385 0, /* IEEE80211_MODE_AUTO */
386 386 IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */
387 387 IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
388 388 IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */
389 389 IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */
390 390 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */
391 391 IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */
392 392 IEEE80211_CHAN_ST, /* IEEE80211_MODE_STURBO_A */
393 393 IEEE80211_CHAN_A, /* IEEE80211_MODE_11NA (check legacy) */
394 394 IEEE80211_CHAN_G, /* IEEE80211_MODE_11NG (check legacy) */
395 395 };
396 396 struct ieee80211_channel *ch;
397 397 uint32_t modeflags;
398 398 int i;
399 399 int achannels = 0;
400 400
401 401 /* validate new mode */
402 402 if ((ic->ic_modecaps & (1 << mode)) == 0) {
403 403 ieee80211_err("ieee80211_setmode(): mode %u not supported"
404 404 " (caps 0x%x)\n", mode, ic->ic_modecaps);
405 405 return (EINVAL);
406 406 }
407 407
408 408 /*
409 409 * Verify at least one channel is present in the available
410 410 * channel list before committing to the new mode.
411 411 * Calculate the active channel set.
412 412 */
413 413 ASSERT(mode < IEEE80211_N(chanflags));
414 414 modeflags = chanflags[mode];
415 415 bzero(ic->ic_chan_active, sizeof (ic->ic_chan_active));
416 416 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
417 417 ch = &ic->ic_sup_channels[i];
418 418 if (ch->ich_flags == 0)
419 419 continue;
420 420 if (mode == IEEE80211_MODE_AUTO) {
421 421 /* take anything but pure turbo channels */
422 422 if ((ch->ich_flags & ~IEEE80211_CHAN_TURBO) != 0) {
423 423 ieee80211_setbit(ic->ic_chan_active, i);
424 424 achannels++;
425 425 }
426 426 } else {
427 427 if ((ch->ich_flags & modeflags) == modeflags) {
428 428 ieee80211_setbit(ic->ic_chan_active, i);
429 429 achannels++;
430 430 }
431 431 }
432 432 }
433 433 if (achannels == 0) {
434 434 ieee80211_err("ieee80211_setmode(): "
435 435 "no channel found for mode %u\n", mode);
436 436 return (EINVAL);
437 437 }
438 438
439 439 /*
440 440 * If no current/default channel is setup or the current
441 441 * channel is wrong for the mode then pick the first
442 442 * available channel from the active list. This is likely
443 443 * not the right one.
444 444 */
445 445 if (ic->ic_ibss_chan == NULL ||
446 446 ieee80211_isclr(ic->ic_chan_active,
447 447 ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
448 448 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
449 449 if (ieee80211_isset(ic->ic_chan_active, i)) {
450 450 ic->ic_ibss_chan = &ic->ic_sup_channels[i];
451 451 break;
452 452 }
453 453 }
454 454 }
455 455 /*
456 456 * If the desired channel is set but no longer valid then reset it.
457 457 */
458 458 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
459 459 ieee80211_isclr(ic->ic_chan_active,
460 460 ieee80211_chan2ieee(ic, ic->ic_des_chan))) {
461 461 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
462 462 }
463 463
464 464 /*
465 465 * Do mode-specific rate setup.
466 466 */
467 467 if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B)
468 468 ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode);
469 469
470 470 /*
471 471 * Setup an initial rate set according to the
472 472 * current/default channel. This will be changed
473 473 * when scanning but must exist now so drivers have
474 474 * consistent state of ic_bsschan.
475 475 */
476 476 if (ic->ic_bss != NULL)
477 477 ic->ic_bss->in_rates = ic->ic_sup_rates[mode];
478 478 ic->ic_curmode = mode;
479 479 ieee80211_reset_erp(ic); /* reset ERP state */
480 480 ieee80211_wme_initparams(ic); /* reset WME stat */
481 481
482 482 return (0);
483 483 }
484 484
485 485 /*
486 486 * Return the phy mode for with the specified channel so the
487 487 * caller can select a rate set. This is problematic for channels
488 488 * where multiple operating modes are possible (e.g. 11g+11b).
489 489 * In those cases we defer to the current operating mode when set.
490 490 */
491 491 /* ARGSUSED */
492 492 enum ieee80211_phymode
493 493 ieee80211_chan2mode(ieee80211com_t *ic, struct ieee80211_channel *chan)
494 494 {
495 495 if (IEEE80211_IS_CHAN_HTA(chan))
496 496 return (IEEE80211_MODE_11NA);
497 497 else if (IEEE80211_IS_CHAN_HTG(chan))
498 498 return (IEEE80211_MODE_11NG);
499 499 else if (IEEE80211_IS_CHAN_108G(chan))
500 500 return (IEEE80211_MODE_TURBO_G);
501 501 else if (IEEE80211_IS_CHAN_ST(chan))
502 502 return (IEEE80211_MODE_STURBO_A);
503 503 else if (IEEE80211_IS_CHAN_T(chan))
504 504 return (IEEE80211_MODE_TURBO_A);
505 505 else if (IEEE80211_IS_CHAN_A(chan))
506 506 return (IEEE80211_MODE_11A);
507 507 else if (IEEE80211_IS_CHAN_ANYG(chan))
508 508 return (IEEE80211_MODE_11G);
509 509 else if (IEEE80211_IS_CHAN_B(chan))
510 510 return (IEEE80211_MODE_11B);
511 511 else if (IEEE80211_IS_CHAN_FHSS(chan))
512 512 return (IEEE80211_MODE_FH);
513 513
514 514 /* NB: should not get here */
515 515 ieee80211_err("cannot map channel to mode; freq %u flags 0x%x\n",
516 516 chan->ich_freq, chan->ich_flags);
517 517
518 518 return (IEEE80211_MODE_11B);
519 519 }
520 520
521 521 const struct ieee80211_rateset *
522 522 ieee80211_get_suprates(ieee80211com_t *ic, struct ieee80211_channel *c)
523 523 {
524 524 if (IEEE80211_IS_CHAN_HTA(c))
525 525 return (&ic->ic_sup_rates[IEEE80211_MODE_11A]);
526 526 if (IEEE80211_IS_CHAN_HTG(c)) {
527 527 return (&ic->ic_sup_rates[IEEE80211_MODE_11G]);
528 528 }
529 529 return (&ic->ic_sup_rates[ieee80211_chan2mode(ic, c)]);
530 530 }
531 531
532 532 /*
533 533 * Locate a channel given a frequency+flags. We cache
534 534 * the previous lookup to optimize swithing between two
535 535 * channels--as happens with dynamic turbo.
536 536 */
537 537 struct ieee80211_channel *
538 538 ieee80211_find_channel(ieee80211com_t *ic, int freq, int flags)
539 539 {
540 540 struct ieee80211_channel *c;
541 541 int i;
542 542
543 543 flags &= IEEE80211_CHAN_ALLTURBO;
544 544 /* brute force search */
545 545 for (i = 0; i < IEEE80211_CHAN_MAX; i++) {
546 546 c = &ic->ic_sup_channels[i];
547 547 if (c->ich_freq == freq &&
548 548 (c->ich_flags & IEEE80211_CHAN_ALLTURBO) == flags)
549 549 return (c);
550 550 }
551 551 return (NULL);
552 552 }
553 553
554 554 /*
555 555 * Return the size of the 802.11 header for a management or data frame.
556 556 */
557 557 int
558 558 ieee80211_hdrsize(const void *data)
559 559 {
560 560 const struct ieee80211_frame *wh = data;
561 561 int size = sizeof (struct ieee80211_frame);
562 562
563 563 /* NB: we don't handle control frames */
564 564 ASSERT((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) !=
565 565 IEEE80211_FC0_TYPE_CTL);
566 566 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
567 567 size += IEEE80211_ADDR_LEN;
568 568 if (IEEE80211_QOS_HAS_SEQ(wh))
569 569 size += sizeof (uint16_t);
570 570
571 571 return (size);
572 572 }
573 573
574 574 /*
575 575 * Return the space occupied by the 802.11 header and any
576 576 * padding required by the driver. This works for a
577 577 * management or data frame.
578 578 */
579 579 int
580 580 ieee80211_hdrspace(ieee80211com_t *ic, const void *data)
581 581 {
582 582 int size = ieee80211_hdrsize(data);
583 583 if (ic->ic_flags & IEEE80211_F_DATAPAD)
584 584 size = roundup(size, sizeof (uint32_t));
585 585 return (size);
586 586 }
587 587
588 588 /*
589 589 * Like ieee80211_hdrsize, but handles any type of frame.
590 590 */
591 591 int
592 592 ieee80211_anyhdrsize(const void *data)
593 593 {
594 594 const struct ieee80211_frame *wh = data;
595 595
596 596 if ((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) {
597 597 switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
598 598 case IEEE80211_FC0_SUBTYPE_CTS:
599 599 case IEEE80211_FC0_SUBTYPE_ACK:
600 600 return (sizeof (struct ieee80211_frame_ack));
601 601 case IEEE80211_FC0_SUBTYPE_BAR:
602 602 return (sizeof (struct ieee80211_frame_bar));
603 603 }
604 604 return (sizeof (struct ieee80211_frame_min));
605 605 } else
606 606 return (ieee80211_hdrsize(data));
607 607 }
608 608
609 609 /*
610 610 * Like ieee80211_hdrspace, but handles any type of frame.
611 611 */
612 612 int
613 613 ieee80211_anyhdrspace(ieee80211com_t *ic, const void *data)
614 614 {
615 615 int size = ieee80211_anyhdrsize(data);
616 616 if (ic->ic_flags & IEEE80211_F_DATAPAD)
617 617 size = roundup(size, sizeof (uint32_t));
618 618 return (size);
619 619 }
620 620
621 621 /*
622 622 * Allocate and setup a management frame of the specified
623 623 * size. We return the mblk and a pointer to the start
624 624 * of the contiguous data area that's been reserved based
625 625 * on the packet length.
626 626 */
627 627 mblk_t *
628 628 ieee80211_getmgtframe(uint8_t **frm, int pktlen)
629 629 {
630 630 mblk_t *mp;
631 631 int len;
632 632
633 633 len = sizeof (struct ieee80211_frame) + pktlen;
634 634 mp = allocb(len, BPRI_MED);
635 635 if (mp != NULL) {
636 636 *frm = mp->b_rptr + sizeof (struct ieee80211_frame);
637 637 mp->b_wptr = mp->b_rptr + len;
638 638 } else {
639 639 ieee80211_err("ieee80211_getmgtframe: "
640 640 "alloc frame failed, %d\n", len);
641 641 }
642 642 return (mp);
643 643 }
644 644
645 645 /*
646 646 * Send system messages to notify the device has joined a WLAN.
647 647 * This is an OS specific function. Solaris marks link status
648 648 * as up.
649 649 */
650 650 void
651 651 ieee80211_notify_node_join(ieee80211com_t *ic, ieee80211_node_t *in)
652 652 {
653 653 if (in == ic->ic_bss)
654 654 mac_link_update(ic->ic_mach, LINK_STATE_UP);
655 655 ieee80211_notify(ic, EVENT_ASSOC); /* notify WPA service */
656 656 }
657 657
658 658 /*
659 659 * Send system messages to notify the device has left a WLAN.
660 660 * This is an OS specific function. Solaris marks link status
661 661 * as down.
662 662 */
663 663 void
664 664 ieee80211_notify_node_leave(ieee80211com_t *ic, ieee80211_node_t *in)
665 665 {
666 666 if (in == ic->ic_bss)
667 667 mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
668 668 ieee80211_notify(ic, EVENT_DISASSOC); /* notify WPA service */
669 669 }
670 670
671 671
672 672 /*
673 673 * Get 802.11 kstats defined in ieee802.11(5)
674 674 *
675 675 * Return 0 on success
676 676 */
677 677 int
678 678 ieee80211_stat(ieee80211com_t *ic, uint_t stat, uint64_t *val)
679 679 {
680 680 ASSERT(val != NULL);
681 681 IEEE80211_LOCK(ic);
682 682 switch (stat) {
683 683 case WIFI_STAT_TX_FRAGS:
684 684 *val = ic->ic_stats.is_tx_frags;
685 685 break;
686 686 case WIFI_STAT_MCAST_TX:
687 687 *val = ic->ic_stats.is_tx_mcast;
688 688 break;
689 689 case WIFI_STAT_TX_FAILED:
690 690 *val = ic->ic_stats.is_tx_failed;
691 691 break;
692 692 case WIFI_STAT_TX_RETRANS:
693 693 *val = ic->ic_stats.is_tx_retries;
694 694 break;
695 695 case WIFI_STAT_RTS_SUCCESS:
696 696 *val = ic->ic_stats.is_rts_success;
697 697 break;
698 698 case WIFI_STAT_RTS_FAILURE:
699 699 *val = ic->ic_stats.is_rts_failure;
700 700 break;
701 701 case WIFI_STAT_ACK_FAILURE:
702 702 *val = ic->ic_stats.is_ack_failure;
703 703 break;
704 704 case WIFI_STAT_RX_FRAGS:
705 705 *val = ic->ic_stats.is_rx_frags;
706 706 break;
707 707 case WIFI_STAT_MCAST_RX:
708 708 *val = ic->ic_stats.is_rx_mcast;
709 709 break;
710 710 case WIFI_STAT_RX_DUPS:
711 711 *val = ic->ic_stats.is_rx_dups;
712 712 break;
713 713 case WIFI_STAT_FCS_ERRORS:
714 714 *val = ic->ic_stats.is_fcs_errors;
715 715 break;
716 716 case WIFI_STAT_WEP_ERRORS:
717 717 *val = ic->ic_stats.is_wep_errors;
718 718 break;
719 719 }
720 720 IEEE80211_UNLOCK(ic);
721 721 return (0);
722 722 }
723 723
724 724 /*
725 725 * Attach network interface to the 802.11 support module. This
726 726 * function must be called before using any of the ieee80211
727 727 * functionss. The parameter "ic" MUST be initialized to tell
728 728 * net80211 about interface's capabilities.
729 729 */
730 730 void
731 731 ieee80211_attach(ieee80211com_t *ic)
732 732 {
733 733 struct ieee80211_impl *im;
734 734 struct ieee80211_channel *ch;
735 735 int i;
736 736
737 737 /* Check mandatory callback functions not NULL */
738 738 ASSERT(ic->ic_xmit != NULL);
739 739
740 740 mutex_init(&ic->ic_genlock, NULL, MUTEX_DRIVER, NULL);
741 741 mutex_init(&ic->ic_doorlock, NULL, MUTEX_DRIVER, NULL);
742 742
743 743 im = kmem_alloc(sizeof (ieee80211_impl_t), KM_SLEEP);
744 744 ic->ic_private = im;
745 745 cv_init(&im->im_scan_cv, NULL, CV_DRIVER, NULL);
746 746
747 747 /*
748 748 * Fill in 802.11 available channel set, mark
749 749 * all available channels as active, and pick
750 750 * a default channel if not already specified.
751 751 */
752 752 bzero(im->im_chan_avail, sizeof (im->im_chan_avail));
753 753 ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO;
754 754 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
755 755 ch = &ic->ic_sup_channels[i];
756 756 if (ch->ich_flags) {
757 757 /* Verify driver passed us valid data */
758 758 if (i != ieee80211_chan2ieee(ic, ch)) {
759 759 ieee80211_err("bad channel ignored: "
760 760 "freq %u flags%x number %u\n",
761 761 ch->ich_freq, ch->ich_flags, i);
762 762 ch->ich_flags = 0;
763 763 continue;
764 764 }
765 765 ieee80211_setbit(im->im_chan_avail, i);
766 766 /* Identify mode capabilities */
767 767 if (IEEE80211_IS_CHAN_A(ch))
768 768 ic->ic_modecaps |= 1 << IEEE80211_MODE_11A;
769 769 if (IEEE80211_IS_CHAN_B(ch))
770 770 ic->ic_modecaps |= 1 << IEEE80211_MODE_11B;
771 771 if (IEEE80211_IS_CHAN_PUREG(ch))
772 772 ic->ic_modecaps |= 1 << IEEE80211_MODE_11G;
773 773 if (IEEE80211_IS_CHAN_FHSS(ch))
774 774 ic->ic_modecaps |= 1 << IEEE80211_MODE_FH;
775 775 if (IEEE80211_IS_CHAN_T(ch))
776 776 ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_A;
777 777 if (IEEE80211_IS_CHAN_108G(ch))
778 778 ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_G;
779 779 if (IEEE80211_IS_CHAN_ST(ch))
780 780 ic->ic_modecaps |= 1 << IEEE80211_MODE_STURBO_A;
781 781 if (IEEE80211_IS_CHAN_HTA(ch))
782 782 ic->ic_modecaps |= 1 << IEEE80211_MODE_11NA;
783 783 if (IEEE80211_IS_CHAN_HTG(ch))
784 784 ic->ic_modecaps |= 1 << IEEE80211_MODE_11NG;
785 785 if (ic->ic_curchan == NULL) {
786 786 /* arbitrarily pick the first channel */
787 787 ic->ic_curchan = &ic->ic_sup_channels[i];
788 788 }
789 789 }
790 790 }
791 791 /* validate ic->ic_curmode */
792 792 if ((ic->ic_modecaps & (1 << ic->ic_curmode)) == 0)
793 793 ic->ic_curmode = IEEE80211_MODE_AUTO;
794 794 ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */
795 795 (void) ieee80211_setmode(ic, ic->ic_curmode);
796 796
797 797 if (ic->ic_caps & IEEE80211_C_WME) /* enable if capable */
798 798 ic->ic_flags |= IEEE80211_F_WME;
799 799 if (ic->ic_caps & IEEE80211_C_BURST)
800 800 ic->ic_flags |= IEEE80211_F_BURST;
801 801 ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
802 802 ic->ic_lintval = ic->ic_bintval;
803 803 ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
804 804 ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
805 805
806 806 ic->ic_reset = ieee80211_default_reset;
807 807
808 808 ieee80211_node_attach(ic);
809 809 ieee80211_proto_attach(ic);
810 810 ieee80211_crypto_attach(ic);
811 811 ieee80211_ht_attach(ic);
812 812
813 813 ic->ic_watchdog_timer = 0;
814 814 }
815 815
816 816 /*
817 817 * Free any ieee80211 structures associated with the driver.
818 818 */
819 819 void
820 820 ieee80211_detach(ieee80211com_t *ic)
821 821 {
822 822 struct ieee80211_impl *im = ic->ic_private;
823 823
824 824 ieee80211_stop_watchdog(ic);
825 825 cv_destroy(&im->im_scan_cv);
826 826 kmem_free(im, sizeof (ieee80211_impl_t));
827 827
828 828 if (ic->ic_opt_ie != NULL)
829 829 ieee80211_free(ic->ic_opt_ie);
830 830
831 831 ieee80211_ht_detach(ic);
832 832 ieee80211_node_detach(ic);
833 833 ieee80211_crypto_detach(ic);
834 834
835 835 mutex_destroy(&ic->ic_genlock);
↓ open down ↓ |
835 lines elided |
↑ open up ↑ |
836 836 mutex_destroy(&ic->ic_doorlock);
837 837 }
838 838
839 839 static struct modlmisc i_wifi_modlmisc = {
840 840 &mod_miscops,
841 841 "IEEE80211 Kernel Module v2.0"
842 842 };
843 843
844 844 static struct modlinkage i_wifi_modlinkage = {
845 845 MODREV_1,
846 - &i_wifi_modlmisc,
847 - NULL
846 + { &i_wifi_modlmisc, NULL }
848 847 };
849 848
850 849 /*
851 850 * modlinkage functions
852 851 */
853 852 int
854 853 _init(void)
855 854 {
856 855 return (mod_install(&i_wifi_modlinkage));
857 856 }
858 857
859 858 int
860 859 _fini(void)
861 860 {
862 861 return (mod_remove(&i_wifi_modlinkage));
863 862 }
864 863
865 864 int
866 865 _info(struct modinfo *modinfop)
867 866 {
868 867 return (mod_info(&i_wifi_modlinkage, modinfop));
869 868 }
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX