10ba2cbe9Sxc151355 /* 2*e2cf88acSQuaker Fang * Copyright 2009 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 /* 390ba2cbe9Sxc151355 * IEEE 802.11 generic handler 400ba2cbe9Sxc151355 */ 410ba2cbe9Sxc151355 420ba2cbe9Sxc151355 #include <sys/param.h> 430ba2cbe9Sxc151355 #include <sys/types.h> 440ba2cbe9Sxc151355 #include <sys/cmn_err.h> 450ba2cbe9Sxc151355 #include <sys/modctl.h> 46a399b765Szf162725 #include <sys/stropts.h> 47a399b765Szf162725 #include <sys/door.h> 48da14cebeSEric Cheng #include <sys/mac_provider.h> 490ba2cbe9Sxc151355 #include "net80211_impl.h" 500ba2cbe9Sxc151355 510ba2cbe9Sxc151355 uint32_t ieee80211_debug = 0x0; /* debug msg flags */ 520ba2cbe9Sxc151355 530ba2cbe9Sxc151355 const char *ieee80211_phymode_name[] = { 540ba2cbe9Sxc151355 "auto", /* IEEE80211_MODE_AUTO */ 550ba2cbe9Sxc151355 "11a", /* IEEE80211_MODE_11A */ 560ba2cbe9Sxc151355 "11b", /* IEEE80211_MODE_11B */ 570ba2cbe9Sxc151355 "11g", /* IEEE80211_MODE_11G */ 580ba2cbe9Sxc151355 "FH", /* IEEE80211_MODE_FH */ 590ba2cbe9Sxc151355 "turboA", /* IEEE80211_MODE_TURBO_A */ 600ba2cbe9Sxc151355 "turboG", /* IEEE80211_MODE_TURBO_G */ 61*e2cf88acSQuaker Fang "sturboA", /* IEEE80211_MODE_STURBO_A */ 62*e2cf88acSQuaker Fang "11na", /* IEEE80211_MODE_11NA */ 63*e2cf88acSQuaker Fang "11ng", /* IEEE80211_MODE_11NG */ 640ba2cbe9Sxc151355 }; 650ba2cbe9Sxc151355 660ba2cbe9Sxc151355 #define IEEE80211_DPRINT(_level, _fmt) do { \ 670ba2cbe9Sxc151355 _NOTE(CONSTCOND) \ 680ba2cbe9Sxc151355 va_list ap; \ 690ba2cbe9Sxc151355 va_start(ap, (_fmt)); \ 700ba2cbe9Sxc151355 vcmn_err((_level), (_fmt), ap); \ 710ba2cbe9Sxc151355 va_end(ap); \ 720ba2cbe9Sxc151355 _NOTE(CONSTCOND) \ 730ba2cbe9Sxc151355 } while (0) 740ba2cbe9Sxc151355 750ba2cbe9Sxc151355 /* 760ba2cbe9Sxc151355 * Print error messages 770ba2cbe9Sxc151355 */ 780ba2cbe9Sxc151355 void 790ba2cbe9Sxc151355 ieee80211_err(const int8_t *fmt, ...) 800ba2cbe9Sxc151355 { 810ba2cbe9Sxc151355 IEEE80211_DPRINT(CE_WARN, fmt); 820ba2cbe9Sxc151355 } 830ba2cbe9Sxc151355 840ba2cbe9Sxc151355 /* 850ba2cbe9Sxc151355 * Print debug messages 860ba2cbe9Sxc151355 */ 870ba2cbe9Sxc151355 void 880ba2cbe9Sxc151355 ieee80211_dbg(uint32_t flag, const int8_t *fmt, ...) 890ba2cbe9Sxc151355 { 900ba2cbe9Sxc151355 if (flag & ieee80211_debug) 910ba2cbe9Sxc151355 IEEE80211_DPRINT(CE_CONT, fmt); 920ba2cbe9Sxc151355 } 930ba2cbe9Sxc151355 940ba2cbe9Sxc151355 /* 95a399b765Szf162725 * Alloc memory, and save the size 96a399b765Szf162725 */ 97a399b765Szf162725 void * 98a399b765Szf162725 ieee80211_malloc(size_t size) 99a399b765Szf162725 { 100a399b765Szf162725 void *p = kmem_zalloc((size + 4), KM_SLEEP); 101a399b765Szf162725 *(int *)p = size; 102a399b765Szf162725 p = (char *)p + 4; 103a399b765Szf162725 104a399b765Szf162725 return (p); 105a399b765Szf162725 } 106a399b765Szf162725 107a399b765Szf162725 void 108a399b765Szf162725 ieee80211_free(void *p) 109a399b765Szf162725 { 110a399b765Szf162725 void *tp = (char *)p - 4; 111a399b765Szf162725 kmem_free((char *)p - 4, *(int *)tp + 4); 112a399b765Szf162725 } 113a399b765Szf162725 114a399b765Szf162725 void 115a399b765Szf162725 ieee80211_mac_update(ieee80211com_t *ic) 116a399b765Szf162725 { 117a399b765Szf162725 wifi_data_t wd = { 0 }; 118a399b765Szf162725 ieee80211_node_t *in; 119a399b765Szf162725 120a399b765Szf162725 /* 121a399b765Szf162725 * We can send data now; update the fastpath with our 122a399b765Szf162725 * current associated BSSID and other relevant settings. 123a399b765Szf162725 */ 124a399b765Szf162725 in = ic->ic_bss; 125a399b765Szf162725 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic); 126a399b765Szf162725 wd.wd_opmode = ic->ic_opmode; 127a399b765Szf162725 IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid); 128*e2cf88acSQuaker Fang wd.wd_qospad = 0; 129*e2cf88acSQuaker Fang if (in->in_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) { 130*e2cf88acSQuaker Fang wd.wd_qospad = 2; 131*e2cf88acSQuaker Fang if (ic->ic_flags & IEEE80211_F_DATAPAD) 132*e2cf88acSQuaker Fang wd.wd_qospad = roundup(wd.wd_qospad, sizeof (uint32_t)); 133*e2cf88acSQuaker Fang } 134a399b765Szf162725 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 135a399b765Szf162725 mac_tx_update(ic->ic_mach); 136a399b765Szf162725 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_mac_update" 137a399b765Szf162725 "(cipher = %d)\n", wd.wd_secalloc); 138a399b765Szf162725 } 139a399b765Szf162725 140a399b765Szf162725 /* 141a399b765Szf162725 * ieee80211_event_thread 142a399b765Szf162725 * open door of wpa, send event to wpad service 143a399b765Szf162725 */ 144a399b765Szf162725 static void 145a399b765Szf162725 ieee80211_event_thread(void *arg) 146a399b765Szf162725 { 147a399b765Szf162725 ieee80211com_t *ic = arg; 148a399b765Szf162725 door_handle_t event_door = NULL; /* Door for upcalls */ 149a399b765Szf162725 wl_events_t ev; 150a399b765Szf162725 door_arg_t darg; 151a399b765Szf162725 152a399b765Szf162725 mutex_enter(&ic->ic_doorlock); 153a399b765Szf162725 154a399b765Szf162725 ev.event = ic->ic_eventq[ic->ic_evq_head]; 155a399b765Szf162725 ic->ic_evq_head ++; 156a399b765Szf162725 if (ic->ic_evq_head >= MAX_EVENT) 157a399b765Szf162725 ic->ic_evq_head = 0; 158a399b765Szf162725 159a399b765Szf162725 ieee80211_dbg(IEEE80211_MSG_DEBUG, "ieee80211_event(%d)\n", ev.event); 160a399b765Szf162725 /* 161a399b765Szf162725 * Locate the door used for upcalls 162a399b765Szf162725 */ 163a399b765Szf162725 if (door_ki_open(ic->ic_wpadoor, &event_door) != 0) { 164a399b765Szf162725 ieee80211_err("ieee80211_event: door_ki_open(%s) failed\n", 165a399b765Szf162725 ic->ic_wpadoor); 166a399b765Szf162725 goto out; 167a399b765Szf162725 } 168a399b765Szf162725 169a399b765Szf162725 darg.data_ptr = (char *)&ev; 170a399b765Szf162725 darg.data_size = sizeof (wl_events_t); 171a399b765Szf162725 darg.desc_ptr = NULL; 172a399b765Szf162725 darg.desc_num = 0; 173a399b765Szf162725 darg.rbuf = NULL; 174a399b765Szf162725 darg.rsize = 0; 175a399b765Szf162725 176323a81d9Sjwadams if (door_ki_upcall_limited(event_door, &darg, NULL, SIZE_MAX, 0) != 0) { 177a399b765Szf162725 ieee80211_err("ieee80211_event: door_ki_upcall() failed\n"); 178a399b765Szf162725 } 179a399b765Szf162725 180a399b765Szf162725 if (event_door) { /* release our hold (if any) */ 181a399b765Szf162725 door_ki_rele(event_door); 182a399b765Szf162725 } 183a399b765Szf162725 184a399b765Szf162725 out: 185a399b765Szf162725 mutex_exit(&ic->ic_doorlock); 186a399b765Szf162725 } 187a399b765Szf162725 188a399b765Szf162725 /* 189a399b765Szf162725 * Notify state transition event message to WPA daemon 190a399b765Szf162725 */ 191a399b765Szf162725 void 192a399b765Szf162725 ieee80211_notify(ieee80211com_t *ic, wpa_event_type event) 193a399b765Szf162725 { 194a399b765Szf162725 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) 195a399b765Szf162725 return; /* Not running on WPA mode */ 196a399b765Szf162725 197a399b765Szf162725 ic->ic_eventq[ic->ic_evq_tail] = event; 198a399b765Szf162725 ic->ic_evq_tail ++; 199a399b765Szf162725 if (ic->ic_evq_tail >= MAX_EVENT) ic->ic_evq_tail = 0; 200a399b765Szf162725 201a399b765Szf162725 /* async */ 202a399b765Szf162725 (void) timeout(ieee80211_event_thread, (void *)ic, 0); 203a399b765Szf162725 } 204a399b765Szf162725 205a399b765Szf162725 /* 2063a1a8936Szf162725 * Register WPA door 2073a1a8936Szf162725 */ 2083a1a8936Szf162725 void 2093a1a8936Szf162725 ieee80211_register_door(ieee80211com_t *ic, const char *drvname, int inst) 2103a1a8936Szf162725 { 2113a1a8936Szf162725 (void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", 2123a1a8936Szf162725 WPA_DOOR, drvname, inst); 2133a1a8936Szf162725 } 2143a1a8936Szf162725 2153a1a8936Szf162725 /* 2160ba2cbe9Sxc151355 * Default reset method for use with the ioctl support. This 2170ba2cbe9Sxc151355 * method is invoked after any state change in the 802.11 2180ba2cbe9Sxc151355 * layer that should be propagated to the hardware but not 2190ba2cbe9Sxc151355 * require re-initialization of the 802.11 state machine (e.g 2200ba2cbe9Sxc151355 * rescanning for an ap). We always return ENETRESET which 2210ba2cbe9Sxc151355 * should cause the driver to re-initialize the device. Drivers 2220ba2cbe9Sxc151355 * can override this method to implement more optimized support. 2230ba2cbe9Sxc151355 */ 2240ba2cbe9Sxc151355 /* ARGSUSED */ 2250ba2cbe9Sxc151355 static int 2260ba2cbe9Sxc151355 ieee80211_default_reset(ieee80211com_t *ic) 2270ba2cbe9Sxc151355 { 2280ba2cbe9Sxc151355 return (ENETRESET); 2290ba2cbe9Sxc151355 } 2300ba2cbe9Sxc151355 2310ba2cbe9Sxc151355 /* 2320ba2cbe9Sxc151355 * Convert channel to IEEE channel number. 2330ba2cbe9Sxc151355 */ 2340ba2cbe9Sxc151355 uint32_t 2350ba2cbe9Sxc151355 ieee80211_chan2ieee(ieee80211com_t *ic, struct ieee80211_channel *ch) 2360ba2cbe9Sxc151355 { 2370ba2cbe9Sxc151355 if ((ic->ic_sup_channels <= ch) && 2380ba2cbe9Sxc151355 (ch <= &ic->ic_sup_channels[IEEE80211_CHAN_MAX])) { 2390ba2cbe9Sxc151355 return (ch - ic->ic_sup_channels); 2400ba2cbe9Sxc151355 } else if (ch == IEEE80211_CHAN_ANYC) { 2410ba2cbe9Sxc151355 return (IEEE80211_CHAN_ANY); 2420ba2cbe9Sxc151355 } else if (ch != NULL) { 2430ba2cbe9Sxc151355 ieee80211_err("invalid channel freq %u flags %x\n", 2440ba2cbe9Sxc151355 ch->ich_freq, ch->ich_flags); 2450ba2cbe9Sxc151355 return (0); 2460ba2cbe9Sxc151355 } 2470ba2cbe9Sxc151355 ieee80211_err("invalid channel (NULL)\n"); /* ch == NULL */ 2480ba2cbe9Sxc151355 return (0); 2490ba2cbe9Sxc151355 } 2500ba2cbe9Sxc151355 2510ba2cbe9Sxc151355 /* 2520ba2cbe9Sxc151355 * Convert IEEE channel number to MHz frequency. 2530ba2cbe9Sxc151355 * chan IEEE channel number 2540ba2cbe9Sxc151355 * flags specify whether the frequency is in the 2GHz ISM 2550ba2cbe9Sxc151355 * band or the 5GHz band 2560ba2cbe9Sxc151355 * 2570ba2cbe9Sxc151355 * 802.11b 2GHz: 14 channels, each 5 MHz wide. Channel 1 is placed 2580ba2cbe9Sxc151355 * at 2.412 GHz, channel 2 at 2.417 GHz, and so on up to channel 13 2590ba2cbe9Sxc151355 * at 2.472 GHz. Channel 14 was defined especially for operation in 2600ba2cbe9Sxc151355 * Japan, and has a center frequency 2.484 GHz. 2610ba2cbe9Sxc151355 * 802.11g 2GHz: adopts the frequency plan of 802.11b. Japan only 2620ba2cbe9Sxc151355 * allows 802.11g operation in channels 1-13 2630ba2cbe9Sxc151355 * 802.11a 5GHz: starting every 5 MHz 2640ba2cbe9Sxc151355 * 802.11b/g channels 15-24 (2512-2692) are used by some implementation 2650ba2cbe9Sxc151355 * (Atheros etc.) 2660ba2cbe9Sxc151355 */ 2670ba2cbe9Sxc151355 uint32_t 2680ba2cbe9Sxc151355 ieee80211_ieee2mhz(uint32_t chan, uint32_t flags) 2690ba2cbe9Sxc151355 { 2700ba2cbe9Sxc151355 if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ 2710ba2cbe9Sxc151355 if (chan == 14) 2720ba2cbe9Sxc151355 return (2484); 2730ba2cbe9Sxc151355 if (chan < 14) 2740ba2cbe9Sxc151355 return (2412 + (chan - 1) * 5); 2750ba2cbe9Sxc151355 else 2760ba2cbe9Sxc151355 return (2512 + ((chan - 15) * 20)); 2770ba2cbe9Sxc151355 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ 2780ba2cbe9Sxc151355 return (5000 + (chan * 5)); /* OFDM */ 2790ba2cbe9Sxc151355 } else { /* either, guess */ 2800ba2cbe9Sxc151355 if (chan == 14) 2810ba2cbe9Sxc151355 return (2484); 2820ba2cbe9Sxc151355 if (chan < 14) /* 0-13 */ 2830ba2cbe9Sxc151355 return (2412 + (chan - 1) * 5); 2840ba2cbe9Sxc151355 if (chan < 27) /* 15-26 */ 2850ba2cbe9Sxc151355 return (2512 + ((chan - 15) * 20)); 2860ba2cbe9Sxc151355 return (5000 + (chan * 5)); 2870ba2cbe9Sxc151355 } 2880ba2cbe9Sxc151355 } 2890ba2cbe9Sxc151355 2900ba2cbe9Sxc151355 /* 2910ba2cbe9Sxc151355 * Do late attach work. It must be called by the driver after 2920ba2cbe9Sxc151355 * calling ieee80211_attach() and before calling most ieee80211 2930ba2cbe9Sxc151355 * functions. 2940ba2cbe9Sxc151355 */ 2950ba2cbe9Sxc151355 void 2960ba2cbe9Sxc151355 ieee80211_media_init(ieee80211com_t *ic) 2970ba2cbe9Sxc151355 { 2980ba2cbe9Sxc151355 /* 2990ba2cbe9Sxc151355 * Do late attach work that must wait for any subclass 3000ba2cbe9Sxc151355 * (i.e. driver) work such as overriding methods. 3010ba2cbe9Sxc151355 */ 3020ba2cbe9Sxc151355 ieee80211_node_lateattach(ic); 3030ba2cbe9Sxc151355 } 3040ba2cbe9Sxc151355 3050ba2cbe9Sxc151355 /* 3060ba2cbe9Sxc151355 * Start Watchdog timer. After count down timer(s), ic_watchdog 3070ba2cbe9Sxc151355 * will be called 3080ba2cbe9Sxc151355 */ 3090ba2cbe9Sxc151355 void 3100ba2cbe9Sxc151355 ieee80211_start_watchdog(ieee80211com_t *ic, uint32_t timer) 3110ba2cbe9Sxc151355 { 3120ba2cbe9Sxc151355 if (ic->ic_watchdog_timer == 0 && ic->ic_watchdog != NULL) { 3130ba2cbe9Sxc151355 ic->ic_watchdog_timer = timeout(ic->ic_watchdog, ic, 3140ba2cbe9Sxc151355 drv_usectohz(1000000 * timer)); 3150ba2cbe9Sxc151355 } 3160ba2cbe9Sxc151355 } 3170ba2cbe9Sxc151355 3180ba2cbe9Sxc151355 /* 3190ba2cbe9Sxc151355 * Stop watchdog timer. 3200ba2cbe9Sxc151355 */ 3210ba2cbe9Sxc151355 void 3220ba2cbe9Sxc151355 ieee80211_stop_watchdog(ieee80211com_t *ic) 3230ba2cbe9Sxc151355 { 3240ba2cbe9Sxc151355 if (ic->ic_watchdog_timer != 0) { 3250ba2cbe9Sxc151355 if (ic->ic_watchdog != NULL) 3260ba2cbe9Sxc151355 (void) untimeout(ic->ic_watchdog_timer); 3270ba2cbe9Sxc151355 ic->ic_watchdog_timer = 0; 3280ba2cbe9Sxc151355 } 3290ba2cbe9Sxc151355 } 3300ba2cbe9Sxc151355 3310ba2cbe9Sxc151355 /* 3320ba2cbe9Sxc151355 * Called from a driver's xxx_watchdog routine. It is used to 3330ba2cbe9Sxc151355 * perform periodic cleanup of state for net80211, as well as 3340ba2cbe9Sxc151355 * timeout scans. 3350ba2cbe9Sxc151355 */ 3360ba2cbe9Sxc151355 void 3370ba2cbe9Sxc151355 ieee80211_watchdog(void *arg) 3380ba2cbe9Sxc151355 { 3390ba2cbe9Sxc151355 ieee80211com_t *ic = arg; 3400ba2cbe9Sxc151355 struct ieee80211_impl *im = ic->ic_private; 3410ba2cbe9Sxc151355 ieee80211_node_table_t *nt; 3420ba2cbe9Sxc151355 int inact_timer = 0; 3430ba2cbe9Sxc151355 3440ba2cbe9Sxc151355 if (ic->ic_state == IEEE80211_S_INIT) 3450ba2cbe9Sxc151355 return; 3460ba2cbe9Sxc151355 3470ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 3480ba2cbe9Sxc151355 if ((im->im_mgt_timer != 0) && (--im->im_mgt_timer == 0)) { 3490ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 3500ba2cbe9Sxc151355 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 3510ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 3520ba2cbe9Sxc151355 } 3530ba2cbe9Sxc151355 3540ba2cbe9Sxc151355 nt = &ic->ic_scan; 3550ba2cbe9Sxc151355 if (nt->nt_inact_timer != 0) { 3560ba2cbe9Sxc151355 if (--nt->nt_inact_timer == 0) 3570ba2cbe9Sxc151355 nt->nt_timeout(nt); 3580ba2cbe9Sxc151355 inact_timer += nt->nt_inact_timer; 3590ba2cbe9Sxc151355 } 3600ba2cbe9Sxc151355 nt = &ic->ic_sta; 3610ba2cbe9Sxc151355 if (nt->nt_inact_timer != 0) { 3620ba2cbe9Sxc151355 if (--nt->nt_inact_timer == 0) 3630ba2cbe9Sxc151355 nt->nt_timeout(nt); 3640ba2cbe9Sxc151355 inact_timer += nt->nt_inact_timer; 3650ba2cbe9Sxc151355 } 3660ba2cbe9Sxc151355 3670ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 3680ba2cbe9Sxc151355 3690ba2cbe9Sxc151355 if (im->im_mgt_timer != 0 || inact_timer > 0) 3700ba2cbe9Sxc151355 ieee80211_start_watchdog(ic, 1); 3710ba2cbe9Sxc151355 } 3720ba2cbe9Sxc151355 3730ba2cbe9Sxc151355 /* 3740ba2cbe9Sxc151355 * Set the current phy mode and recalculate the active channel 3750ba2cbe9Sxc151355 * set and supported rates based on the available channels for 3760ba2cbe9Sxc151355 * this mode. Also select a new BSS channel if the current one 3770ba2cbe9Sxc151355 * is inappropriate for this mode. 3780ba2cbe9Sxc151355 * This function is called by net80211, and not intended to be 3790ba2cbe9Sxc151355 * called directly. 3800ba2cbe9Sxc151355 */ 3810ba2cbe9Sxc151355 static int 3820ba2cbe9Sxc151355 ieee80211_setmode(ieee80211com_t *ic, enum ieee80211_phymode mode) 3830ba2cbe9Sxc151355 { 3840ba2cbe9Sxc151355 static const uint32_t chanflags[] = { 3850ba2cbe9Sxc151355 0, /* IEEE80211_MODE_AUTO */ 3860ba2cbe9Sxc151355 IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ 3870ba2cbe9Sxc151355 IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ 3880ba2cbe9Sxc151355 IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ 3890ba2cbe9Sxc151355 IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ 3900ba2cbe9Sxc151355 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */ 3910ba2cbe9Sxc151355 IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ 392*e2cf88acSQuaker Fang IEEE80211_CHAN_ST, /* IEEE80211_MODE_STURBO_A */ 393*e2cf88acSQuaker Fang IEEE80211_CHAN_A, /* IEEE80211_MODE_11NA (check legacy) */ 394*e2cf88acSQuaker Fang IEEE80211_CHAN_G, /* IEEE80211_MODE_11NG (check legacy) */ 3950ba2cbe9Sxc151355 }; 3960ba2cbe9Sxc151355 struct ieee80211_channel *ch; 3970ba2cbe9Sxc151355 uint32_t modeflags; 3980ba2cbe9Sxc151355 int i; 3990ba2cbe9Sxc151355 int achannels = 0; 4000ba2cbe9Sxc151355 4010ba2cbe9Sxc151355 /* validate new mode */ 4020ba2cbe9Sxc151355 if ((ic->ic_modecaps & (1 << mode)) == 0) { 4030ba2cbe9Sxc151355 ieee80211_err("ieee80211_setmode(): mode %u not supported" 4040ba2cbe9Sxc151355 " (caps 0x%x)\n", mode, ic->ic_modecaps); 4050ba2cbe9Sxc151355 return (EINVAL); 4060ba2cbe9Sxc151355 } 4070ba2cbe9Sxc151355 4080ba2cbe9Sxc151355 /* 4090ba2cbe9Sxc151355 * Verify at least one channel is present in the available 4100ba2cbe9Sxc151355 * channel list before committing to the new mode. 4110ba2cbe9Sxc151355 * Calculate the active channel set. 4120ba2cbe9Sxc151355 */ 4130ba2cbe9Sxc151355 ASSERT(mode < IEEE80211_N(chanflags)); 4140ba2cbe9Sxc151355 modeflags = chanflags[mode]; 4150ba2cbe9Sxc151355 bzero(ic->ic_chan_active, sizeof (ic->ic_chan_active)); 4160ba2cbe9Sxc151355 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 4170ba2cbe9Sxc151355 ch = &ic->ic_sup_channels[i]; 4180ba2cbe9Sxc151355 if (ch->ich_flags == 0) 4190ba2cbe9Sxc151355 continue; 4200ba2cbe9Sxc151355 if (mode == IEEE80211_MODE_AUTO) { 4210ba2cbe9Sxc151355 /* take anything but pure turbo channels */ 4220ba2cbe9Sxc151355 if ((ch->ich_flags & ~IEEE80211_CHAN_TURBO) != 0) { 4230ba2cbe9Sxc151355 ieee80211_setbit(ic->ic_chan_active, i); 4240ba2cbe9Sxc151355 achannels++; 4250ba2cbe9Sxc151355 } 4260ba2cbe9Sxc151355 } else { 4270ba2cbe9Sxc151355 if ((ch->ich_flags & modeflags) == modeflags) { 4280ba2cbe9Sxc151355 ieee80211_setbit(ic->ic_chan_active, i); 4290ba2cbe9Sxc151355 achannels++; 4300ba2cbe9Sxc151355 } 4310ba2cbe9Sxc151355 } 4320ba2cbe9Sxc151355 } 4330ba2cbe9Sxc151355 if (achannels == 0) { 4340ba2cbe9Sxc151355 ieee80211_err("ieee80211_setmode(): " 4350ba2cbe9Sxc151355 "no channel found for mode %u\n", mode); 4360ba2cbe9Sxc151355 return (EINVAL); 4370ba2cbe9Sxc151355 } 4380ba2cbe9Sxc151355 4390ba2cbe9Sxc151355 /* 4400ba2cbe9Sxc151355 * If no current/default channel is setup or the current 4410ba2cbe9Sxc151355 * channel is wrong for the mode then pick the first 4420ba2cbe9Sxc151355 * available channel from the active list. This is likely 4430ba2cbe9Sxc151355 * not the right one. 4440ba2cbe9Sxc151355 */ 4450ba2cbe9Sxc151355 if (ic->ic_ibss_chan == NULL || 4460ba2cbe9Sxc151355 ieee80211_isclr(ic->ic_chan_active, 4470ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 4480ba2cbe9Sxc151355 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 4490ba2cbe9Sxc151355 if (ieee80211_isset(ic->ic_chan_active, i)) { 4500ba2cbe9Sxc151355 ic->ic_ibss_chan = &ic->ic_sup_channels[i]; 4510ba2cbe9Sxc151355 break; 4520ba2cbe9Sxc151355 } 4530ba2cbe9Sxc151355 } 4540ba2cbe9Sxc151355 } 4550ba2cbe9Sxc151355 /* 4560ba2cbe9Sxc151355 * If the desired channel is set but no longer valid then reset it. 4570ba2cbe9Sxc151355 */ 4580ba2cbe9Sxc151355 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 4590ba2cbe9Sxc151355 ieee80211_isclr(ic->ic_chan_active, 4600ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_des_chan))) { 4610ba2cbe9Sxc151355 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 4620ba2cbe9Sxc151355 } 4630ba2cbe9Sxc151355 4640ba2cbe9Sxc151355 /* 4650ba2cbe9Sxc151355 * Do mode-specific rate setup. 4660ba2cbe9Sxc151355 */ 4670ba2cbe9Sxc151355 if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B) 4680ba2cbe9Sxc151355 ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode); 4690ba2cbe9Sxc151355 4700ba2cbe9Sxc151355 /* 4710ba2cbe9Sxc151355 * Setup an initial rate set according to the 4720ba2cbe9Sxc151355 * current/default channel. This will be changed 4730ba2cbe9Sxc151355 * when scanning but must exist now so drivers have 4740ba2cbe9Sxc151355 * consistent state of ic_bsschan. 4750ba2cbe9Sxc151355 */ 4760ba2cbe9Sxc151355 if (ic->ic_bss != NULL) 4770ba2cbe9Sxc151355 ic->ic_bss->in_rates = ic->ic_sup_rates[mode]; 4780ba2cbe9Sxc151355 ic->ic_curmode = mode; 4790ba2cbe9Sxc151355 ieee80211_reset_erp(ic); /* reset ERP state */ 480*e2cf88acSQuaker Fang ieee80211_wme_initparams(ic); /* reset WME stat */ 4810ba2cbe9Sxc151355 4820ba2cbe9Sxc151355 return (0); 4830ba2cbe9Sxc151355 } 4840ba2cbe9Sxc151355 4850ba2cbe9Sxc151355 /* 4860ba2cbe9Sxc151355 * Return the phy mode for with the specified channel so the 4870ba2cbe9Sxc151355 * caller can select a rate set. This is problematic for channels 4880ba2cbe9Sxc151355 * where multiple operating modes are possible (e.g. 11g+11b). 4890ba2cbe9Sxc151355 * In those cases we defer to the current operating mode when set. 4900ba2cbe9Sxc151355 */ 491*e2cf88acSQuaker Fang /* ARGSUSED */ 4920ba2cbe9Sxc151355 enum ieee80211_phymode 4930ba2cbe9Sxc151355 ieee80211_chan2mode(ieee80211com_t *ic, struct ieee80211_channel *chan) 4940ba2cbe9Sxc151355 { 495*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HTA(chan)) 496*e2cf88acSQuaker Fang return (IEEE80211_MODE_11NA); 497*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_HTG(chan)) 498*e2cf88acSQuaker Fang return (IEEE80211_MODE_11NG); 499*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_108G(chan)) 5000ba2cbe9Sxc151355 return (IEEE80211_MODE_TURBO_G); 501*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_ST(chan)) 502*e2cf88acSQuaker Fang return (IEEE80211_MODE_STURBO_A); 503*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_T(chan)) 504*e2cf88acSQuaker Fang return (IEEE80211_MODE_TURBO_A); 505*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_A(chan)) 506*e2cf88acSQuaker Fang return (IEEE80211_MODE_11A); 507*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_ANYG(chan)) 5080ba2cbe9Sxc151355 return (IEEE80211_MODE_11G); 509*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_B(chan)) 510*e2cf88acSQuaker Fang return (IEEE80211_MODE_11B); 511*e2cf88acSQuaker Fang else if (IEEE80211_IS_CHAN_FHSS(chan)) 512*e2cf88acSQuaker Fang return (IEEE80211_MODE_FH); 513*e2cf88acSQuaker Fang 514*e2cf88acSQuaker Fang /* NB: should not get here */ 515*e2cf88acSQuaker Fang ieee80211_err("cannot map channel to mode; freq %u flags 0x%x\n", 516*e2cf88acSQuaker Fang chan->ich_freq, chan->ich_flags); 517*e2cf88acSQuaker Fang 5180ba2cbe9Sxc151355 return (IEEE80211_MODE_11B); 5190ba2cbe9Sxc151355 } 520*e2cf88acSQuaker Fang 521*e2cf88acSQuaker Fang const struct ieee80211_rateset * 522*e2cf88acSQuaker Fang ieee80211_get_suprates(ieee80211com_t *ic, struct ieee80211_channel *c) 523*e2cf88acSQuaker Fang { 524*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HTA(c)) 525*e2cf88acSQuaker Fang return (&ic->ic_sup_rates[IEEE80211_MODE_11A]); 526*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HTG(c)) { 527*e2cf88acSQuaker Fang return (&ic->ic_sup_rates[IEEE80211_MODE_11G]); 528*e2cf88acSQuaker Fang } 529*e2cf88acSQuaker Fang return (&ic->ic_sup_rates[ieee80211_chan2mode(ic, c)]); 530*e2cf88acSQuaker Fang } 531*e2cf88acSQuaker Fang 532*e2cf88acSQuaker Fang /* 533*e2cf88acSQuaker Fang * Locate a channel given a frequency+flags. We cache 534*e2cf88acSQuaker Fang * the previous lookup to optimize swithing between two 535*e2cf88acSQuaker Fang * channels--as happens with dynamic turbo. 536*e2cf88acSQuaker Fang */ 537*e2cf88acSQuaker Fang struct ieee80211_channel * 538*e2cf88acSQuaker Fang ieee80211_find_channel(ieee80211com_t *ic, int freq, int flags) 539*e2cf88acSQuaker Fang { 540*e2cf88acSQuaker Fang struct ieee80211_channel *c; 541*e2cf88acSQuaker Fang int i; 542*e2cf88acSQuaker Fang 543*e2cf88acSQuaker Fang flags &= IEEE80211_CHAN_ALLTURBO; 544*e2cf88acSQuaker Fang /* brute force search */ 545*e2cf88acSQuaker Fang for (i = 0; i < IEEE80211_CHAN_MAX; i++) { 546*e2cf88acSQuaker Fang c = &ic->ic_sup_channels[i]; 547*e2cf88acSQuaker Fang if (c->ich_freq == freq && 548*e2cf88acSQuaker Fang (c->ich_flags & IEEE80211_CHAN_ALLTURBO) == flags) 549*e2cf88acSQuaker Fang return (c); 550*e2cf88acSQuaker Fang } 551*e2cf88acSQuaker Fang return (NULL); 5520ba2cbe9Sxc151355 } 5530ba2cbe9Sxc151355 5540ba2cbe9Sxc151355 /* 5550ba2cbe9Sxc151355 * Return the size of the 802.11 header for a management or data frame. 5560ba2cbe9Sxc151355 */ 5570ba2cbe9Sxc151355 int 558*e2cf88acSQuaker Fang ieee80211_hdrsize(const void *data) 5590ba2cbe9Sxc151355 { 5600ba2cbe9Sxc151355 const struct ieee80211_frame *wh = data; 5610ba2cbe9Sxc151355 int size = sizeof (struct ieee80211_frame); 5620ba2cbe9Sxc151355 5630ba2cbe9Sxc151355 /* NB: we don't handle control frames */ 5640ba2cbe9Sxc151355 ASSERT((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) != 5650ba2cbe9Sxc151355 IEEE80211_FC0_TYPE_CTL); 5660ba2cbe9Sxc151355 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 5670ba2cbe9Sxc151355 size += IEEE80211_ADDR_LEN; 568*e2cf88acSQuaker Fang if (IEEE80211_QOS_HAS_SEQ(wh)) 569*e2cf88acSQuaker Fang size += sizeof (uint16_t); 5700ba2cbe9Sxc151355 5710ba2cbe9Sxc151355 return (size); 5720ba2cbe9Sxc151355 } 5730ba2cbe9Sxc151355 5740ba2cbe9Sxc151355 /* 575*e2cf88acSQuaker Fang * Return the space occupied by the 802.11 header and any 576*e2cf88acSQuaker Fang * padding required by the driver. This works for a 577*e2cf88acSQuaker Fang * management or data frame. 578*e2cf88acSQuaker Fang */ 579*e2cf88acSQuaker Fang int 580*e2cf88acSQuaker Fang ieee80211_hdrspace(ieee80211com_t *ic, const void *data) 581*e2cf88acSQuaker Fang { 582*e2cf88acSQuaker Fang int size = ieee80211_hdrsize(data); 583*e2cf88acSQuaker Fang if (ic->ic_flags & IEEE80211_F_DATAPAD) 584*e2cf88acSQuaker Fang size = roundup(size, sizeof (uint32_t)); 585*e2cf88acSQuaker Fang return (size); 586*e2cf88acSQuaker Fang } 587*e2cf88acSQuaker Fang 588*e2cf88acSQuaker Fang /* 589*e2cf88acSQuaker Fang * Like ieee80211_hdrsize, but handles any type of frame. 590*e2cf88acSQuaker Fang */ 591*e2cf88acSQuaker Fang int 592*e2cf88acSQuaker Fang ieee80211_anyhdrsize(const void *data) 593*e2cf88acSQuaker Fang { 594*e2cf88acSQuaker Fang const struct ieee80211_frame *wh = data; 595*e2cf88acSQuaker Fang 596*e2cf88acSQuaker Fang if ((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) { 597*e2cf88acSQuaker Fang switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { 598*e2cf88acSQuaker Fang case IEEE80211_FC0_SUBTYPE_CTS: 599*e2cf88acSQuaker Fang case IEEE80211_FC0_SUBTYPE_ACK: 600*e2cf88acSQuaker Fang return (sizeof (struct ieee80211_frame_ack)); 601*e2cf88acSQuaker Fang case IEEE80211_FC0_SUBTYPE_BAR: 602*e2cf88acSQuaker Fang return (sizeof (struct ieee80211_frame_bar)); 603*e2cf88acSQuaker Fang } 604*e2cf88acSQuaker Fang return (sizeof (struct ieee80211_frame_min)); 605*e2cf88acSQuaker Fang } else 606*e2cf88acSQuaker Fang return (ieee80211_hdrsize(data)); 607*e2cf88acSQuaker Fang } 608*e2cf88acSQuaker Fang 609*e2cf88acSQuaker Fang /* 610*e2cf88acSQuaker Fang * Like ieee80211_hdrspace, but handles any type of frame. 611*e2cf88acSQuaker Fang */ 612*e2cf88acSQuaker Fang int 613*e2cf88acSQuaker Fang ieee80211_anyhdrspace(ieee80211com_t *ic, const void *data) 614*e2cf88acSQuaker Fang { 615*e2cf88acSQuaker Fang int size = ieee80211_anyhdrsize(data); 616*e2cf88acSQuaker Fang if (ic->ic_flags & IEEE80211_F_DATAPAD) 617*e2cf88acSQuaker Fang size = roundup(size, sizeof (uint32_t)); 618*e2cf88acSQuaker Fang return (size); 619*e2cf88acSQuaker Fang } 620*e2cf88acSQuaker Fang 621*e2cf88acSQuaker Fang /* 6220ba2cbe9Sxc151355 * Allocate and setup a management frame of the specified 6230ba2cbe9Sxc151355 * size. We return the mblk and a pointer to the start 6240ba2cbe9Sxc151355 * of the contiguous data area that's been reserved based 6250ba2cbe9Sxc151355 * on the packet length. 6260ba2cbe9Sxc151355 */ 6270ba2cbe9Sxc151355 mblk_t * 6280ba2cbe9Sxc151355 ieee80211_getmgtframe(uint8_t **frm, int pktlen) 6290ba2cbe9Sxc151355 { 6300ba2cbe9Sxc151355 mblk_t *mp; 6310ba2cbe9Sxc151355 int len; 6320ba2cbe9Sxc151355 6330ba2cbe9Sxc151355 len = sizeof (struct ieee80211_frame) + pktlen; 6340ba2cbe9Sxc151355 mp = allocb(len, BPRI_MED); 6350ba2cbe9Sxc151355 if (mp != NULL) { 6360ba2cbe9Sxc151355 *frm = mp->b_rptr + sizeof (struct ieee80211_frame); 6370ba2cbe9Sxc151355 mp->b_wptr = mp->b_rptr + len; 6380ba2cbe9Sxc151355 } else { 6390ba2cbe9Sxc151355 ieee80211_err("ieee80211_getmgtframe: " 6400ba2cbe9Sxc151355 "alloc frame failed, %d\n", len); 6410ba2cbe9Sxc151355 } 6420ba2cbe9Sxc151355 return (mp); 6430ba2cbe9Sxc151355 } 6440ba2cbe9Sxc151355 6450ba2cbe9Sxc151355 /* 6460ba2cbe9Sxc151355 * Send system messages to notify the device has joined a WLAN. 6470ba2cbe9Sxc151355 * This is an OS specific function. Solaris marks link status 6480ba2cbe9Sxc151355 * as up. 6490ba2cbe9Sxc151355 */ 6500ba2cbe9Sxc151355 void 6510ba2cbe9Sxc151355 ieee80211_notify_node_join(ieee80211com_t *ic, ieee80211_node_t *in) 6520ba2cbe9Sxc151355 { 6530ba2cbe9Sxc151355 if (in == ic->ic_bss) 6540ba2cbe9Sxc151355 mac_link_update(ic->ic_mach, LINK_STATE_UP); 655a399b765Szf162725 ieee80211_notify(ic, EVENT_ASSOC); /* notify WPA service */ 6560ba2cbe9Sxc151355 } 6570ba2cbe9Sxc151355 6580ba2cbe9Sxc151355 /* 6590ba2cbe9Sxc151355 * Send system messages to notify the device has left a WLAN. 6600ba2cbe9Sxc151355 * This is an OS specific function. Solaris marks link status 6610ba2cbe9Sxc151355 * as down. 6620ba2cbe9Sxc151355 */ 6630ba2cbe9Sxc151355 void 6640ba2cbe9Sxc151355 ieee80211_notify_node_leave(ieee80211com_t *ic, ieee80211_node_t *in) 6650ba2cbe9Sxc151355 { 6660ba2cbe9Sxc151355 if (in == ic->ic_bss) 6670ba2cbe9Sxc151355 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 668a399b765Szf162725 ieee80211_notify(ic, EVENT_DISASSOC); /* notify WPA service */ 6690ba2cbe9Sxc151355 } 6700ba2cbe9Sxc151355 671*e2cf88acSQuaker Fang 6720ba2cbe9Sxc151355 /* 6730ba2cbe9Sxc151355 * Get 802.11 kstats defined in ieee802.11(5) 6740ba2cbe9Sxc151355 * 6750ba2cbe9Sxc151355 * Return 0 on success 6760ba2cbe9Sxc151355 */ 6770ba2cbe9Sxc151355 int 6780ba2cbe9Sxc151355 ieee80211_stat(ieee80211com_t *ic, uint_t stat, uint64_t *val) 6790ba2cbe9Sxc151355 { 6800ba2cbe9Sxc151355 ASSERT(val != NULL); 6810ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 6820ba2cbe9Sxc151355 switch (stat) { 6830ba2cbe9Sxc151355 case WIFI_STAT_TX_FRAGS: 6840ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_frags; 6850ba2cbe9Sxc151355 break; 6860ba2cbe9Sxc151355 case WIFI_STAT_MCAST_TX: 6870ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_mcast; 6880ba2cbe9Sxc151355 break; 6890ba2cbe9Sxc151355 case WIFI_STAT_TX_FAILED: 6900ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_failed; 6910ba2cbe9Sxc151355 break; 6920ba2cbe9Sxc151355 case WIFI_STAT_TX_RETRANS: 6930ba2cbe9Sxc151355 *val = ic->ic_stats.is_tx_retries; 6940ba2cbe9Sxc151355 break; 6950ba2cbe9Sxc151355 case WIFI_STAT_RTS_SUCCESS: 6960ba2cbe9Sxc151355 *val = ic->ic_stats.is_rts_success; 6970ba2cbe9Sxc151355 break; 6980ba2cbe9Sxc151355 case WIFI_STAT_RTS_FAILURE: 6990ba2cbe9Sxc151355 *val = ic->ic_stats.is_rts_failure; 7000ba2cbe9Sxc151355 break; 7010ba2cbe9Sxc151355 case WIFI_STAT_ACK_FAILURE: 7020ba2cbe9Sxc151355 *val = ic->ic_stats.is_ack_failure; 7030ba2cbe9Sxc151355 break; 7040ba2cbe9Sxc151355 case WIFI_STAT_RX_FRAGS: 7050ba2cbe9Sxc151355 *val = ic->ic_stats.is_rx_frags; 7060ba2cbe9Sxc151355 break; 7070ba2cbe9Sxc151355 case WIFI_STAT_MCAST_RX: 7080ba2cbe9Sxc151355 *val = ic->ic_stats.is_rx_mcast; 7090ba2cbe9Sxc151355 break; 7100ba2cbe9Sxc151355 case WIFI_STAT_RX_DUPS: 7110ba2cbe9Sxc151355 *val = ic->ic_stats.is_rx_dups; 7120ba2cbe9Sxc151355 break; 7130ba2cbe9Sxc151355 case WIFI_STAT_FCS_ERRORS: 7140ba2cbe9Sxc151355 *val = ic->ic_stats.is_fcs_errors; 7150ba2cbe9Sxc151355 break; 7160ba2cbe9Sxc151355 case WIFI_STAT_WEP_ERRORS: 7170ba2cbe9Sxc151355 *val = ic->ic_stats.is_wep_errors; 7180ba2cbe9Sxc151355 break; 7190ba2cbe9Sxc151355 } 7200ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 7210ba2cbe9Sxc151355 return (0); 7220ba2cbe9Sxc151355 } 7230ba2cbe9Sxc151355 7240ba2cbe9Sxc151355 /* 7250ba2cbe9Sxc151355 * Attach network interface to the 802.11 support module. This 7260ba2cbe9Sxc151355 * function must be called before using any of the ieee80211 7270ba2cbe9Sxc151355 * functionss. The parameter "ic" MUST be initialized to tell 7280ba2cbe9Sxc151355 * net80211 about interface's capabilities. 7290ba2cbe9Sxc151355 */ 7300ba2cbe9Sxc151355 void 7310ba2cbe9Sxc151355 ieee80211_attach(ieee80211com_t *ic) 7320ba2cbe9Sxc151355 { 7330ba2cbe9Sxc151355 struct ieee80211_impl *im; 7340ba2cbe9Sxc151355 struct ieee80211_channel *ch; 7350ba2cbe9Sxc151355 int i; 7360ba2cbe9Sxc151355 7370ba2cbe9Sxc151355 /* Check mandatory callback functions not NULL */ 7380ba2cbe9Sxc151355 ASSERT(ic->ic_xmit != NULL); 7390ba2cbe9Sxc151355 7400ba2cbe9Sxc151355 mutex_init(&ic->ic_genlock, NULL, MUTEX_DRIVER, NULL); 741a399b765Szf162725 mutex_init(&ic->ic_doorlock, NULL, MUTEX_DRIVER, NULL); 7420ba2cbe9Sxc151355 7430ba2cbe9Sxc151355 im = kmem_alloc(sizeof (ieee80211_impl_t), KM_SLEEP); 7440ba2cbe9Sxc151355 ic->ic_private = im; 7450ba2cbe9Sxc151355 cv_init(&im->im_scan_cv, NULL, CV_DRIVER, NULL); 7460ba2cbe9Sxc151355 7470ba2cbe9Sxc151355 /* 7480ba2cbe9Sxc151355 * Fill in 802.11 available channel set, mark 7490ba2cbe9Sxc151355 * all available channels as active, and pick 7500ba2cbe9Sxc151355 * a default channel if not already specified. 7510ba2cbe9Sxc151355 */ 7520ba2cbe9Sxc151355 bzero(im->im_chan_avail, sizeof (im->im_chan_avail)); 7530ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO; 7540ba2cbe9Sxc151355 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 7550ba2cbe9Sxc151355 ch = &ic->ic_sup_channels[i]; 7560ba2cbe9Sxc151355 if (ch->ich_flags) { 7570ba2cbe9Sxc151355 /* Verify driver passed us valid data */ 7580ba2cbe9Sxc151355 if (i != ieee80211_chan2ieee(ic, ch)) { 7590ba2cbe9Sxc151355 ieee80211_err("bad channel ignored: " 7600ba2cbe9Sxc151355 "freq %u flags%x number %u\n", 7610ba2cbe9Sxc151355 ch->ich_freq, ch->ich_flags, i); 7620ba2cbe9Sxc151355 ch->ich_flags = 0; 7630ba2cbe9Sxc151355 continue; 7640ba2cbe9Sxc151355 } 7650ba2cbe9Sxc151355 ieee80211_setbit(im->im_chan_avail, i); 7660ba2cbe9Sxc151355 /* Identify mode capabilities */ 7670ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_A(ch)) 7680ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_11A; 7690ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_B(ch)) 7700ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_11B; 7710ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_PUREG(ch)) 7720ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_11G; 7730ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_FHSS(ch)) 7740ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_FH; 7750ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_T(ch)) 7760ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_A; 7770ba2cbe9Sxc151355 if (IEEE80211_IS_CHAN_108G(ch)) 7780ba2cbe9Sxc151355 ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_G; 779*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_ST(ch)) 780*e2cf88acSQuaker Fang ic->ic_modecaps |= 1 << IEEE80211_MODE_STURBO_A; 781*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HTA(ch)) 782*e2cf88acSQuaker Fang ic->ic_modecaps |= 1 << IEEE80211_MODE_11NA; 783*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HTG(ch)) 784*e2cf88acSQuaker Fang ic->ic_modecaps |= 1 << IEEE80211_MODE_11NG; 7850ba2cbe9Sxc151355 if (ic->ic_curchan == NULL) { 7860ba2cbe9Sxc151355 /* arbitrarily pick the first channel */ 7870ba2cbe9Sxc151355 ic->ic_curchan = &ic->ic_sup_channels[i]; 7880ba2cbe9Sxc151355 } 7890ba2cbe9Sxc151355 } 7900ba2cbe9Sxc151355 } 7910ba2cbe9Sxc151355 /* validate ic->ic_curmode */ 7920ba2cbe9Sxc151355 if ((ic->ic_modecaps & (1 << ic->ic_curmode)) == 0) 7930ba2cbe9Sxc151355 ic->ic_curmode = IEEE80211_MODE_AUTO; 7940ba2cbe9Sxc151355 ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ 7950ba2cbe9Sxc151355 (void) ieee80211_setmode(ic, ic->ic_curmode); 7960ba2cbe9Sxc151355 797*e2cf88acSQuaker Fang if (ic->ic_caps & IEEE80211_C_WME) /* enable if capable */ 798*e2cf88acSQuaker Fang ic->ic_flags |= IEEE80211_F_WME; 7990ba2cbe9Sxc151355 if (ic->ic_caps & IEEE80211_C_BURST) 8000ba2cbe9Sxc151355 ic->ic_flags |= IEEE80211_F_BURST; 8010ba2cbe9Sxc151355 ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; 8020ba2cbe9Sxc151355 ic->ic_lintval = ic->ic_bintval; 8030ba2cbe9Sxc151355 ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; 8040ba2cbe9Sxc151355 ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; 8050ba2cbe9Sxc151355 8060ba2cbe9Sxc151355 ic->ic_reset = ieee80211_default_reset; 8070ba2cbe9Sxc151355 8080ba2cbe9Sxc151355 ieee80211_node_attach(ic); 8090ba2cbe9Sxc151355 ieee80211_proto_attach(ic); 8100ba2cbe9Sxc151355 ieee80211_crypto_attach(ic); 811*e2cf88acSQuaker Fang ieee80211_ht_attach(ic); 8120ba2cbe9Sxc151355 8130ba2cbe9Sxc151355 ic->ic_watchdog_timer = 0; 8140ba2cbe9Sxc151355 } 8150ba2cbe9Sxc151355 8160ba2cbe9Sxc151355 /* 8170ba2cbe9Sxc151355 * Free any ieee80211 structures associated with the driver. 8180ba2cbe9Sxc151355 */ 8190ba2cbe9Sxc151355 void 8200ba2cbe9Sxc151355 ieee80211_detach(ieee80211com_t *ic) 8210ba2cbe9Sxc151355 { 8220ba2cbe9Sxc151355 struct ieee80211_impl *im = ic->ic_private; 8230ba2cbe9Sxc151355 8240ba2cbe9Sxc151355 ieee80211_stop_watchdog(ic); 8250ba2cbe9Sxc151355 cv_destroy(&im->im_scan_cv); 8260ba2cbe9Sxc151355 kmem_free(im, sizeof (ieee80211_impl_t)); 8270ba2cbe9Sxc151355 82840db2e2bSzf162725 if (ic->ic_opt_ie != NULL) 82940db2e2bSzf162725 ieee80211_free(ic->ic_opt_ie); 83040db2e2bSzf162725 831*e2cf88acSQuaker Fang ieee80211_ht_detach(ic); 8320ba2cbe9Sxc151355 ieee80211_node_detach(ic); 8330ba2cbe9Sxc151355 ieee80211_crypto_detach(ic); 8340ba2cbe9Sxc151355 8350ba2cbe9Sxc151355 mutex_destroy(&ic->ic_genlock); 836a399b765Szf162725 mutex_destroy(&ic->ic_doorlock); 8370ba2cbe9Sxc151355 } 8380ba2cbe9Sxc151355 8390ba2cbe9Sxc151355 static struct modlmisc i_wifi_modlmisc = { 8400ba2cbe9Sxc151355 &mod_miscops, 841*e2cf88acSQuaker Fang "IEEE80211 Kernel Module v2.0" 8420ba2cbe9Sxc151355 }; 8430ba2cbe9Sxc151355 8440ba2cbe9Sxc151355 static struct modlinkage i_wifi_modlinkage = { 8450ba2cbe9Sxc151355 MODREV_1, 8460ba2cbe9Sxc151355 &i_wifi_modlmisc, 8470ba2cbe9Sxc151355 NULL 8480ba2cbe9Sxc151355 }; 8490ba2cbe9Sxc151355 8500ba2cbe9Sxc151355 /* 8510ba2cbe9Sxc151355 * modlinkage functions 8520ba2cbe9Sxc151355 */ 8530ba2cbe9Sxc151355 int 8540ba2cbe9Sxc151355 _init(void) 8550ba2cbe9Sxc151355 { 8560ba2cbe9Sxc151355 return (mod_install(&i_wifi_modlinkage)); 8570ba2cbe9Sxc151355 } 8580ba2cbe9Sxc151355 8590ba2cbe9Sxc151355 int 8600ba2cbe9Sxc151355 _fini(void) 8610ba2cbe9Sxc151355 { 8620ba2cbe9Sxc151355 return (mod_remove(&i_wifi_modlinkage)); 8630ba2cbe9Sxc151355 } 8640ba2cbe9Sxc151355 8650ba2cbe9Sxc151355 int 8660ba2cbe9Sxc151355 _info(struct modinfo *modinfop) 8670ba2cbe9Sxc151355 { 8680ba2cbe9Sxc151355 return (mod_info(&i_wifi_modlinkage, modinfop)); 8690ba2cbe9Sxc151355 } 870