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