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
ieee80211_err(const int8_t * fmt,...)790ba2cbe9Sxc151355 ieee80211_err(const int8_t *fmt, ...)
800ba2cbe9Sxc151355 {
810ba2cbe9Sxc151355 IEEE80211_DPRINT(CE_WARN, fmt);
820ba2cbe9Sxc151355 }
830ba2cbe9Sxc151355
840ba2cbe9Sxc151355 /*
850ba2cbe9Sxc151355 * Print debug messages
860ba2cbe9Sxc151355 */
870ba2cbe9Sxc151355 void
ieee80211_dbg(uint32_t flag,const int8_t * fmt,...)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 *
ieee80211_malloc(size_t size)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
ieee80211_free(void * p)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
ieee80211_mac_update(ieee80211com_t * ic)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
ieee80211_event_thread(void * arg)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
ieee80211_notify(ieee80211com_t * ic,wpa_event_type event)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
ieee80211_register_door(ieee80211com_t * ic,const char * drvname,int inst)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
ieee80211_default_reset(ieee80211com_t * ic)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
ieee80211_chan2ieee(ieee80211com_t * ic,struct ieee80211_channel * ch)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
ieee80211_ieee2mhz(uint32_t chan,uint32_t flags)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
ieee80211_media_init(ieee80211com_t * ic)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
ieee80211_start_watchdog(ieee80211com_t * ic,uint32_t timer)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
ieee80211_stop_watchdog(ieee80211com_t * ic)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
ieee80211_watchdog(void * arg)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
ieee80211_setmode(ieee80211com_t * ic,enum ieee80211_phymode mode)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
ieee80211_chan2mode(ieee80211com_t * ic,struct ieee80211_channel * chan)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 *
ieee80211_get_suprates(ieee80211com_t * ic,struct ieee80211_channel * c)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 *
ieee80211_find_channel(ieee80211com_t * ic,int freq,int flags)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
ieee80211_hdrsize(const void * data)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
ieee80211_hdrspace(ieee80211com_t * ic,const void * data)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
ieee80211_anyhdrsize(const void * data)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
ieee80211_anyhdrspace(ieee80211com_t * ic,const void * data)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 *
ieee80211_getmgtframe(uint8_t ** frm,int pktlen)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
ieee80211_notify_node_join(ieee80211com_t * ic,ieee80211_node_t * in)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
ieee80211_notify_node_leave(ieee80211com_t * ic,ieee80211_node_t * in)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
ieee80211_stat(ieee80211com_t * ic,uint_t stat,uint64_t * val)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
ieee80211_attach(ieee80211com_t * ic)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
ieee80211_detach(ieee80211com_t * ic)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
_init(void)8540ba2cbe9Sxc151355 _init(void)
8550ba2cbe9Sxc151355 {
8560ba2cbe9Sxc151355 return (mod_install(&i_wifi_modlinkage));
8570ba2cbe9Sxc151355 }
8580ba2cbe9Sxc151355
8590ba2cbe9Sxc151355 int
_fini(void)8600ba2cbe9Sxc151355 _fini(void)
8610ba2cbe9Sxc151355 {
8620ba2cbe9Sxc151355 return (mod_remove(&i_wifi_modlinkage));
8630ba2cbe9Sxc151355 }
8640ba2cbe9Sxc151355
8650ba2cbe9Sxc151355 int
_info(struct modinfo * modinfop)8660ba2cbe9Sxc151355 _info(struct modinfo *modinfop)
8670ba2cbe9Sxc151355 {
8680ba2cbe9Sxc151355 return (mod_info(&i_wifi_modlinkage, modinfop));
8690ba2cbe9Sxc151355 }
870