10ba2cbe9Sxc151355 /* 240db2e2bSzf162725 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30ba2cbe9Sxc151355 * Use is subject to license terms. 40ba2cbe9Sxc151355 */ 50ba2cbe9Sxc151355 60ba2cbe9Sxc151355 /* 70ba2cbe9Sxc151355 * Copyright (c) 2001 Atsushi Onoe 80ba2cbe9Sxc151355 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 90ba2cbe9Sxc151355 * All rights reserved. 100ba2cbe9Sxc151355 * 110ba2cbe9Sxc151355 * Redistribution and use in source and binary forms, with or without 120ba2cbe9Sxc151355 * modification, are permitted provided that the following conditions 130ba2cbe9Sxc151355 * are met: 140ba2cbe9Sxc151355 * 1. Redistributions of source code must retain the above copyright 150ba2cbe9Sxc151355 * notice, this list of conditions and the following disclaimer. 160ba2cbe9Sxc151355 * 2. Redistributions in binary form must reproduce the above copyright 170ba2cbe9Sxc151355 * notice, this list of conditions and the following disclaimer in the 180ba2cbe9Sxc151355 * documentation and/or other materials provided with the distribution. 190ba2cbe9Sxc151355 * 3. The name of the author may not be used to endorse or promote products 200ba2cbe9Sxc151355 * derived from this software without specific prior written permission. 210ba2cbe9Sxc151355 * 220ba2cbe9Sxc151355 * Alternatively, this software may be distributed under the terms of the 230ba2cbe9Sxc151355 * GNU General Public License ("GPL") version 2 as published by the Free 240ba2cbe9Sxc151355 * Software Foundation. 250ba2cbe9Sxc151355 * 260ba2cbe9Sxc151355 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 270ba2cbe9Sxc151355 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 280ba2cbe9Sxc151355 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 290ba2cbe9Sxc151355 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 300ba2cbe9Sxc151355 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 310ba2cbe9Sxc151355 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 320ba2cbe9Sxc151355 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 330ba2cbe9Sxc151355 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 340ba2cbe9Sxc151355 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 350ba2cbe9Sxc151355 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 360ba2cbe9Sxc151355 */ 370ba2cbe9Sxc151355 380ba2cbe9Sxc151355 #pragma ident "%Z%%M% %I% %E% SMI" 390ba2cbe9Sxc151355 400ba2cbe9Sxc151355 /* 410ba2cbe9Sxc151355 * IEEE 802.11 generic handler 420ba2cbe9Sxc151355 */ 430ba2cbe9Sxc151355 440ba2cbe9Sxc151355 #include <sys/param.h> 450ba2cbe9Sxc151355 #include <sys/types.h> 460ba2cbe9Sxc151355 #include <sys/cmn_err.h> 470ba2cbe9Sxc151355 #include <sys/modctl.h> 48a399b765Szf162725 #include <sys/stropts.h> 49a399b765Szf162725 #include <sys/door.h> 500ba2cbe9Sxc151355 #include "net80211_impl.h" 510ba2cbe9Sxc151355 520ba2cbe9Sxc151355 uint32_t ieee80211_debug = 0x0; /* debug msg flags */ 530ba2cbe9Sxc151355 540ba2cbe9Sxc151355 const char *ieee80211_phymode_name[] = { 550ba2cbe9Sxc151355 "auto", /* IEEE80211_MODE_AUTO */ 560ba2cbe9Sxc151355 "11a", /* IEEE80211_MODE_11A */ 570ba2cbe9Sxc151355 "11b", /* IEEE80211_MODE_11B */ 580ba2cbe9Sxc151355 "11g", /* IEEE80211_MODE_11G */ 590ba2cbe9Sxc151355 "FH", /* IEEE80211_MODE_FH */ 600ba2cbe9Sxc151355 "turboA", /* IEEE80211_MODE_TURBO_A */ 610ba2cbe9Sxc151355 "turboG", /* IEEE80211_MODE_TURBO_G */ 620ba2cbe9Sxc151355 }; 630ba2cbe9Sxc151355 640ba2cbe9Sxc151355 #define IEEE80211_DPRINT(_level, _fmt) do { \ 650ba2cbe9Sxc151355 _NOTE(CONSTCOND) \ 660ba2cbe9Sxc151355 va_list ap; \ 670ba2cbe9Sxc151355 va_start(ap, (_fmt)); \ 680ba2cbe9Sxc151355 vcmn_err((_level), (_fmt), ap); \ 690ba2cbe9Sxc151355 va_end(ap); \ 700ba2cbe9Sxc151355 _NOTE(CONSTCOND) \ 710ba2cbe9Sxc151355 } while (0) 720ba2cbe9Sxc151355 730ba2cbe9Sxc151355 /* 740ba2cbe9Sxc151355 * Print error messages 750ba2cbe9Sxc151355 */ 760ba2cbe9Sxc151355 void 770ba2cbe9Sxc151355 ieee80211_err(const int8_t *fmt, ...) 780ba2cbe9Sxc151355 { 790ba2cbe9Sxc151355 IEEE80211_DPRINT(CE_WARN, fmt); 800ba2cbe9Sxc151355 } 810ba2cbe9Sxc151355 820ba2cbe9Sxc151355 /* 830ba2cbe9Sxc151355 * Print debug messages 840ba2cbe9Sxc151355 */ 850ba2cbe9Sxc151355 void 860ba2cbe9Sxc151355 ieee80211_dbg(uint32_t flag, const int8_t *fmt, ...) 870ba2cbe9Sxc151355 { 880ba2cbe9Sxc151355 if (flag & ieee80211_debug) 890ba2cbe9Sxc151355 IEEE80211_DPRINT(CE_CONT, fmt); 900ba2cbe9Sxc151355 } 910ba2cbe9Sxc151355 920ba2cbe9Sxc151355 /* 93a399b765Szf162725 * Alloc memory, and save the size 94a399b765Szf162725 */ 95a399b765Szf162725 void * 96a399b765Szf162725 ieee80211_malloc(size_t size) 97a399b765Szf162725 { 98a399b765Szf162725 void *p = kmem_zalloc((size + 4), KM_SLEEP); 99a399b765Szf162725 *(int *)p = size; 100a399b765Szf162725 p = (char *)p + 4; 101a399b765Szf162725 102a399b765Szf162725 return (p); 103a399b765Szf162725 } 104a399b765Szf162725 105a399b765Szf162725 void 106a399b765Szf162725 ieee80211_free(void *p) 107a399b765Szf162725 { 108a399b765Szf162725 void *tp = (char *)p - 4; 109a399b765Szf162725 kmem_free((char *)p - 4, *(int *)tp + 4); 110a399b765Szf162725 } 111a399b765Szf162725 112a399b765Szf162725 void 113a399b765Szf162725 ieee80211_mac_update(ieee80211com_t *ic) 114a399b765Szf162725 { 115a399b765Szf162725 wifi_data_t wd = { 0 }; 116a399b765Szf162725 ieee80211_node_t *in; 117a399b765Szf162725 118a399b765Szf162725 /* 119a399b765Szf162725 * We can send data now; update the fastpath with our 120a399b765Szf162725 * current associated BSSID and other relevant settings. 121a399b765Szf162725 */ 122a399b765Szf162725 in = ic->ic_bss; 123a399b765Szf162725 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic); 124a399b765Szf162725 wd.wd_opmode = ic->ic_opmode; 125a399b765Szf162725 IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid); 126a399b765Szf162725 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 127a399b765Szf162725 mac_tx_update(ic->ic_mach); 128a399b765Szf162725 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_mac_update" 129a399b765Szf162725 "(cipher = %d)\n", wd.wd_secalloc); 130a399b765Szf162725 } 131a399b765Szf162725 132a399b765Szf162725 /* 133a399b765Szf162725 * ieee80211_event_thread 134a399b765Szf162725 * open door of wpa, send event to wpad service 135a399b765Szf162725 */ 136a399b765Szf162725 static void 137a399b765Szf162725 ieee80211_event_thread(void *arg) 138a399b765Szf162725 { 139a399b765Szf162725 ieee80211com_t *ic = arg; 140a399b765Szf162725 door_handle_t event_door = NULL; /* Door for upcalls */ 141a399b765Szf162725 wl_events_t ev; 142a399b765Szf162725 door_arg_t darg; 143a399b765Szf162725 144a399b765Szf162725 mutex_enter(&ic->ic_doorlock); 145a399b765Szf162725 146a399b765Szf162725 ev.event = ic->ic_eventq[ic->ic_evq_head]; 147a399b765Szf162725 ic->ic_evq_head ++; 148a399b765Szf162725 if (ic->ic_evq_head >= MAX_EVENT) 149a399b765Szf162725 ic->ic_evq_head = 0; 150a399b765Szf162725 151a399b765Szf162725 ieee80211_dbg(IEEE80211_MSG_DEBUG, "ieee80211_event(%d)\n", ev.event); 152a399b765Szf162725 /* 153a399b765Szf162725 * Locate the door used for upcalls 154a399b765Szf162725 */ 155a399b765Szf162725 if (door_ki_open(ic->ic_wpadoor, &event_door) != 0) { 156a399b765Szf162725 ieee80211_err("ieee80211_event: door_ki_open(%s) failed\n", 157a399b765Szf162725 ic->ic_wpadoor); 158a399b765Szf162725 goto out; 159a399b765Szf162725 } 160a399b765Szf162725 161a399b765Szf162725 darg.data_ptr = (char *)&ev; 162a399b765Szf162725 darg.data_size = sizeof (wl_events_t); 163a399b765Szf162725 darg.desc_ptr = NULL; 164a399b765Szf162725 darg.desc_num = 0; 165a399b765Szf162725 darg.rbuf = NULL; 166a399b765Szf162725 darg.rsize = 0; 167a399b765Szf162725 168*323a81d9Sjwadams if (door_ki_upcall_limited(event_door, &darg, NULL, SIZE_MAX, 0) != 0) { 169a399b765Szf162725 ieee80211_err("ieee80211_event: door_ki_upcall() failed\n"); 170a399b765Szf162725 } 171a399b765Szf162725 172a399b765Szf162725 if (event_door) { /* release our hold (if any) */ 173a399b765Szf162725 door_ki_rele(event_door); 174a399b765Szf162725 } 175a399b765Szf162725 176a399b765Szf162725 out: 177a399b765Szf162725 mutex_exit(&ic->ic_doorlock); 178a399b765Szf162725 } 179a399b765Szf162725 180a399b765Szf162725 /* 181a399b765Szf162725 * Notify state transition event message to WPA daemon 182a399b765Szf162725 */ 183a399b765Szf162725 void 184a399b765Szf162725 ieee80211_notify(ieee80211com_t *ic, wpa_event_type event) 185a399b765Szf162725 { 186a399b765Szf162725 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) 187a399b765Szf162725 return; /* Not running on WPA mode */ 188a399b765Szf162725 189a399b765Szf162725 ic->ic_eventq[ic->ic_evq_tail] = event; 190a399b765Szf162725 ic->ic_evq_tail ++; 191a399b765Szf162725 if (ic->ic_evq_tail >= MAX_EVENT) ic->ic_evq_tail = 0; 192a399b765Szf162725 193a399b765Szf162725 /* async */ 194a399b765Szf162725 (void) timeout(ieee80211_event_thread, (void *)ic, 0); 195a399b765Szf162725 } 196a399b765Szf162725 197a399b765Szf162725 /* 1983a1a8936Szf162725 * Register WPA door 1993a1a8936Szf162725 */ 2003a1a8936Szf162725 void 2013a1a8936Szf162725 ieee80211_register_door(ieee80211com_t *ic, const char *drvname, int inst) 2023a1a8936Szf162725 { 2033a1a8936Szf162725 (void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", 2043a1a8936Szf162725 WPA_DOOR, drvname, inst); 2053a1a8936Szf162725 } 2063a1a8936Szf162725 2073a1a8936Szf162725 /* 2080ba2cbe9Sxc151355 * Default reset method for use with the ioctl support. This 2090ba2cbe9Sxc151355 * method is invoked after any state change in the 802.11 2100ba2cbe9Sxc151355 * layer that should be propagated to the hardware but not 2110ba2cbe9Sxc151355 * require re-initialization of the 802.11 state machine (e.g 2120ba2cbe9Sxc151355 * rescanning for an ap). We always return ENETRESET which 2130ba2cbe9Sxc151355 * should cause the driver to re-initialize the device. Drivers 2140ba2cbe9Sxc151355 * can override this method to implement more optimized support. 2150ba2cbe9Sxc151355 */ 2160ba2cbe9Sxc151355 /* ARGSUSED */ 2170ba2cbe9Sxc151355 static int 2180ba2cbe9Sxc151355 ieee80211_default_reset(ieee80211com_t *ic) 2190ba2cbe9Sxc151355 { 2200ba2cbe9Sxc151355 return (ENETRESET); 2210ba2cbe9Sxc151355 } 2220ba2cbe9Sxc151355 2230ba2cbe9Sxc151355 /* 2240ba2cbe9Sxc151355 * Convert channel to IEEE channel number. 2250ba2cbe9Sxc151355 */ 2260ba2cbe9Sxc151355 uint32_t 2270ba2cbe9Sxc151355 ieee80211_chan2ieee(ieee80211com_t *ic, struct ieee80211_channel *ch) 2280ba2cbe9Sxc151355 { 2290ba2cbe9Sxc151355 if ((ic->ic_sup_channels <= ch) && 2300ba2cbe9Sxc151355 (ch <= &ic->ic_sup_channels[IEEE80211_CHAN_MAX])) { 2310ba2cbe9Sxc151355 return (ch - ic->ic_sup_channels); 2320ba2cbe9Sxc151355 } else if (ch == IEEE80211_CHAN_ANYC) { 2330ba2cbe9Sxc151355 return (IEEE80211_CHAN_ANY); 2340ba2cbe9Sxc151355 } else if (ch != NULL) { 2350ba2cbe9Sxc151355 ieee80211_err("invalid channel freq %u flags %x\n", 2360ba2cbe9Sxc151355 ch->ich_freq, ch->ich_flags); 2370ba2cbe9Sxc151355 return (0); 2380ba2cbe9Sxc151355 } 2390ba2cbe9Sxc151355 ieee80211_err("invalid channel (NULL)\n"); /* ch == NULL */ 2400ba2cbe9Sxc151355 return (0); 2410ba2cbe9Sxc151355 } 2420ba2cbe9Sxc151355 2430ba2cbe9Sxc151355 /* 2440ba2cbe9Sxc151355 * Convert IEEE channel number to MHz frequency. 2450ba2cbe9Sxc151355 * chan IEEE channel number 2460ba2cbe9Sxc151355 * flags specify whether the frequency is in the 2GHz ISM 2470ba2cbe9Sxc151355 * band or the 5GHz band 2480ba2cbe9Sxc151355 * 2490ba2cbe9Sxc151355 * 802.11b 2GHz: 14 channels, each 5 MHz wide. Channel 1 is placed 2500ba2cbe9Sxc151355 * at 2.412 GHz, channel 2 at 2.417 GHz, and so on up to channel 13 2510ba2cbe9Sxc151355 * at 2.472 GHz. Channel 14 was defined especially for operation in 2520ba2cbe9Sxc151355 * Japan, and has a center frequency 2.484 GHz. 2530ba2cbe9Sxc151355 * 802.11g 2GHz: adopts the frequency plan of 802.11b. Japan only 2540ba2cbe9Sxc151355 * allows 802.11g operation in channels 1-13 2550ba2cbe9Sxc151355 * 802.11a 5GHz: starting every 5 MHz 2560ba2cbe9Sxc151355 * 802.11b/g channels 15-24 (2512-2692) are used by some implementation 2570ba2cbe9Sxc151355 * (Atheros etc.) 2580ba2cbe9Sxc151355 */ 2590ba2cbe9Sxc151355 uint32_t 2600ba2cbe9Sxc151355 ieee80211_ieee2mhz(uint32_t chan, uint32_t flags) 2610ba2cbe9Sxc151355 { 2620ba2cbe9Sxc151355 if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ 2630ba2cbe9Sxc151355 if (chan == 14) 2640ba2cbe9Sxc151355 return (2484); 2650ba2cbe9Sxc151355 if (chan < 14) 2660ba2cbe9Sxc151355 return (2412 + (chan - 1) * 5); 2670ba2cbe9Sxc151355 else 2680ba2cbe9Sxc151355 return (2512 + ((chan - 15) * 20)); 2690ba2cbe9Sxc151355 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ 2700ba2cbe9Sxc151355 return (5000 + (chan * 5)); /* OFDM */ 2710ba2cbe9Sxc151355 } else { /* either, guess */ 2720ba2cbe9Sxc151355 if (chan == 14) 2730ba2cbe9Sxc151355 return (2484); 2740ba2cbe9Sxc151355 if (chan < 14) /* 0-13 */ 2750ba2cbe9Sxc151355 return (2412 + (chan - 1) * 5); 2760ba2cbe9Sxc151355 if (chan < 27) /* 15-26 */ 2770ba2cbe9Sxc151355 return (2512 + ((chan - 15) * 20)); 2780ba2cbe9Sxc151355 return (5000 + (chan * 5)); 2790ba2cbe9Sxc151355 } 2800ba2cbe9Sxc151355 } 2810ba2cbe9Sxc151355 2820ba2cbe9Sxc151355 /* 2830ba2cbe9Sxc151355 * Do late attach work. It must be called by the driver after 2840ba2cbe9Sxc151355 * calling ieee80211_attach() and before calling most ieee80211 2850ba2cbe9Sxc151355 * functions. 2860ba2cbe9Sxc151355 */ 2870ba2cbe9Sxc151355 void 2880ba2cbe9Sxc151355 ieee80211_media_init(ieee80211com_t *ic) 2890ba2cbe9Sxc151355 { 2900ba2cbe9Sxc151355 /* 2910ba2cbe9Sxc151355 * Do late attach work that must wait for any subclass 2920ba2cbe9Sxc151355 * (i.e. driver) work such as overriding methods. 2930ba2cbe9Sxc151355 */ 2940ba2cbe9Sxc151355 ieee80211_node_lateattach(ic); 2950ba2cbe9Sxc151355 } 2960ba2cbe9Sxc151355 2970ba2cbe9Sxc151355 /* 2980ba2cbe9Sxc151355 * Start Watchdog timer. After count down timer(s), ic_watchdog 2990ba2cbe9Sxc151355 * will be called 3000ba2cbe9Sxc151355 */ 3010ba2cbe9Sxc151355 void 3020ba2cbe9Sxc151355 ieee80211_start_watchdog(ieee80211com_t *ic, uint32_t timer) 3030ba2cbe9Sxc151355 { 3040ba2cbe9Sxc151355 if (ic->ic_watchdog_timer == 0 && ic->ic_watchdog != NULL) { 3050ba2cbe9Sxc151355 ic->ic_watchdog_timer = timeout(ic->ic_watchdog, ic, 3060ba2cbe9Sxc151355 drv_usectohz(1000000 * timer)); 3070ba2cbe9Sxc151355 } 3080ba2cbe9Sxc151355 } 3090ba2cbe9Sxc151355 3100ba2cbe9Sxc151355 /* 3110ba2cbe9Sxc151355 * Stop watchdog timer. 3120ba2cbe9Sxc151355 */ 3130ba2cbe9Sxc151355 void 3140ba2cbe9Sxc151355 ieee80211_stop_watchdog(ieee80211com_t *ic) 3150ba2cbe9Sxc151355 { 3160ba2cbe9Sxc151355 if (ic->ic_watchdog_timer != 0) { 3170ba2cbe9Sxc151355 if (ic->ic_watchdog != NULL) 3180ba2cbe9Sxc151355 (void) untimeout(ic->ic_watchdog_timer); 3190ba2cbe9Sxc151355 ic->ic_watchdog_timer = 0; 3200ba2cbe9Sxc151355 } 3210ba2cbe9Sxc151355 } 3220ba2cbe9Sxc151355 3230ba2cbe9Sxc151355 /* 3240ba2cbe9Sxc151355 * Called from a driver's xxx_watchdog routine. It is used to 3250ba2cbe9Sxc151355 * perform periodic cleanup of state for net80211, as well as 3260ba2cbe9Sxc151355 * timeout scans. 3270ba2cbe9Sxc151355 */ 3280ba2cbe9Sxc151355 void 3290ba2cbe9Sxc151355 ieee80211_watchdog(void *arg) 3300ba2cbe9Sxc151355 { 3310ba2cbe9Sxc151355 ieee80211com_t *ic = arg; 3320ba2cbe9Sxc151355 struct ieee80211_impl *im = ic->ic_private; 3330ba2cbe9Sxc151355 ieee80211_node_table_t *nt; 3340ba2cbe9Sxc151355 int inact_timer = 0; 3350ba2cbe9Sxc151355 3360ba2cbe9Sxc151355 if (ic->ic_state == IEEE80211_S_INIT) 3370ba2cbe9Sxc151355 return; 3380ba2cbe9Sxc151355 3390ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 3400ba2cbe9Sxc151355 if ((im->im_mgt_timer != 0) && (--im->im_mgt_timer == 0)) { 3410ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 3420ba2cbe9Sxc151355 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 3430ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 3440ba2cbe9Sxc151355 } 3450ba2cbe9Sxc151355 3460ba2cbe9Sxc151355 nt = &ic->ic_scan; 3470ba2cbe9Sxc151355 if (nt->nt_inact_timer != 0) { 3480ba2cbe9Sxc151355 if (--nt->nt_inact_timer == 0) 3490ba2cbe9Sxc151355 nt->nt_timeout(nt); 3500ba2cbe9Sxc151355 inact_timer += nt->nt_inact_timer; 3510ba2cbe9Sxc151355 } 3520ba2cbe9Sxc151355 nt = &ic->ic_sta; 3530ba2cbe9Sxc151355 if (nt->nt_inact_timer != 0) { 3540ba2cbe9Sxc151355 if (--nt->nt_inact_timer == 0) 3550ba2cbe9Sxc151355 nt->nt_timeout(nt); 3560ba2cbe9Sxc151355 inact_timer += nt->nt_inact_timer; 3570ba2cbe9Sxc151355 } 3580ba2cbe9Sxc151355 3590ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 3600ba2cbe9Sxc151355 3610ba2cbe9Sxc151355 if (im->im_mgt_timer != 0 || inact_timer > 0) 3620ba2cbe9Sxc151355 ieee80211_start_watchdog(ic, 1); 3630ba2cbe9Sxc151355 } 3640ba2cbe9Sxc151355 3650ba2cbe9Sxc151355 /* 3660ba2cbe9Sxc151355 * Set the current phy mode and recalculate the active channel 3670ba2cbe9Sxc151355 * set and supported rates based on the available channels for 3680ba2cbe9Sxc151355 * this mode. Also select a new BSS channel if the current one 3690ba2cbe9Sxc151355 * is inappropriate for this mode. 3700ba2cbe9Sxc151355 * This function is called by net80211, and not intended to be 3710ba2cbe9Sxc151355 * called directly. 3720ba2cbe9Sxc151355 */ 3730ba2cbe9Sxc151355 static int 3740ba2cbe9Sxc151355 ieee80211_setmode(ieee80211com_t *ic, enum ieee80211_phymode mode) 3750ba2cbe9Sxc151355 { 3760ba2cbe9Sxc151355 static const uint32_t chanflags[] = { 3770ba2cbe9Sxc151355 0, /* IEEE80211_MODE_AUTO */ 3780ba2cbe9Sxc151355 IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ 3790ba2cbe9Sxc151355 IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ 3800ba2cbe9Sxc151355 IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ 3810ba2cbe9Sxc151355 IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ 3820ba2cbe9Sxc151355 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */ 3830ba2cbe9Sxc151355 IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ 3840ba2cbe9Sxc151355 }; 3850ba2cbe9Sxc151355 struct ieee80211_channel *ch; 3860ba2cbe9Sxc151355 uint32_t modeflags; 3870ba2cbe9Sxc151355 int i; 3880ba2cbe9Sxc151355 int achannels = 0; 3890ba2cbe9Sxc151355 3900ba2cbe9Sxc151355 /* validate new mode */ 3910ba2cbe9Sxc151355 if ((ic->ic_modecaps & (1 << mode)) == 0) { 3920ba2cbe9Sxc151355 ieee80211_err("ieee80211_setmode(): mode %u not supported" 3930ba2cbe9Sxc151355 " (caps 0x%x)\n", mode, ic->ic_modecaps); 3940ba2cbe9Sxc151355 return (EINVAL); 3950ba2cbe9Sxc151355 } 3960ba2cbe9Sxc151355 3970ba2cbe9Sxc151355 /* 3980ba2cbe9Sxc151355 * Verify at least one channel is present in the available 3990ba2cbe9Sxc151355 * channel list before committing to the new mode. 4000ba2cbe9Sxc151355 * Calculate the active channel set. 4010ba2cbe9Sxc151355 */ 4020ba2cbe9Sxc151355 ASSERT(mode < IEEE80211_N(chanflags)); 4030ba2cbe9Sxc151355 modeflags = chanflags[mode]; 4040ba2cbe9Sxc151355 bzero(ic->ic_chan_active, sizeof (ic->ic_chan_active)); 4050ba2cbe9Sxc151355 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 4060ba2cbe9Sxc151355 ch = &ic->ic_sup_channels[i]; 4070ba2cbe9Sxc151355 if (ch->ich_flags == 0) 4080ba2cbe9Sxc151355 continue; 4090ba2cbe9Sxc151355 if (mode == IEEE80211_MODE_AUTO) { 4100ba2cbe9Sxc151355 /* take anything but pure turbo channels */ 4110ba2cbe9Sxc151355 if ((ch->ich_flags & ~IEEE80211_CHAN_TURBO) != 0) { 4120ba2cbe9Sxc151355 ieee80211_setbit(ic->ic_chan_active, i); 4130ba2cbe9Sxc151355 achannels++; 4140ba2cbe9Sxc151355 } 4150ba2cbe9Sxc151355 } else { 4160ba2cbe9Sxc151355 if ((ch->ich_flags & modeflags) == modeflags) { 4170ba2cbe9Sxc151355 ieee80211_setbit(ic->ic_chan_active, i); 4180ba2cbe9Sxc151355 achannels++; 4190ba2cbe9Sxc151355 } 4200ba2cbe9Sxc151355 } 4210ba2cbe9Sxc151355 } 4220ba2cbe9Sxc151355 if (achannels == 0) { 4230ba2cbe9Sxc151355 ieee80211_err("ieee80211_setmode(): " 4240ba2cbe9Sxc151355 "no channel found for mode %u\n", mode); 4250ba2cbe9Sxc151355 return (EINVAL); 4260ba2cbe9Sxc151355 } 4270ba2cbe9Sxc151355 4280ba2cbe9Sxc151355 /* 4290ba2cbe9Sxc151355 * If no current/default channel is setup or the current 4300ba2cbe9Sxc151355 * channel is wrong for the mode then pick the first 4310ba2cbe9Sxc151355 * available channel from the active list. This is likely 4320ba2cbe9Sxc151355 * not the right one. 4330ba2cbe9Sxc151355 */ 4340ba2cbe9Sxc151355 if (ic->ic_ibss_chan == NULL || 4350ba2cbe9Sxc151355 ieee80211_isclr(ic->ic_chan_active, 4360ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 4370ba2cbe9Sxc151355 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 4380ba2cbe9Sxc151355 if (ieee80211_isset(ic->ic_chan_active, i)) { 4390ba2cbe9Sxc151355 ic->ic_ibss_chan = &ic->ic_sup_channels[i]; 4400ba2cbe9Sxc151355 break; 4410ba2cbe9Sxc151355 } 4420ba2cbe9Sxc151355 } 4430ba2cbe9Sxc151355 } 4440ba2cbe9Sxc151355 /* 4450ba2cbe9Sxc151355 * If the desired channel is set but no longer valid then reset it. 4460ba2cbe9Sxc151355 */ 4470ba2cbe9Sxc151355 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 4480ba2cbe9Sxc151355 ieee80211_isclr(ic->ic_chan_active, 4490ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_des_chan))) { 4500ba2cbe9Sxc151355 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 4510ba2cbe9Sxc151355 } 4520ba2cbe9Sxc151355 4530ba2cbe9Sxc151355 /* 4540ba2cbe9Sxc151355 * Do mode-specific rate setup. 4550ba2cbe9Sxc151355 */ 4560ba2cbe9Sxc151355 if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B) 4570ba2cbe9Sxc151355 ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode); 4580ba2cbe9Sxc151355 4590ba2cbe9Sxc151355 /* 4600ba2cbe9Sxc151355 * Setup an initial rate set according to the 4610ba2cbe9Sxc151355 * current/default channel. This will be changed 4620ba2cbe9Sxc151355 * when scanning but must exist now so drivers have 4630ba2cbe9Sxc151355 * consistent state of ic_bsschan. 4640ba2cbe9Sxc151355 */ 4650ba2cbe9Sxc151355 if (ic->ic_bss != NULL) 4660ba2cbe9Sxc151355 ic->ic_bss->in_rates = ic->ic_sup_rates[mode]; 4670ba2cbe9Sxc151355 ic->ic_curmode = mode; 4680ba2cbe9Sxc151355 ieee80211_reset_erp(ic); /* reset ERP state */ 4690ba2cbe9Sxc151355 4700ba2cbe9Sxc151355 return (0); 4710ba2cbe9Sxc151355 } 4720ba2cbe9Sxc151355 4730ba2cbe9Sxc151355 /* 4740ba2cbe9Sxc151355 * Return the phy mode for with the specified channel so the 4750ba2cbe9Sxc151355 * caller can select a rate set. This is problematic for channels 4760ba2cbe9Sxc151355 * where multiple operating modes are possible (e.g. 11g+11b). 4770ba2cbe9Sxc151355 * In those cases we defer to the current operating mode when set. 4780ba2cbe9Sxc151355 */ 4790ba2cbe9Sxc151355 enum ieee80211_phymode 4800ba2cbe9Sxc151355 ieee80211_chan2mode(ieee80211com_t *ic, struct ieee80211_channel *chan) 4810ba2cbe9Sxc151355 { 4820ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_T(chan)) { 4830ba2cbe9Sxc151355 return (IEEE80211_MODE_TURBO_A); 4840ba2cbe9Sxc151355 } else if (IEEE80211_IS_CHAN_5GHZ(chan)) { 4850ba2cbe9Sxc151355 return (IEEE80211_MODE_11A); 4860ba2cbe9Sxc151355 } else if (IEEE80211_IS_CHAN_FHSS(chan)) { 4870ba2cbe9Sxc151355 return (IEEE80211_MODE_FH); 4880ba2cbe9Sxc151355 } else if (chan->ich_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) { 4890ba2cbe9Sxc151355 /* 4900ba2cbe9Sxc151355 * This assumes all 11g channels are also usable 4910ba2cbe9Sxc151355 * for 11b, which is currently true. 4920ba2cbe9Sxc151355 */ 4930ba2cbe9Sxc151355 if (ic->ic_curmode == IEEE80211_MODE_TURBO_G) 4940ba2cbe9Sxc151355 return (IEEE80211_MODE_TURBO_G); 4950ba2cbe9Sxc151355 if (ic->ic_curmode == IEEE80211_MODE_11B) 4960ba2cbe9Sxc151355 return (IEEE80211_MODE_11B); 4970ba2cbe9Sxc151355 return (IEEE80211_MODE_11G); 4980ba2cbe9Sxc151355 } else { 4990ba2cbe9Sxc151355 return (IEEE80211_MODE_11B); 5000ba2cbe9Sxc151355 } 5010ba2cbe9Sxc151355 } 5020ba2cbe9Sxc151355 5030ba2cbe9Sxc151355 /* 5040ba2cbe9Sxc151355 * Return the size of the 802.11 header for a management or data frame. 5050ba2cbe9Sxc151355 */ 5060ba2cbe9Sxc151355 int 5070ba2cbe9Sxc151355 ieee80211_hdrspace(const void *data) 5080ba2cbe9Sxc151355 { 5090ba2cbe9Sxc151355 const struct ieee80211_frame *wh = data; 5100ba2cbe9Sxc151355 int size = sizeof (struct ieee80211_frame); 5110ba2cbe9Sxc151355 5120ba2cbe9Sxc151355 /* NB: we don't handle control frames */ 5130ba2cbe9Sxc151355 ASSERT((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) != 5140ba2cbe9Sxc151355 IEEE80211_FC0_TYPE_CTL); 5150ba2cbe9Sxc151355 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 5160ba2cbe9Sxc151355 size += IEEE80211_ADDR_LEN; 5170ba2cbe9Sxc151355 5180ba2cbe9Sxc151355 return (size); 5190ba2cbe9Sxc151355 } 5200ba2cbe9Sxc151355 5210ba2cbe9Sxc151355 /* 5220ba2cbe9Sxc151355 * Allocate and setup a management frame of the specified 5230ba2cbe9Sxc151355 * size. We return the mblk and a pointer to the start 5240ba2cbe9Sxc151355 * of the contiguous data area that's been reserved based 5250ba2cbe9Sxc151355 * on the packet length. 5260ba2cbe9Sxc151355 */ 5270ba2cbe9Sxc151355 mblk_t * 5280ba2cbe9Sxc151355 ieee80211_getmgtframe(uint8_t **frm, int pktlen) 5290ba2cbe9Sxc151355 { 5300ba2cbe9Sxc151355 mblk_t *mp; 5310ba2cbe9Sxc151355 int len; 5320ba2cbe9Sxc151355 5330ba2cbe9Sxc151355 len = sizeof (struct ieee80211_frame) + pktlen; 5340ba2cbe9Sxc151355 mp = allocb(len, BPRI_MED); 5350ba2cbe9Sxc151355 if (mp != NULL) { 5360ba2cbe9Sxc151355 *frm = mp->b_rptr + sizeof (struct ieee80211_frame); 5370ba2cbe9Sxc151355 mp->b_wptr = mp->b_rptr + len; 5380ba2cbe9Sxc151355 } else { 5390ba2cbe9Sxc151355 ieee80211_err("ieee80211_getmgtframe: " 5400ba2cbe9Sxc151355 "alloc frame failed, %d\n", len); 5410ba2cbe9Sxc151355 } 5420ba2cbe9Sxc151355 return (mp); 5430ba2cbe9Sxc151355 } 5440ba2cbe9Sxc151355 5450ba2cbe9Sxc151355 /* 5460ba2cbe9Sxc151355 * Send system messages to notify the device has joined a WLAN. 5470ba2cbe9Sxc151355 * This is an OS specific function. Solaris marks link status 5480ba2cbe9Sxc151355 * as up. 5490ba2cbe9Sxc151355 */ 5500ba2cbe9Sxc151355 void 5510ba2cbe9Sxc151355 ieee80211_notify_node_join(ieee80211com_t *ic, ieee80211_node_t *in) 5520ba2cbe9Sxc151355 { 5530ba2cbe9Sxc151355 if (in == ic->ic_bss) 5540ba2cbe9Sxc151355 mac_link_update(ic->ic_mach, LINK_STATE_UP); 555a399b765Szf162725 ieee80211_notify(ic, EVENT_ASSOC); /* notify WPA service */ 5560ba2cbe9Sxc151355 } 5570ba2cbe9Sxc151355 5580ba2cbe9Sxc151355 /* 5590ba2cbe9Sxc151355 * Send system messages to notify the device has left a WLAN. 5600ba2cbe9Sxc151355 * This is an OS specific function. Solaris marks link status 5610ba2cbe9Sxc151355 * as down. 5620ba2cbe9Sxc151355 */ 5630ba2cbe9Sxc151355 void 5640ba2cbe9Sxc151355 ieee80211_notify_node_leave(ieee80211com_t *ic, ieee80211_node_t *in) 5650ba2cbe9Sxc151355 { 5660ba2cbe9Sxc151355 if (in == ic->ic_bss) 5670ba2cbe9Sxc151355 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 568a399b765Szf162725 ieee80211_notify(ic, EVENT_DISASSOC); /* notify WPA service */ 5690ba2cbe9Sxc151355 } 5700ba2cbe9Sxc151355 5710ba2cbe9Sxc151355 /* 5720ba2cbe9Sxc151355 * Get 802.11 kstats defined in ieee802.11(5) 5730ba2cbe9Sxc151355 * 5740ba2cbe9Sxc151355 * Return 0 on success 5750ba2cbe9Sxc151355 */ 5760ba2cbe9Sxc151355 int 5770ba2cbe9Sxc151355 ieee80211_stat(ieee80211com_t *ic, uint_t stat, uint64_t *val) 5780ba2cbe9Sxc151355 { 5790ba2cbe9Sxc151355 ASSERT(val != NULL); 5800ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 5810ba2cbe9Sxc151355 switch (stat) { 5820ba2cbe9Sxc151355 case WIFI_STAT_TX_FRAGS: 5830ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_frags; 5840ba2cbe9Sxc151355 break; 5850ba2cbe9Sxc151355 case WIFI_STAT_MCAST_TX: 5860ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_mcast; 5870ba2cbe9Sxc151355 break; 5880ba2cbe9Sxc151355 case WIFI_STAT_TX_FAILED: 5890ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_failed; 5900ba2cbe9Sxc151355 break; 5910ba2cbe9Sxc151355 case WIFI_STAT_TX_RETRANS: 5920ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_retries; 5930ba2cbe9Sxc151355 break; 5940ba2cbe9Sxc151355 case WIFI_STAT_RTS_SUCCESS: 5950ba2cbe9Sxc151355 *val = ic->ic_stats.is_rts_success; 5960ba2cbe9Sxc151355 break; 5970ba2cbe9Sxc151355 case WIFI_STAT_RTS_FAILURE: 5980ba2cbe9Sxc151355 *val = ic->ic_stats.is_rts_failure; 5990ba2cbe9Sxc151355 break; 6000ba2cbe9Sxc151355 case WIFI_STAT_ACK_FAILURE: 6010ba2cbe9Sxc151355 *val = ic->ic_stats.is_ack_failure; 6020ba2cbe9Sxc151355 break; 6030ba2cbe9Sxc151355 case WIFI_STAT_RX_FRAGS: 6040ba2cbe9Sxc151355 *val = ic->ic_stats.is_rx_frags; 6050ba2cbe9Sxc151355 break; 6060ba2cbe9Sxc151355 case WIFI_STAT_MCAST_RX: 6070ba2cbe9Sxc151355 *val = ic->ic_stats.is_rx_mcast; 6080ba2cbe9Sxc151355 break; 6090ba2cbe9Sxc151355 case WIFI_STAT_RX_DUPS: 6100ba2cbe9Sxc151355 *val = ic->ic_stats.is_rx_dups; 6110ba2cbe9Sxc151355 break; 6120ba2cbe9Sxc151355 case WIFI_STAT_FCS_ERRORS: 6130ba2cbe9Sxc151355 *val = ic->ic_stats.is_fcs_errors; 6140ba2cbe9Sxc151355 break; 6150ba2cbe9Sxc151355 case WIFI_STAT_WEP_ERRORS: 6160ba2cbe9Sxc151355 *val = ic->ic_stats.is_wep_errors; 6170ba2cbe9Sxc151355 break; 6180ba2cbe9Sxc151355 } 6190ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 6200ba2cbe9Sxc151355 return (0); 6210ba2cbe9Sxc151355 } 6220ba2cbe9Sxc151355 6230ba2cbe9Sxc151355 /* 6240ba2cbe9Sxc151355 * Attach network interface to the 802.11 support module. This 6250ba2cbe9Sxc151355 * function must be called before using any of the ieee80211 6260ba2cbe9Sxc151355 * functionss. The parameter "ic" MUST be initialized to tell 6270ba2cbe9Sxc151355 * net80211 about interface's capabilities. 6280ba2cbe9Sxc151355 */ 6290ba2cbe9Sxc151355 void 6300ba2cbe9Sxc151355 ieee80211_attach(ieee80211com_t *ic) 6310ba2cbe9Sxc151355 { 6320ba2cbe9Sxc151355 struct ieee80211_impl *im; 6330ba2cbe9Sxc151355 struct ieee80211_channel *ch; 6340ba2cbe9Sxc151355 int i; 6350ba2cbe9Sxc151355 6360ba2cbe9Sxc151355 /* Check mandatory callback functions not NULL */ 6370ba2cbe9Sxc151355 ASSERT(ic->ic_xmit != NULL); 6380ba2cbe9Sxc151355 6390ba2cbe9Sxc151355 mutex_init(&ic->ic_genlock, NULL, MUTEX_DRIVER, NULL); 640a399b765Szf162725 mutex_init(&ic->ic_doorlock, NULL, MUTEX_DRIVER, NULL); 6410ba2cbe9Sxc151355 6420ba2cbe9Sxc151355 im = kmem_alloc(sizeof (ieee80211_impl_t), KM_SLEEP); 6430ba2cbe9Sxc151355 ic->ic_private = im; 6440ba2cbe9Sxc151355 cv_init(&im->im_scan_cv, NULL, CV_DRIVER, NULL); 6450ba2cbe9Sxc151355 6460ba2cbe9Sxc151355 /* 6470ba2cbe9Sxc151355 * Fill in 802.11 available channel set, mark 6480ba2cbe9Sxc151355 * all available channels as active, and pick 6490ba2cbe9Sxc151355 * a default channel if not already specified. 6500ba2cbe9Sxc151355 */ 6510ba2cbe9Sxc151355 bzero(im->im_chan_avail, sizeof (im->im_chan_avail)); 6520ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO; 6530ba2cbe9Sxc151355 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 6540ba2cbe9Sxc151355 ch = &ic->ic_sup_channels[i]; 6550ba2cbe9Sxc151355 if (ch->ich_flags) { 6560ba2cbe9Sxc151355 /* Verify driver passed us valid data */ 6570ba2cbe9Sxc151355 if (i != ieee80211_chan2ieee(ic, ch)) { 6580ba2cbe9Sxc151355 ieee80211_err("bad channel ignored: " 6590ba2cbe9Sxc151355 "freq %u flags%x number %u\n", 6600ba2cbe9Sxc151355 ch->ich_freq, ch->ich_flags, i); 6610ba2cbe9Sxc151355 ch->ich_flags = 0; 6620ba2cbe9Sxc151355 continue; 6630ba2cbe9Sxc151355 } 6640ba2cbe9Sxc151355 ieee80211_setbit(im->im_chan_avail, i); 6650ba2cbe9Sxc151355 /* Identify mode capabilities */ 6660ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_A(ch)) 6670ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_11A; 6680ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_B(ch)) 6690ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_11B; 6700ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_PUREG(ch)) 6710ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_11G; 6720ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_FHSS(ch)) 6730ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_FH; 6740ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_T(ch)) 6750ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_A; 6760ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_108G(ch)) 6770ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_G; 6780ba2cbe9Sxc151355 if (ic->ic_curchan == NULL) { 6790ba2cbe9Sxc151355 /* arbitrarily pick the first channel */ 6800ba2cbe9Sxc151355 ic->ic_curchan = &ic->ic_sup_channels[i]; 6810ba2cbe9Sxc151355 } 6820ba2cbe9Sxc151355 } 6830ba2cbe9Sxc151355 } 6840ba2cbe9Sxc151355 /* validate ic->ic_curmode */ 6850ba2cbe9Sxc151355 if ((ic->ic_modecaps & (1 << ic->ic_curmode)) == 0) 6860ba2cbe9Sxc151355 ic->ic_curmode = IEEE80211_MODE_AUTO; 6870ba2cbe9Sxc151355 ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ 6880ba2cbe9Sxc151355 (void) ieee80211_setmode(ic, ic->ic_curmode); 6890ba2cbe9Sxc151355 6900ba2cbe9Sxc151355 if (ic->ic_caps & IEEE80211_C_BURST) 6910ba2cbe9Sxc151355 ic->ic_flags |= IEEE80211_F_BURST; 6920ba2cbe9Sxc151355 ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; 6930ba2cbe9Sxc151355 ic->ic_lintval = ic->ic_bintval; 6940ba2cbe9Sxc151355 ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; 6950ba2cbe9Sxc151355 ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; 6960ba2cbe9Sxc151355 6970ba2cbe9Sxc151355 ic->ic_reset = ieee80211_default_reset; 6980ba2cbe9Sxc151355 6990ba2cbe9Sxc151355 ieee80211_node_attach(ic); 7000ba2cbe9Sxc151355 ieee80211_proto_attach(ic); 7010ba2cbe9Sxc151355 ieee80211_crypto_attach(ic); 7020ba2cbe9Sxc151355 7030ba2cbe9Sxc151355 ic->ic_watchdog_timer = 0; 7040ba2cbe9Sxc151355 } 7050ba2cbe9Sxc151355 7060ba2cbe9Sxc151355 /* 7070ba2cbe9Sxc151355 * Free any ieee80211 structures associated with the driver. 7080ba2cbe9Sxc151355 */ 7090ba2cbe9Sxc151355 void 7100ba2cbe9Sxc151355 ieee80211_detach(ieee80211com_t *ic) 7110ba2cbe9Sxc151355 { 7120ba2cbe9Sxc151355 struct ieee80211_impl *im = ic->ic_private; 7130ba2cbe9Sxc151355 7140ba2cbe9Sxc151355 ieee80211_stop_watchdog(ic); 7150ba2cbe9Sxc151355 cv_destroy(&im->im_scan_cv); 7160ba2cbe9Sxc151355 kmem_free(im, sizeof (ieee80211_impl_t)); 7170ba2cbe9Sxc151355 71840db2e2bSzf162725 if (ic->ic_opt_ie != NULL) 71940db2e2bSzf162725 ieee80211_free(ic->ic_opt_ie); 72040db2e2bSzf162725 7210ba2cbe9Sxc151355 ieee80211_node_detach(ic); 7220ba2cbe9Sxc151355 ieee80211_crypto_detach(ic); 7230ba2cbe9Sxc151355 7240ba2cbe9Sxc151355 mutex_destroy(&ic->ic_genlock); 725a399b765Szf162725 mutex_destroy(&ic->ic_doorlock); 7260ba2cbe9Sxc151355 } 7270ba2cbe9Sxc151355 7280ba2cbe9Sxc151355 static struct modlmisc i_wifi_modlmisc = { 7290ba2cbe9Sxc151355 &mod_miscops, 7303a1a8936Szf162725 "IEEE80211 Kernel Module v1.3" 7310ba2cbe9Sxc151355 }; 7320ba2cbe9Sxc151355 7330ba2cbe9Sxc151355 static struct modlinkage i_wifi_modlinkage = { 7340ba2cbe9Sxc151355 MODREV_1, 7350ba2cbe9Sxc151355 &i_wifi_modlmisc, 7360ba2cbe9Sxc151355 NULL 7370ba2cbe9Sxc151355 }; 7380ba2cbe9Sxc151355 7390ba2cbe9Sxc151355 /* 7400ba2cbe9Sxc151355 * modlinkage functions 7410ba2cbe9Sxc151355 */ 7420ba2cbe9Sxc151355 int 7430ba2cbe9Sxc151355 _init(void) 7440ba2cbe9Sxc151355 { 7450ba2cbe9Sxc151355 return (mod_install(&i_wifi_modlinkage)); 7460ba2cbe9Sxc151355 } 7470ba2cbe9Sxc151355 7480ba2cbe9Sxc151355 int 7490ba2cbe9Sxc151355 _fini(void) 7500ba2cbe9Sxc151355 { 7510ba2cbe9Sxc151355 return (mod_remove(&i_wifi_modlinkage)); 7520ba2cbe9Sxc151355 } 7530ba2cbe9Sxc151355 7540ba2cbe9Sxc151355 int 7550ba2cbe9Sxc151355 _info(struct modinfo *modinfop) 7560ba2cbe9Sxc151355 { 7570ba2cbe9Sxc151355 return (mod_info(&i_wifi_modlinkage, modinfop)); 7580ba2cbe9Sxc151355 } 759