2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
39 * IEEE 802.11 generic handler
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/cmn_err.h>
45 #include <sys/modctl.h>
46 #include <sys/stropts.h>
48 #include <sys/mac_provider.h>
49 #include "net80211_impl.h"
51 uint32_t ieee80211_debug
= 0x0; /* debug msg flags */
53 const char *ieee80211_phymode_name
[] = {
54 "auto", /* IEEE80211_MODE_AUTO */
55 "11a", /* IEEE80211_MODE_11A */
56 "11b", /* IEEE80211_MODE_11B */
57 "11g", /* IEEE80211_MODE_11G */
58 "FH", /* IEEE80211_MODE_FH */
59 "turboA", /* IEEE80211_MODE_TURBO_A */
60 "turboG", /* IEEE80211_MODE_TURBO_G */
61 "sturboA", /* IEEE80211_MODE_STURBO_A */
62 "11na", /* IEEE80211_MODE_11NA */
63 "11ng", /* IEEE80211_MODE_11NG */
66 #define IEEE80211_DPRINT(_level, _fmt) do { \
69 va_start(ap, (_fmt)); \
70 vcmn_err((_level), (_fmt), ap); \
76 * Print error messages
79 ieee80211_err(const int8_t *fmt
, ...)
81 IEEE80211_DPRINT(CE_WARN
, fmt
);
85 * Print debug messages
88 ieee80211_dbg(uint32_t flag
, const int8_t *fmt
, ...)
90 if (flag
& ieee80211_debug
)
91 IEEE80211_DPRINT(CE_CONT
, fmt
);
95 * Alloc memory, and save the size
98 ieee80211_malloc(size_t size
)
100 void *p
= kmem_zalloc((size
+ 4), KM_SLEEP
);
108 ieee80211_free(void *p
)
110 void *tp
= (char *)p
- 4;
111 kmem_free((char *)p
- 4, *(int *)tp
+ 4);
115 ieee80211_mac_update(ieee80211com_t
*ic
)
117 wifi_data_t wd
= { 0 };
118 ieee80211_node_t
*in
;
121 * We can send data now; update the fastpath with our
122 * current associated BSSID and other relevant settings.
125 wd
.wd_secalloc
= ieee80211_crypto_getciphertype(ic
);
126 wd
.wd_opmode
= ic
->ic_opmode
;
127 IEEE80211_ADDR_COPY(wd
.wd_bssid
, in
->in_bssid
);
129 if (in
->in_flags
& (IEEE80211_NODE_QOS
|IEEE80211_NODE_HT
)) {
131 if (ic
->ic_flags
& IEEE80211_F_DATAPAD
)
132 wd
.wd_qospad
= roundup(wd
.wd_qospad
, sizeof (uint32_t));
134 (void) mac_pdata_update(ic
->ic_mach
, &wd
, sizeof (wd
));
135 mac_tx_update(ic
->ic_mach
);
136 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_mac_update"
137 "(cipher = %d)\n", wd
.wd_secalloc
);
141 * ieee80211_event_thread
142 * open door of wpa, send event to wpad service
145 ieee80211_event_thread(void *arg
)
147 ieee80211com_t
*ic
= arg
;
148 door_handle_t event_door
= NULL
; /* Door for upcalls */
152 mutex_enter(&ic
->ic_doorlock
);
154 ev
.event
= ic
->ic_eventq
[ic
->ic_evq_head
];
156 if (ic
->ic_evq_head
>= MAX_EVENT
)
159 ieee80211_dbg(IEEE80211_MSG_DEBUG
, "ieee80211_event(%d)\n", ev
.event
);
161 * Locate the door used for upcalls
163 if (door_ki_open(ic
->ic_wpadoor
, &event_door
) != 0) {
164 ieee80211_err("ieee80211_event: door_ki_open(%s) failed\n",
169 darg
.data_ptr
= (char *)&ev
;
170 darg
.data_size
= sizeof (wl_events_t
);
171 darg
.desc_ptr
= NULL
;
176 if (door_ki_upcall_limited(event_door
, &darg
, NULL
, SIZE_MAX
, 0) != 0) {
177 ieee80211_err("ieee80211_event: door_ki_upcall() failed\n");
180 if (event_door
) { /* release our hold (if any) */
181 door_ki_rele(event_door
);
185 mutex_exit(&ic
->ic_doorlock
);
189 * Notify state transition event message to WPA daemon
192 ieee80211_notify(ieee80211com_t
*ic
, wpa_event_type event
)
194 if ((ic
->ic_flags
& IEEE80211_F_WPA
) == 0)
195 return; /* Not running on WPA mode */
197 ic
->ic_eventq
[ic
->ic_evq_tail
] = event
;
199 if (ic
->ic_evq_tail
>= MAX_EVENT
) ic
->ic_evq_tail
= 0;
202 (void) timeout(ieee80211_event_thread
, (void *)ic
, 0);
209 ieee80211_register_door(ieee80211com_t
*ic
, const char *drvname
, int inst
)
211 (void) snprintf(ic
->ic_wpadoor
, MAX_IEEE80211STR
, "%s_%s%d",
212 WPA_DOOR
, drvname
, inst
);
216 * Default reset method for use with the ioctl support. This
217 * method is invoked after any state change in the 802.11
218 * layer that should be propagated to the hardware but not
219 * require re-initialization of the 802.11 state machine (e.g
220 * rescanning for an ap). We always return ENETRESET which
221 * should cause the driver to re-initialize the device. Drivers
222 * can override this method to implement more optimized support.
226 ieee80211_default_reset(ieee80211com_t
*ic
)
232 * Convert channel to IEEE channel number.
235 ieee80211_chan2ieee(ieee80211com_t
*ic
, struct ieee80211_channel
*ch
)
237 if ((ic
->ic_sup_channels
<= ch
) &&
238 (ch
<= &ic
->ic_sup_channels
[IEEE80211_CHAN_MAX
])) {
239 return (ch
- ic
->ic_sup_channels
);
240 } else if (ch
== IEEE80211_CHAN_ANYC
) {
241 return (IEEE80211_CHAN_ANY
);
242 } else if (ch
!= NULL
) {
243 ieee80211_err("invalid channel freq %u flags %x\n",
244 ch
->ich_freq
, ch
->ich_flags
);
247 ieee80211_err("invalid channel (NULL)\n"); /* ch == NULL */
252 * Convert IEEE channel number to MHz frequency.
253 * chan IEEE channel number
254 * flags specify whether the frequency is in the 2GHz ISM
255 * band or the 5GHz band
257 * 802.11b 2GHz: 14 channels, each 5 MHz wide. Channel 1 is placed
258 * at 2.412 GHz, channel 2 at 2.417 GHz, and so on up to channel 13
259 * at 2.472 GHz. Channel 14 was defined especially for operation in
260 * Japan, and has a center frequency 2.484 GHz.
261 * 802.11g 2GHz: adopts the frequency plan of 802.11b. Japan only
262 * allows 802.11g operation in channels 1-13
263 * 802.11a 5GHz: starting every 5 MHz
264 * 802.11b/g channels 15-24 (2512-2692) are used by some implementation
268 ieee80211_ieee2mhz(uint32_t chan
, uint32_t flags
)
270 if (flags
& IEEE80211_CHAN_2GHZ
) { /* 2GHz band */
274 return (2412 + (chan
- 1) * 5);
276 return (2512 + ((chan
- 15) * 20));
277 } else if (flags
& IEEE80211_CHAN_5GHZ
) { /* 5Ghz band */
278 return (5000 + (chan
* 5)); /* OFDM */
279 } else { /* either, guess */
282 if (chan
< 14) /* 0-13 */
283 return (2412 + (chan
- 1) * 5);
284 if (chan
< 27) /* 15-26 */
285 return (2512 + ((chan
- 15) * 20));
286 return (5000 + (chan
* 5));
291 * Do late attach work. It must be called by the driver after
292 * calling ieee80211_attach() and before calling most ieee80211
296 ieee80211_media_init(ieee80211com_t
*ic
)
299 * Do late attach work that must wait for any subclass
300 * (i.e. driver) work such as overriding methods.
302 ieee80211_node_lateattach(ic
);
306 * Start Watchdog timer. After count down timer(s), ic_watchdog
310 ieee80211_start_watchdog(ieee80211com_t
*ic
, uint32_t timer
)
312 if (ic
->ic_watchdog_timer
== 0 && ic
->ic_watchdog
!= NULL
) {
313 ic
->ic_watchdog_timer
= timeout(ic
->ic_watchdog
, ic
,
314 drv_usectohz(1000000 * timer
));
319 * Stop watchdog timer.
322 ieee80211_stop_watchdog(ieee80211com_t
*ic
)
324 if (ic
->ic_watchdog_timer
!= 0) {
325 if (ic
->ic_watchdog
!= NULL
)
326 (void) untimeout(ic
->ic_watchdog_timer
);
327 ic
->ic_watchdog_timer
= 0;
332 * Called from a driver's xxx_watchdog routine. It is used to
333 * perform periodic cleanup of state for net80211, as well as
337 ieee80211_watchdog(void *arg
)
339 ieee80211com_t
*ic
= arg
;
340 struct ieee80211_impl
*im
= ic
->ic_private
;
341 ieee80211_node_table_t
*nt
;
344 if (ic
->ic_state
== IEEE80211_S_INIT
)
348 if ((im
->im_mgt_timer
!= 0) && (--im
->im_mgt_timer
== 0)) {
349 IEEE80211_UNLOCK(ic
);
350 ieee80211_new_state(ic
, IEEE80211_S_SCAN
, -1);
355 if (nt
->nt_inact_timer
!= 0) {
356 if (--nt
->nt_inact_timer
== 0)
358 inact_timer
+= nt
->nt_inact_timer
;
361 if (nt
->nt_inact_timer
!= 0) {
362 if (--nt
->nt_inact_timer
== 0)
364 inact_timer
+= nt
->nt_inact_timer
;
367 IEEE80211_UNLOCK(ic
);
369 if (im
->im_mgt_timer
!= 0 || inact_timer
> 0)
370 ieee80211_start_watchdog(ic
, 1);
374 * Set the current phy mode and recalculate the active channel
375 * set and supported rates based on the available channels for
376 * this mode. Also select a new BSS channel if the current one
377 * is inappropriate for this mode.
378 * This function is called by net80211, and not intended to be
382 ieee80211_setmode(ieee80211com_t
*ic
, enum ieee80211_phymode mode
)
384 static const uint32_t chanflags
[] = {
385 0, /* IEEE80211_MODE_AUTO */
386 IEEE80211_CHAN_A
, /* IEEE80211_MODE_11A */
387 IEEE80211_CHAN_B
, /* IEEE80211_MODE_11B */
388 IEEE80211_CHAN_PUREG
, /* IEEE80211_MODE_11G */
389 IEEE80211_CHAN_FHSS
, /* IEEE80211_MODE_FH */
390 IEEE80211_CHAN_T
, /* IEEE80211_MODE_TURBO_A */
391 IEEE80211_CHAN_108G
, /* IEEE80211_MODE_TURBO_G */
392 IEEE80211_CHAN_ST
, /* IEEE80211_MODE_STURBO_A */
393 IEEE80211_CHAN_A
, /* IEEE80211_MODE_11NA (check legacy) */
394 IEEE80211_CHAN_G
, /* IEEE80211_MODE_11NG (check legacy) */
396 struct ieee80211_channel
*ch
;
401 /* validate new mode */
402 if ((ic
->ic_modecaps
& (1 << mode
)) == 0) {
403 ieee80211_err("ieee80211_setmode(): mode %u not supported"
404 " (caps 0x%x)\n", mode
, ic
->ic_modecaps
);
409 * Verify at least one channel is present in the available
410 * channel list before committing to the new mode.
411 * Calculate the active channel set.
413 ASSERT(mode
< IEEE80211_N(chanflags
));
414 modeflags
= chanflags
[mode
];
415 bzero(ic
->ic_chan_active
, sizeof (ic
->ic_chan_active
));
416 for (i
= 0; i
<= IEEE80211_CHAN_MAX
; i
++) {
417 ch
= &ic
->ic_sup_channels
[i
];
418 if (ch
->ich_flags
== 0)
420 if (mode
== IEEE80211_MODE_AUTO
) {
421 /* take anything but pure turbo channels */
422 if ((ch
->ich_flags
& ~IEEE80211_CHAN_TURBO
) != 0) {
423 ieee80211_setbit(ic
->ic_chan_active
, i
);
427 if ((ch
->ich_flags
& modeflags
) == modeflags
) {
428 ieee80211_setbit(ic
->ic_chan_active
, i
);
433 if (achannels
== 0) {
434 ieee80211_err("ieee80211_setmode(): "
435 "no channel found for mode %u\n", mode
);
440 * If no current/default channel is setup or the current
441 * channel is wrong for the mode then pick the first
442 * available channel from the active list. This is likely
445 if (ic
->ic_ibss_chan
== NULL
||
446 ieee80211_isclr(ic
->ic_chan_active
,
447 ieee80211_chan2ieee(ic
, ic
->ic_ibss_chan
))) {
448 for (i
= 0; i
<= IEEE80211_CHAN_MAX
; i
++) {
449 if (ieee80211_isset(ic
->ic_chan_active
, i
)) {
450 ic
->ic_ibss_chan
= &ic
->ic_sup_channels
[i
];
456 * If the desired channel is set but no longer valid then reset it.
458 if (ic
->ic_des_chan
!= IEEE80211_CHAN_ANYC
&&
459 ieee80211_isclr(ic
->ic_chan_active
,
460 ieee80211_chan2ieee(ic
, ic
->ic_des_chan
))) {
461 ic
->ic_des_chan
= IEEE80211_CHAN_ANYC
;
465 * Do mode-specific rate setup.
467 if (mode
== IEEE80211_MODE_11G
|| mode
== IEEE80211_MODE_11B
)
468 ieee80211_setbasicrates(&ic
->ic_sup_rates
[mode
], mode
);
471 * Setup an initial rate set according to the
472 * current/default channel. This will be changed
473 * when scanning but must exist now so drivers have
474 * consistent state of ic_bsschan.
476 if (ic
->ic_bss
!= NULL
)
477 ic
->ic_bss
->in_rates
= ic
->ic_sup_rates
[mode
];
478 ic
->ic_curmode
= mode
;
479 ieee80211_reset_erp(ic
); /* reset ERP state */
480 ieee80211_wme_initparams(ic
); /* reset WME stat */
486 * Return the phy mode for with the specified channel so the
487 * caller can select a rate set. This is problematic for channels
488 * where multiple operating modes are possible (e.g. 11g+11b).
489 * In those cases we defer to the current operating mode when set.
492 enum ieee80211_phymode
493 ieee80211_chan2mode(ieee80211com_t
*ic
, struct ieee80211_channel
*chan
)
495 if (IEEE80211_IS_CHAN_HTA(chan
))
496 return (IEEE80211_MODE_11NA
);
497 else if (IEEE80211_IS_CHAN_HTG(chan
))
498 return (IEEE80211_MODE_11NG
);
499 else if (IEEE80211_IS_CHAN_108G(chan
))
500 return (IEEE80211_MODE_TURBO_G
);
501 else if (IEEE80211_IS_CHAN_ST(chan
))
502 return (IEEE80211_MODE_STURBO_A
);
503 else if (IEEE80211_IS_CHAN_T(chan
))
504 return (IEEE80211_MODE_TURBO_A
);
505 else if (IEEE80211_IS_CHAN_A(chan
))
506 return (IEEE80211_MODE_11A
);
507 else if (IEEE80211_IS_CHAN_ANYG(chan
))
508 return (IEEE80211_MODE_11G
);
509 else if (IEEE80211_IS_CHAN_B(chan
))
510 return (IEEE80211_MODE_11B
);
511 else if (IEEE80211_IS_CHAN_FHSS(chan
))
512 return (IEEE80211_MODE_FH
);
514 /* NB: should not get here */
515 ieee80211_err("cannot map channel to mode; freq %u flags 0x%x\n",
516 chan
->ich_freq
, chan
->ich_flags
);
518 return (IEEE80211_MODE_11B
);
521 const struct ieee80211_rateset
*
522 ieee80211_get_suprates(ieee80211com_t
*ic
, struct ieee80211_channel
*c
)
524 if (IEEE80211_IS_CHAN_HTA(c
))
525 return (&ic
->ic_sup_rates
[IEEE80211_MODE_11A
]);
526 if (IEEE80211_IS_CHAN_HTG(c
)) {
527 return (&ic
->ic_sup_rates
[IEEE80211_MODE_11G
]);
529 return (&ic
->ic_sup_rates
[ieee80211_chan2mode(ic
, c
)]);
533 * Locate a channel given a frequency+flags. We cache
534 * the previous lookup to optimize swithing between two
535 * channels--as happens with dynamic turbo.
537 struct ieee80211_channel
*
538 ieee80211_find_channel(ieee80211com_t
*ic
, int freq
, int flags
)
540 struct ieee80211_channel
*c
;
543 flags
&= IEEE80211_CHAN_ALLTURBO
;
544 /* brute force search */
545 for (i
= 0; i
< IEEE80211_CHAN_MAX
; i
++) {
546 c
= &ic
->ic_sup_channels
[i
];
547 if (c
->ich_freq
== freq
&&
548 (c
->ich_flags
& IEEE80211_CHAN_ALLTURBO
) == flags
)
555 * Return the size of the 802.11 header for a management or data frame.
558 ieee80211_hdrsize(const void *data
)
560 const struct ieee80211_frame
*wh
= data
;
561 int size
= sizeof (struct ieee80211_frame
);
563 /* NB: we don't handle control frames */
564 ASSERT((wh
->i_fc
[0]&IEEE80211_FC0_TYPE_MASK
) !=
565 IEEE80211_FC0_TYPE_CTL
);
566 if ((wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
) == IEEE80211_FC1_DIR_DSTODS
)
567 size
+= IEEE80211_ADDR_LEN
;
568 if (IEEE80211_QOS_HAS_SEQ(wh
))
569 size
+= sizeof (uint16_t);
575 * Return the space occupied by the 802.11 header and any
576 * padding required by the driver. This works for a
577 * management or data frame.
580 ieee80211_hdrspace(ieee80211com_t
*ic
, const void *data
)
582 int size
= ieee80211_hdrsize(data
);
583 if (ic
->ic_flags
& IEEE80211_F_DATAPAD
)
584 size
= roundup(size
, sizeof (uint32_t));
589 * Like ieee80211_hdrsize, but handles any type of frame.
592 ieee80211_anyhdrsize(const void *data
)
594 const struct ieee80211_frame
*wh
= data
;
596 if ((wh
->i_fc
[0]&IEEE80211_FC0_TYPE_MASK
) == IEEE80211_FC0_TYPE_CTL
) {
597 switch (wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
) {
598 case IEEE80211_FC0_SUBTYPE_CTS
:
599 case IEEE80211_FC0_SUBTYPE_ACK
:
600 return (sizeof (struct ieee80211_frame_ack
));
601 case IEEE80211_FC0_SUBTYPE_BAR
:
602 return (sizeof (struct ieee80211_frame_bar
));
604 return (sizeof (struct ieee80211_frame_min
));
606 return (ieee80211_hdrsize(data
));
610 * Like ieee80211_hdrspace, but handles any type of frame.
613 ieee80211_anyhdrspace(ieee80211com_t
*ic
, const void *data
)
615 int size
= ieee80211_anyhdrsize(data
);
616 if (ic
->ic_flags
& IEEE80211_F_DATAPAD
)
617 size
= roundup(size
, sizeof (uint32_t));
622 * Allocate and setup a management frame of the specified
623 * size. We return the mblk and a pointer to the start
624 * of the contiguous data area that's been reserved based
625 * on the packet length.
628 ieee80211_getmgtframe(uint8_t **frm
, int pktlen
)
633 len
= sizeof (struct ieee80211_frame
) + pktlen
;
634 mp
= allocb(len
, BPRI_MED
);
636 *frm
= mp
->b_rptr
+ sizeof (struct ieee80211_frame
);
637 mp
->b_wptr
= mp
->b_rptr
+ len
;
639 ieee80211_err("ieee80211_getmgtframe: "
640 "alloc frame failed, %d\n", len
);
646 * Send system messages to notify the device has joined a WLAN.
647 * This is an OS specific function. Solaris marks link status
651 ieee80211_notify_node_join(ieee80211com_t
*ic
, ieee80211_node_t
*in
)
653 if (in
== ic
->ic_bss
)
654 mac_link_update(ic
->ic_mach
, LINK_STATE_UP
);
655 ieee80211_notify(ic
, EVENT_ASSOC
); /* notify WPA service */
659 * Send system messages to notify the device has left a WLAN.
660 * This is an OS specific function. Solaris marks link status
664 ieee80211_notify_node_leave(ieee80211com_t
*ic
, ieee80211_node_t
*in
)
666 if (in
== ic
->ic_bss
)
667 mac_link_update(ic
->ic_mach
, LINK_STATE_DOWN
);
668 ieee80211_notify(ic
, EVENT_DISASSOC
); /* notify WPA service */
673 * Get 802.11 kstats defined in ieee802.11(5)
675 * Return 0 on success
678 ieee80211_stat(ieee80211com_t
*ic
, uint_t stat
, uint64_t *val
)
683 case WIFI_STAT_TX_FRAGS
:
684 *val
= ic
->ic_stats
.is_tx_frags
;
686 case WIFI_STAT_MCAST_TX
:
687 *val
= ic
->ic_stats
.is_tx_mcast
;
689 case WIFI_STAT_TX_FAILED
:
690 *val
= ic
->ic_stats
.is_tx_failed
;
692 case WIFI_STAT_TX_RETRANS
:
693 *val
= ic
->ic_stats
.is_tx_retries
;
695 case WIFI_STAT_RTS_SUCCESS
:
696 *val
= ic
->ic_stats
.is_rts_success
;
698 case WIFI_STAT_RTS_FAILURE
:
699 *val
= ic
->ic_stats
.is_rts_failure
;
701 case WIFI_STAT_ACK_FAILURE
:
702 *val
= ic
->ic_stats
.is_ack_failure
;
704 case WIFI_STAT_RX_FRAGS
:
705 *val
= ic
->ic_stats
.is_rx_frags
;
707 case WIFI_STAT_MCAST_RX
:
708 *val
= ic
->ic_stats
.is_rx_mcast
;
710 case WIFI_STAT_RX_DUPS
:
711 *val
= ic
->ic_stats
.is_rx_dups
;
713 case WIFI_STAT_FCS_ERRORS
:
714 *val
= ic
->ic_stats
.is_fcs_errors
;
716 case WIFI_STAT_WEP_ERRORS
:
717 *val
= ic
->ic_stats
.is_wep_errors
;
720 IEEE80211_UNLOCK(ic
);
725 * Attach network interface to the 802.11 support module. This
726 * function must be called before using any of the ieee80211
727 * functionss. The parameter "ic" MUST be initialized to tell
728 * net80211 about interface's capabilities.
731 ieee80211_attach(ieee80211com_t
*ic
)
733 struct ieee80211_impl
*im
;
734 struct ieee80211_channel
*ch
;
737 /* Check mandatory callback functions not NULL */
738 ASSERT(ic
->ic_xmit
!= NULL
);
740 mutex_init(&ic
->ic_genlock
, NULL
, MUTEX_DRIVER
, NULL
);
741 mutex_init(&ic
->ic_doorlock
, NULL
, MUTEX_DRIVER
, NULL
);
743 im
= kmem_alloc(sizeof (ieee80211_impl_t
), KM_SLEEP
);
745 cv_init(&im
->im_scan_cv
, NULL
, CV_DRIVER
, NULL
);
748 * Fill in 802.11 available channel set, mark
749 * all available channels as active, and pick
750 * a default channel if not already specified.
752 bzero(im
->im_chan_avail
, sizeof (im
->im_chan_avail
));
753 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_AUTO
;
754 for (i
= 0; i
<= IEEE80211_CHAN_MAX
; i
++) {
755 ch
= &ic
->ic_sup_channels
[i
];
757 /* Verify driver passed us valid data */
758 if (i
!= ieee80211_chan2ieee(ic
, ch
)) {
759 ieee80211_err("bad channel ignored: "
760 "freq %u flags%x number %u\n",
761 ch
->ich_freq
, ch
->ich_flags
, i
);
765 ieee80211_setbit(im
->im_chan_avail
, i
);
766 /* Identify mode capabilities */
767 if (IEEE80211_IS_CHAN_A(ch
))
768 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_11A
;
769 if (IEEE80211_IS_CHAN_B(ch
))
770 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_11B
;
771 if (IEEE80211_IS_CHAN_PUREG(ch
))
772 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_11G
;
773 if (IEEE80211_IS_CHAN_FHSS(ch
))
774 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_FH
;
775 if (IEEE80211_IS_CHAN_T(ch
))
776 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_TURBO_A
;
777 if (IEEE80211_IS_CHAN_108G(ch
))
778 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_TURBO_G
;
779 if (IEEE80211_IS_CHAN_ST(ch
))
780 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_STURBO_A
;
781 if (IEEE80211_IS_CHAN_HTA(ch
))
782 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_11NA
;
783 if (IEEE80211_IS_CHAN_HTG(ch
))
784 ic
->ic_modecaps
|= 1 << IEEE80211_MODE_11NG
;
785 if (ic
->ic_curchan
== NULL
) {
786 /* arbitrarily pick the first channel */
787 ic
->ic_curchan
= &ic
->ic_sup_channels
[i
];
791 /* validate ic->ic_curmode */
792 if ((ic
->ic_modecaps
& (1 << ic
->ic_curmode
)) == 0)
793 ic
->ic_curmode
= IEEE80211_MODE_AUTO
;
794 ic
->ic_des_chan
= IEEE80211_CHAN_ANYC
; /* any channel is ok */
795 (void) ieee80211_setmode(ic
, ic
->ic_curmode
);
797 if (ic
->ic_caps
& IEEE80211_C_WME
) /* enable if capable */
798 ic
->ic_flags
|= IEEE80211_F_WME
;
799 if (ic
->ic_caps
& IEEE80211_C_BURST
)
800 ic
->ic_flags
|= IEEE80211_F_BURST
;
801 ic
->ic_bintval
= IEEE80211_BINTVAL_DEFAULT
;
802 ic
->ic_lintval
= ic
->ic_bintval
;
803 ic
->ic_txpowlimit
= IEEE80211_TXPOWER_MAX
;
804 ic
->ic_bmissthreshold
= IEEE80211_HWBMISS_DEFAULT
;
806 ic
->ic_reset
= ieee80211_default_reset
;
808 ieee80211_node_attach(ic
);
809 ieee80211_proto_attach(ic
);
810 ieee80211_crypto_attach(ic
);
811 ieee80211_ht_attach(ic
);
813 ic
->ic_watchdog_timer
= 0;
817 * Free any ieee80211 structures associated with the driver.
820 ieee80211_detach(ieee80211com_t
*ic
)
822 struct ieee80211_impl
*im
= ic
->ic_private
;
824 ieee80211_stop_watchdog(ic
);
825 cv_destroy(&im
->im_scan_cv
);
826 kmem_free(im
, sizeof (ieee80211_impl_t
));
828 if (ic
->ic_opt_ie
!= NULL
)
829 ieee80211_free(ic
->ic_opt_ie
);
831 ieee80211_ht_detach(ic
);
832 ieee80211_node_detach(ic
);
833 ieee80211_crypto_detach(ic
);
835 mutex_destroy(&ic
->ic_genlock
);
836 mutex_destroy(&ic
->ic_doorlock
);
839 static struct modlmisc i_wifi_modlmisc
= {
841 "IEEE80211 Kernel Module v2.0"
844 static struct modlinkage i_wifi_modlinkage
= {
851 * modlinkage functions
856 return (mod_install(&i_wifi_modlinkage
));
862 return (mod_remove(&i_wifi_modlinkage
));
866 _info(struct modinfo
*modinfop
)
868 return (mod_info(&i_wifi_modlinkage
, modinfop
));