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