150276Speter/*-
250276Speter * Copyright (c) 2001 Atsushi Onoe
3166124Srafan * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
4166124Srafan * All rights reserved.
5166124Srafan *
697049Speter * Redistribution and use in source and binary forms, with or without
762449Speter * modification, are permitted provided that the following conditions
850276Speter * are met:
9184989Srafan * 1. Redistributions of source code must retain the above copyright
10184989Srafan *    notice, this list of conditions and the following disclaimer.
11166124Srafan * 2. Redistributions in binary form must reproduce the above copyright
1297049Speter *    notice, this list of conditions and the following disclaimer in the
13166124Srafan *    documentation and/or other materials provided with the distribution.
14166124Srafan *
15166124Srafan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1697049Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17166124Srafan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18166124Srafan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19166124Srafan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20166124Srafan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21166124Srafan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22166124Srafan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23166124Srafan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24166124Srafan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25166124Srafan */
26166124Srafan
27166124Srafan#include <sys/cdefs.h>
28166124Srafan__FBSDID("$FreeBSD: releng/10.3/sys/net80211/ieee80211_ioctl.c 252369 2013-06-29 06:36:42Z rpaulo $");
29166124Srafan
30166124Srafan/*
31166124Srafan * IEEE 802.11 ioctl support (FreeBSD-specific)
32166124Srafan */
33166124Srafan
34166124Srafan#include "opt_inet.h"
35166124Srafan#include "opt_ipx.h"
3697049Speter#include "opt_wlan.h"
3750276Speter
3850276Speter#include <sys/endian.h>
3950276Speter#include <sys/param.h>
4050276Speter#include <sys/kernel.h>
4150276Speter#include <sys/priv.h>
4250276Speter#include <sys/socket.h>
4350276Speter#include <sys/sockio.h>
4462449Speter#include <sys/systm.h>
4550276Speter
4662449Speter#include <net/if.h>
4750276Speter#include <net/if_dl.h>
4850276Speter#include <net/if_media.h>
4950276Speter#include <net/ethernet.h>
5050276Speter
5150276Speter#ifdef INET
5250276Speter#include <netinet/in.h>
5350276Speter#include <netinet/if_ether.h>
5450276Speter#endif
5550276Speter
5650276Speter#ifdef IPX
5750276Speter#include <netipx/ipx.h>
5850276Speter#include <netipx/ipx_if.h>
5950276Speter#endif
6050276Speter
6150276Speter#include <net80211/ieee80211_var.h>
6262449Speter#include <net80211/ieee80211_ioctl.h>
6350276Speter#include <net80211/ieee80211_regdomain.h>
6450276Speter#include <net80211/ieee80211_input.h>
6550276Speter
6650276Speter#define	IS_UP_AUTO(_vap) \
6750276Speter	(IFNET_IS_UP_RUNNING((_vap)->iv_ifp) && \
6850276Speter	 (_vap)->iv_roaming == IEEE80211_ROAMING_AUTO)
6950276Speter
7050276Speterstatic const uint8_t zerobssid[IEEE80211_ADDR_LEN];
71166124Srafanstatic struct ieee80211_channel *findchannel(struct ieee80211com *,
7250276Speter		int ieee, int mode);
7350276Speterstatic int ieee80211_scanreq(struct ieee80211vap *,
7450276Speter		struct ieee80211_scan_req *);
7550276Speter
7650276Speterstatic __noinline int
7750276Speterieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
7850276Speter{
7950276Speter	struct ieee80211com *ic = vap->iv_ic;
8050276Speter	struct ieee80211_node *ni;
8150276Speter	struct ieee80211req_key ik;
8250276Speter	struct ieee80211_key *wk;
8350276Speter	const struct ieee80211_cipher *cip;
8450276Speter	u_int kid;
8550276Speter	int error;
8650276Speter
8750276Speter	if (ireq->i_len != sizeof(ik))
8850276Speter		return EINVAL;
8950276Speter	error = copyin(ireq->i_data, &ik, sizeof(ik));
9050276Speter	if (error)
9150276Speter		return error;
9250276Speter	kid = ik.ik_keyix;
9350276Speter	if (kid == IEEE80211_KEYIX_NONE) {
9450276Speter		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, ik.ik_macaddr);
9550276Speter		if (ni == NULL)
9650276Speter			return ENOENT;
97166124Srafan		wk = &ni->ni_ucastkey;
9850276Speter	} else {
9950276Speter		if (kid >= IEEE80211_WEP_NKID)
10050276Speter			return EINVAL;
10150276Speter		wk = &vap->iv_nw_keys[kid];
10250276Speter		IEEE80211_ADDR_COPY(&ik.ik_macaddr, vap->iv_bss->ni_macaddr);
10350276Speter		ni = NULL;
10450276Speter	}
10550276Speter	cip = wk->wk_cipher;
10650276Speter	ik.ik_type = cip->ic_cipher;
10750276Speter	ik.ik_keylen = wk->wk_keylen;
10850276Speter	ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
10950276Speter	if (wk->wk_keyix == vap->iv_def_txkey)
11050276Speter		ik.ik_flags |= IEEE80211_KEY_DEFAULT;
11150276Speter	if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
11250276Speter		/* NB: only root can read key data */
11350276Speter		ik.ik_keyrsc = wk->wk_keyrsc[IEEE80211_NONQOS_TID];
11450276Speter		ik.ik_keytsc = wk->wk_keytsc;
11550276Speter		memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
11650276Speter		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
11750276Speter			memcpy(ik.ik_keydata+wk->wk_keylen,
11850276Speter				wk->wk_key + IEEE80211_KEYBUF_SIZE,
11950276Speter				IEEE80211_MICBUF_SIZE);
12050276Speter			ik.ik_keylen += IEEE80211_MICBUF_SIZE;
12150276Speter		}
12250276Speter	} else {
12350276Speter		ik.ik_keyrsc = 0;
12450276Speter		ik.ik_keytsc = 0;
12550276Speter		memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
12650276Speter	}
12750276Speter	if (ni != NULL)
12850276Speter		ieee80211_free_node(ni);
129166124Srafan	return copyout(&ik, ireq->i_data, sizeof(ik));
13050276Speter}
13150276Speter
13250276Speterstatic __noinline int
13350276Speterieee80211_ioctl_getchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
13450276Speter{
13550276Speter	struct ieee80211com *ic = vap->iv_ic;
13650276Speter
13750276Speter	if (sizeof(ic->ic_chan_active) < ireq->i_len)
13850276Speter		ireq->i_len = sizeof(ic->ic_chan_active);
139166124Srafan	return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
14050276Speter}
14150276Speter
14250276Speterstatic __noinline int
14350276Speterieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq)
14450276Speter{
14550276Speter	struct ieee80211com *ic = vap->iv_ic;
14650276Speter	uint32_t space;
14750276Speter
14850276Speter	space = __offsetof(struct ieee80211req_chaninfo,
14950276Speter			ic_chans[ic->ic_nchans]);
15050276Speter	if (space > ireq->i_len)
15150276Speter		space = ireq->i_len;
15250276Speter	/* XXX assumes compatible layout */
15350276Speter	return copyout(&ic->ic_nchans, ireq->i_data, space);
15450276Speter}
15550276Speter
15650276Speterstatic __noinline int
15750276Speterieee80211_ioctl_getwpaie(struct ieee80211vap *vap,
15850276Speter	struct ieee80211req *ireq, int req)
15950276Speter{
16050276Speter	struct ieee80211_node *ni;
16150276Speter	struct ieee80211req_wpaie2 wpaie;
16250276Speter	int error;
16350276Speter
16450276Speter	if (ireq->i_len < IEEE80211_ADDR_LEN)
16550276Speter		return EINVAL;
16650276Speter	error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
16750276Speter	if (error != 0)
16850276Speter		return error;
16950276Speter	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, wpaie.wpa_macaddr);
17050276Speter	if (ni == NULL)
17150276Speter		return ENOENT;
172166124Srafan	memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
173166124Srafan	if (ni->ni_ies.wpa_ie != NULL) {
174166124Srafan		int ielen = ni->ni_ies.wpa_ie[1] + 2;
17550276Speter		if (ielen > sizeof(wpaie.wpa_ie))
176166124Srafan			ielen = sizeof(wpaie.wpa_ie);
17750276Speter		memcpy(wpaie.wpa_ie, ni->ni_ies.wpa_ie, ielen);
17850276Speter	}
17950276Speter	if (req == IEEE80211_IOC_WPAIE2) {
18050276Speter		memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie));
18150276Speter		if (ni->ni_ies.rsn_ie != NULL) {
18250276Speter			int ielen = ni->ni_ies.rsn_ie[1] + 2;
183166124Srafan			if (ielen > sizeof(wpaie.rsn_ie))
18450276Speter				ielen = sizeof(wpaie.rsn_ie);
18550276Speter			memcpy(wpaie.rsn_ie, ni->ni_ies.rsn_ie, ielen);
18650276Speter		}
18750276Speter		if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
18850276Speter			ireq->i_len = sizeof(struct ieee80211req_wpaie2);
18950276Speter	} else {
19050276Speter		/* compatibility op, may overwrite wpa ie */
19150276Speter		/* XXX check ic_flags? */
19250276Speter		if (ni->ni_ies.rsn_ie != NULL) {
19350276Speter			int ielen = ni->ni_ies.rsn_ie[1] + 2;
19450276Speter			if (ielen > sizeof(wpaie.wpa_ie))
19550276Speter				ielen = sizeof(wpaie.wpa_ie);
19650276Speter			memcpy(wpaie.wpa_ie, ni->ni_ies.rsn_ie, ielen);
19750276Speter		}
19850276Speter		if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
19950276Speter			ireq->i_len = sizeof(struct ieee80211req_wpaie);
20050276Speter	}
20150276Speter	ieee80211_free_node(ni);
20250276Speter	return copyout(&wpaie, ireq->i_data, ireq->i_len);
20350276Speter}
20450276Speter
20550276Speterstatic __noinline int
20650276Speterieee80211_ioctl_getstastats(struct ieee80211vap *vap, struct ieee80211req *ireq)
20750276Speter{
20850276Speter	struct ieee80211_node *ni;
20950276Speter	uint8_t macaddr[IEEE80211_ADDR_LEN];
21050276Speter	const size_t off = __offsetof(struct ieee80211req_sta_stats, is_stats);
21150276Speter	int error;
21250276Speter
21350276Speter	if (ireq->i_len < off)
21450276Speter		return EINVAL;
21550276Speter	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
21650276Speter	if (error != 0)
21750276Speter		return error;
218166124Srafan	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
21950276Speter	if (ni == NULL)
22050276Speter		return ENOENT;
22150276Speter	if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
22250276Speter		ireq->i_len = sizeof(struct ieee80211req_sta_stats);
22350276Speter	/* NB: copy out only the statistics */
22450276Speter	error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
22562449Speter			ireq->i_len - off);
22662449Speter	ieee80211_free_node(ni);
22750276Speter	return error;
22850276Speter}
22950276Speter
23050276Speterstruct scanreq {
23150276Speter	struct ieee80211req_scan_result *sr;
23250276Speter	size_t space;
233166124Srafan};
23450276Speter
23550276Speterstatic size_t
23650276Speterscan_space(const struct ieee80211_scan_entry *se, int *ielen)
23750276Speter{
238166124Srafan	size_t len;
23950276Speter
24050276Speter	*ielen = se->se_ies.len;
24150276Speter	/*
24250276Speter	 * NB: ie's can be no more than 255 bytes and the max 802.11
24350276Speter	 * packet is <3Kbytes so we are sure this doesn't overflow
24462449Speter	 * 16-bits; if this is a concern we can drop the ie's.
24550276Speter	 */
24650276Speter	len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] +
24750276Speter	    se->se_meshid[1] + *ielen;
24850276Speter	return roundup(len, sizeof(uint32_t));
24950276Speter}
25050276Speter
25150276Speterstatic void
25250276Speterget_scan_space(void *arg, const struct ieee80211_scan_entry *se)
25350276Speter{
25450276Speter	struct scanreq *req = arg;
25550276Speter	int ielen;
25650276Speter
25750276Speter	req->space += scan_space(se, &ielen);
25850276Speter}
25950276Speter
260166124Srafanstatic __noinline void
261166124Srafanget_scan_result(void *arg, const struct ieee80211_scan_entry *se)
26250276Speter{
26350276Speter	struct scanreq *req = arg;
26450276Speter	struct ieee80211req_scan_result *sr;
26550276Speter	int ielen, len, nr, nxr;
26650276Speter	uint8_t *cp;
26750276Speter
26850276Speter	len = scan_space(se, &ielen);
26950276Speter	if (len > req->space)
27050276Speter		return;
27150276Speter
272166124Srafan	sr = req->sr;
27350276Speter	KASSERT(len <= 65535 && ielen <= 65535,
27450276Speter	    ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
27550276Speter	sr->isr_len = len;
27650276Speter	sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
27750276Speter	sr->isr_ie_len = ielen;
27850276Speter	sr->isr_freq = se->se_chan->ic_freq;
27950276Speter	sr->isr_flags = se->se_chan->ic_flags;
28050276Speter	sr->isr_rssi = se->se_rssi;
28150276Speter	sr->isr_noise = se->se_noise;
282166124Srafan	sr->isr_intval = se->se_intval;
28350276Speter	sr->isr_capinfo = se->se_capinfo;
28450276Speter	sr->isr_erp = se->se_erp;
28550276Speter	IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
28650276Speter	nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
28750276Speter	memcpy(sr->isr_rates, se->se_rates+2, nr);
28850276Speter	nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
28962449Speter	memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
29050276Speter	sr->isr_nrates = nr + nxr;
29150276Speter
29250276Speter	/* copy SSID */
29350276Speter	sr->isr_ssid_len = se->se_ssid[1];
29450276Speter	cp = ((uint8_t *)sr) + sr->isr_ie_off;
29550276Speter	memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
29650276Speter
29750276Speter	/* copy mesh id */
29850276Speter	cp += sr->isr_ssid_len;
29950276Speter	sr->isr_meshid_len = se->se_meshid[1];
300166124Srafan	memcpy(cp, se->se_meshid+2, sr->isr_meshid_len);
301166124Srafan	cp += sr->isr_meshid_len;
302166124Srafan
303166124Srafan	if (ielen)
304166124Srafan		memcpy(cp, se->se_ies.data, ielen);
305166124Srafan
306166124Srafan	req->space -= len;
307166124Srafan	req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
308166124Srafan}
309166124Srafan
310166124Srafanstatic __noinline int
311166124Srafanieee80211_ioctl_getscanresults(struct ieee80211vap *vap,
312166124Srafan	struct ieee80211req *ireq)
313166124Srafan{
314166124Srafan	struct scanreq req;
31550276Speter	int error;
316166124Srafan
317166124Srafan	if (ireq->i_len < sizeof(struct scanreq))
318166124Srafan		return EFAULT;
31962449Speter
320174993Srafan	error = 0;
321174993Srafan	req.space = 0;
322174993Srafan	ieee80211_scan_iterate(vap, get_scan_space, &req);
323174993Srafan	if (req.space > ireq->i_len)
324174993Srafan		req.space = ireq->i_len;
325174993Srafan	if (req.space > 0) {
326174993Srafan		uint32_t space;
327174993Srafan		void *p;
328174993Srafan
329174993Srafan		space = req.space;
33050276Speter		/* XXX M_WAITOK after driver lock released */
33150276Speter		p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO);
33250276Speter		if (p == NULL)
33350276Speter			return ENOMEM;
33450276Speter		req.sr = p;
33562449Speter		ieee80211_scan_iterate(vap, get_scan_result, &req);
33662449Speter		ireq->i_len = space - req.space;
337166124Srafan		error = copyout(p, ireq->i_data, ireq->i_len);
338166124Srafan		free(p, M_TEMP);
339166124Srafan	} else
340166124Srafan		ireq->i_len = 0;
341166124Srafan
342166124Srafan	return error;
343166124Srafan}
344166124Srafan
345166124Srafanstruct stainforeq {
346166124Srafan	struct ieee80211vap *vap;
347166124Srafan	struct ieee80211req_sta_info *si;
348166124Srafan	size_t	space;
349166124Srafan};
350166124Srafan
351166124Srafanstatic size_t
352166124Srafansta_space(const struct ieee80211_node *ni, size_t *ielen)
353166124Srafan{
354166124Srafan	*ielen = ni->ni_ies.len;
355166124Srafan	return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
356166124Srafan		      sizeof(uint32_t));
357166124Srafan}
358166124Srafan
359166124Srafanstatic void
360166124Srafanget_sta_space(void *arg, struct ieee80211_node *ni)
361166124Srafan{
362166124Srafan	struct stainforeq *req = arg;
363166124Srafan	size_t ielen;
364166124Srafan
365166124Srafan	if (req->vap != ni->ni_vap)
366166124Srafan		return;
367166124Srafan	if (ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP &&
368166124Srafan	    ni->ni_associd == 0)	/* only associated stations */
369166124Srafan		return;
370166124Srafan	req->space += sta_space(ni, &ielen);
371166124Srafan}
372166124Srafan
373166124Srafanstatic __noinline void
374166124Srafanget_sta_info(void *arg, struct ieee80211_node *ni)
375166124Srafan{
376166124Srafan	struct stainforeq *req = arg;
377166124Srafan	struct ieee80211vap *vap = ni->ni_vap;
378166124Srafan	struct ieee80211req_sta_info *si;
379166124Srafan	size_t ielen, len;
380166124Srafan	uint8_t *cp;
381166124Srafan
382166124Srafan	if (req->vap != ni->ni_vap)
38362449Speter		return;
38450276Speter	if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
38550276Speter	    ni->ni_associd == 0)	/* only associated stations */
38650276Speter		return;
38750276Speter	if (ni->ni_chan == IEEE80211_CHAN_ANYC)	/* XXX bogus entry */
38850276Speter		return;
38950276Speter	len = sta_space(ni, &ielen);
390166124Srafan	if (len > req->space)
391166124Srafan		return;
392166124Srafan	si = req->si;
39350276Speter	si->isi_len = len;
394166124Srafan	si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
39550276Speter	si->isi_ie_len = ielen;
39650276Speter	si->isi_freq = ni->ni_chan->ic_freq;
39750276Speter	si->isi_flags = ni->ni_chan->ic_flags;
398166124Srafan	si->isi_state = ni->ni_flags;
399166124Srafan	si->isi_authmode = ni->ni_authmode;
400166124Srafan	vap->iv_ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
401166124Srafan	vap->iv_ic->ic_node_getmimoinfo(ni, &si->isi_mimo);
402166124Srafan	si->isi_capinfo = ni->ni_capinfo;
403166124Srafan	si->isi_erp = ni->ni_erp;
40450276Speter	IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
405166124Srafan	si->isi_nrates = ni->ni_rates.rs_nrates;
406166124Srafan	if (si->isi_nrates > 15)
407166124Srafan		si->isi_nrates = 15;
408166124Srafan	memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
409166124Srafan	si->isi_txrate = ni->ni_txrate;
410166124Srafan	if (si->isi_txrate & IEEE80211_RATE_MCS) {
41150276Speter		const struct ieee80211_mcs_rates *mcs =
41250276Speter		    &ieee80211_htrates[ni->ni_txrate &~ IEEE80211_RATE_MCS];
41350276Speter		if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
41450276Speter			if (ni->ni_flags & IEEE80211_NODE_SGI40)
415166124Srafan				si->isi_txmbps = mcs->ht40_rate_800ns;
416166124Srafan			else
417166124Srafan				si->isi_txmbps = mcs->ht40_rate_400ns;
418166124Srafan		} else {
419166124Srafan			if (ni->ni_flags & IEEE80211_NODE_SGI20)
420166124Srafan				si->isi_txmbps = mcs->ht20_rate_800ns;
42150276Speter			else
42250276Speter				si->isi_txmbps = mcs->ht20_rate_400ns;
42350276Speter		}
424166124Srafan	} else
425166124Srafan		si->isi_txmbps = si->isi_txrate;
426166124Srafan	si->isi_associd = ni->ni_associd;
42750276Speter	si->isi_txpower = ni->ni_txpower;
42850276Speter	si->isi_vlan = ni->ni_vlan;
42950276Speter	if (ni->ni_flags & IEEE80211_NODE_QOS) {
43050276Speter		memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
43150276Speter		memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
43250276Speter	} else {
43350276Speter		si->isi_txseqs[0] = ni->ni_txseqs[IEEE80211_NONQOS_TID];
43450276Speter		si->isi_rxseqs[0] = ni->ni_rxseqs[IEEE80211_NONQOS_TID];
435166124Srafan	}
436166124Srafan	/* NB: leave all cases in case we relax ni_associd == 0 check */
437166124Srafan	if (ieee80211_node_is_authorized(ni))
43850276Speter		si->isi_inact = vap->iv_inact_run;
43950276Speter	else if (ni->ni_associd != 0 ||
44050276Speter	    (vap->iv_opmode == IEEE80211_M_WDS &&
441166124Srafan	     (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)))
442166124Srafan		si->isi_inact = vap->iv_inact_auth;
443166124Srafan	else
444166124Srafan		si->isi_inact = vap->iv_inact_init;
44550276Speter	si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
44650276Speter	si->isi_localid = ni->ni_mllid;
447166124Srafan	si->isi_peerid = ni->ni_mlpid;
448166124Srafan	si->isi_peerstate = ni->ni_mlstate;
44950276Speter
45050276Speter	if (ielen) {
45150276Speter		cp = ((uint8_t *)si) + si->isi_ie_off;
45250276Speter		memcpy(cp, ni->ni_ies.data, ielen);
45350276Speter	}
454166124Srafan
455166124Srafan	req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
456166124Srafan	req->space -= len;
457166124Srafan}
458166124Srafan
459166124Srafanstatic __noinline int
460166124Srafangetstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq,
46150276Speter	struct ieee80211_node *ni, size_t off)
46250276Speter{
46350276Speter	struct ieee80211com *ic = vap->iv_ic;
46450276Speter	struct stainforeq req;
46550276Speter	size_t space;
46650276Speter	void *p;
46750276Speter	int error;
46850276Speter
46950276Speter	error = 0;
47050276Speter	req.space = 0;
47162449Speter	req.vap = vap;
47262449Speter	if (ni == NULL)
47362449Speter		ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
47462449Speter	else
475166124Srafan		get_sta_space(&req, ni);
476166124Srafan	if (req.space > ireq->i_len)
477166124Srafan		req.space = ireq->i_len;
478166124Srafan	if (req.space > 0) {
47962449Speter		space = req.space;
480166124Srafan		/* XXX M_WAITOK after driver lock released */
48162449Speter		p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO);
482166124Srafan		if (p == NULL) {
483166124Srafan			error = ENOMEM;
484166124Srafan			goto bad;
485166124Srafan		}
48650276Speter		req.si = p;
487166124Srafan		if (ni == NULL)
488166124Srafan			ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
489166124Srafan		else
490166124Srafan			get_sta_info(&req, ni);
49162449Speter		ireq->i_len = space - req.space;
49250276Speter		error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
49350276Speter		free(p, M_TEMP);
49450276Speter	} else
49550276Speter		ireq->i_len = 0;
49650276Speterbad:
49750276Speter	if (ni != NULL)
49850276Speter		ieee80211_free_node(ni);
49950276Speter	return error;
50050276Speter}
50150276Speter
50250276Speterstatic __noinline int
50350276Speterieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq)
50450276Speter{
50550276Speter	uint8_t macaddr[IEEE80211_ADDR_LEN];
50650276Speter	const size_t off = __offsetof(struct ieee80211req_sta_req, info);
50750276Speter	struct ieee80211_node *ni;
50850276Speter	int error;
50950276Speter
51050276Speter	if (ireq->i_len < sizeof(struct ieee80211req_sta_req))
51150276Speter		return EFAULT;
51250276Speter	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
51350276Speter	if (error != 0)
51450276Speter		return error;
51550276Speter	if (IEEE80211_ADDR_EQ(macaddr, vap->iv_ifp->if_broadcastaddr)) {
51650276Speter		ni = NULL;
51750276Speter	} else {
51862449Speter		ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
519166124Srafan		if (ni == NULL)
520166124Srafan			return ENOENT;
521166124Srafan	}
522166124Srafan	return getstainfo_common(vap, ireq, ni, off);
523166124Srafan}
524166124Srafan
525166124Srafanstatic __noinline int
526166124Srafanieee80211_ioctl_getstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq)
527166124Srafan{
528166124Srafan	struct ieee80211_node *ni;
529166124Srafan	struct ieee80211req_sta_txpow txpow;
53050276Speter	int error;
53150276Speter
532166124Srafan	if (ireq->i_len != sizeof(txpow))
533166124Srafan		return EINVAL;
534166124Srafan	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
53550276Speter	if (error != 0)
53650276Speter		return error;
537166124Srafan	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, txpow.it_macaddr);
53850276Speter	if (ni == NULL)
53950276Speter		return ENOENT;
54050276Speter	txpow.it_txpow = ni->ni_txpower;
541166124Srafan	error = copyout(&txpow, ireq->i_data, sizeof(txpow));
542166124Srafan	ieee80211_free_node(ni);
543166124Srafan	return error;
544166124Srafan}
545166124Srafan
546166124Srafanstatic __noinline int
547166124Srafanieee80211_ioctl_getwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq)
548166124Srafan{
549166124Srafan	struct ieee80211com *ic = vap->iv_ic;
550166124Srafan	struct ieee80211_wme_state *wme = &ic->ic_wme;
551166124Srafan	struct wmeParams *wmep;
552166124Srafan	int ac;
553166124Srafan
554166124Srafan	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
555166124Srafan		return EINVAL;
55650276Speter
557166124Srafan	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
558166124Srafan	if (ac >= WME_NUM_AC)
559166124Srafan		ac = WME_AC_BE;
560166124Srafan	if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
561166124Srafan		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
562166124Srafan	else
563166124Srafan		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
564166124Srafan	switch (ireq->i_type) {
56550276Speter	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
56650276Speter		ireq->i_val = wmep->wmep_logcwmin;
56750276Speter		break;
56850276Speter	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
56950276Speter		ireq->i_val = wmep->wmep_logcwmax;
570166124Srafan		break;
571166124Srafan	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
572166124Srafan		ireq->i_val = wmep->wmep_aifsn;
573166124Srafan		break;
574166124Srafan	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
575166124Srafan		ireq->i_val = wmep->wmep_txopLimit;
576166124Srafan		break;
577166124Srafan	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
578166124Srafan		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
579166124Srafan		ireq->i_val = wmep->wmep_acm;
580166124Srafan		break;
58150276Speter	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
582166124Srafan		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
583166124Srafan		ireq->i_val = !wmep->wmep_noackPolicy;
584166124Srafan		break;
585166124Srafan	}
58650276Speter	return 0;
58750276Speter}
58850276Speter
589166124Srafanstatic __noinline int
590166124Srafanieee80211_ioctl_getmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq)
59150276Speter{
592166124Srafan	const struct ieee80211_aclator *acl = vap->iv_acl;
593166124Srafan
594166124Srafan	return (acl == NULL ? EINVAL : acl->iac_getioctl(vap, ireq));
595166124Srafan}
596166124Srafan
597166124Srafanstatic __noinline int
59862449Speterieee80211_ioctl_getcurchan(struct ieee80211vap *vap, struct ieee80211req *ireq)
599166124Srafan{
600166124Srafan	struct ieee80211com *ic = vap->iv_ic;
601166124Srafan	struct ieee80211_channel *c;
602166124Srafan
603166124Srafan	if (ireq->i_len != sizeof(struct ieee80211_channel))
604166124Srafan		return EINVAL;
60562449Speter	/*
60650276Speter	 * vap's may have different operating channels when HT is
60750276Speter	 * in use.  When in RUN state report the vap-specific channel.
60850276Speter	 * Otherwise return curchan.
60950276Speter	 */
610166124Srafan	if (vap->iv_state == IEEE80211_S_RUN)
61150276Speter		c = vap->iv_bss->ni_chan;
61250276Speter	else
61350276Speter		c = ic->ic_curchan;
614166124Srafan	return copyout(c, ireq->i_data, sizeof(*c));
615166124Srafan}
616166124Srafan
617166124Srafanstatic int
618166124Srafangetappie(const struct ieee80211_appie *aie, struct ieee80211req *ireq)
619166124Srafan{
620166124Srafan	if (aie == NULL)
621166124Srafan		return EINVAL;
622166124Srafan	/* NB: truncate, caller can check length */
623166124Srafan	if (ireq->i_len > aie->ie_len)
624166124Srafan		ireq->i_len = aie->ie_len;
62550276Speter	return copyout(aie->ie_data, ireq->i_data, ireq->i_len);
62650276Speter}
62750276Speter
62850276Speterstatic int
62950276Speterieee80211_ioctl_getappie(struct ieee80211vap *vap, struct ieee80211req *ireq)
63050276Speter{
63150276Speter	uint8_t fc0;
63250276Speter
63350276Speter	fc0 = ireq->i_val & 0xff;
63450276Speter	if ((fc0 & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
63550276Speter		return EINVAL;
63650276Speter	/* NB: could check iv_opmode and reject but hardly worth the effort */
63750276Speter	switch (fc0 & IEEE80211_FC0_SUBTYPE_MASK) {
63850276Speter	case IEEE80211_FC0_SUBTYPE_BEACON:
639166124Srafan		return getappie(vap->iv_appie_beacon, ireq);
640166124Srafan	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
641166124Srafan		return getappie(vap->iv_appie_proberesp, ireq);
642166124Srafan	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
643166124Srafan		return getappie(vap->iv_appie_assocresp, ireq);
64450276Speter	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
64550276Speter		return getappie(vap->iv_appie_probereq, ireq);
646166124Srafan	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
647166124Srafan		return getappie(vap->iv_appie_assocreq, ireq);
648166124Srafan	case IEEE80211_FC0_SUBTYPE_BEACON|IEEE80211_FC0_SUBTYPE_PROBE_RESP:
649166124Srafan		return getappie(vap->iv_appie_wpa, ireq);
65050276Speter	}
65150276Speter	return EINVAL;
652166124Srafan}
653166124Srafan
654166124Srafanstatic __noinline int
655166124Srafanieee80211_ioctl_getregdomain(struct ieee80211vap *vap,
65650276Speter	const struct ieee80211req *ireq)
65750276Speter{
65850276Speter	struct ieee80211com *ic = vap->iv_ic;
65950276Speter
66050276Speter	if (ireq->i_len != sizeof(ic->ic_regdomain))
66150276Speter		return EINVAL;
66250276Speter	return copyout(&ic->ic_regdomain, ireq->i_data,
663166124Srafan	    sizeof(ic->ic_regdomain));
664166124Srafan}
665166124Srafan
666166124Srafanstatic __noinline int
667166124Srafanieee80211_ioctl_getroam(struct ieee80211vap *vap,
668166124Srafan	const struct ieee80211req *ireq)
669166124Srafan{
670166124Srafan	size_t len = ireq->i_len;
671166124Srafan	/* NB: accept short requests for backwards compat */
672166124Srafan	if (len > sizeof(vap->iv_roamparms))
673166124Srafan		len = sizeof(vap->iv_roamparms);
674166124Srafan	return copyout(vap->iv_roamparms, ireq->i_data, len);
675166124Srafan}
676166124Srafan
677166124Srafanstatic __noinline int
678166124Srafanieee80211_ioctl_gettxparams(struct ieee80211vap *vap,
679166124Srafan	const struct ieee80211req *ireq)
680166124Srafan{
681166124Srafan	size_t len = ireq->i_len;
682166124Srafan	/* NB: accept short requests for backwards compat */
683166124Srafan	if (len > sizeof(vap->iv_txparms))
684166124Srafan		len = sizeof(vap->iv_txparms);
685166124Srafan	return copyout(vap->iv_txparms, ireq->i_data, len);
68650276Speter}
68750276Speter
68850276Speterstatic __noinline int
68950276Speterieee80211_ioctl_getdevcaps(struct ieee80211com *ic,
69050276Speter	const struct ieee80211req *ireq)
69150276Speter{
69250276Speter	struct ieee80211_devcaps_req *dc;
69350276Speter	struct ieee80211req_chaninfo *ci;
69450276Speter	int maxchans, error;
69550276Speter
69650276Speter	maxchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_devcaps_req)) /
69750276Speter	    sizeof(struct ieee80211_channel));
69850276Speter	/* NB: require 1 so we know ic_nchans is accessible */
69950276Speter	if (maxchans < 1)
70050276Speter		return EINVAL;
70150276Speter	/* constrain max request size, 2K channels is ~24Kbytes */
70250276Speter	if (maxchans > 2048)
70350276Speter		maxchans = 2048;
70450276Speter	dc = (struct ieee80211_devcaps_req *)
70550276Speter	    malloc(IEEE80211_DEVCAPS_SIZE(maxchans), M_TEMP, M_NOWAIT | M_ZERO);
70650276Speter	if (dc == NULL)
70750276Speter		return ENOMEM;
70850276Speter	dc->dc_drivercaps = ic->ic_caps;
70950276Speter	dc->dc_cryptocaps = ic->ic_cryptocaps;
710166124Srafan	dc->dc_htcaps = ic->ic_htcaps;
71150276Speter	ci = &dc->dc_chaninfo;
71250276Speter	ic->ic_getradiocaps(ic, maxchans, &ci->ic_nchans, ci->ic_chans);
713166124Srafan	KASSERT(ci->ic_nchans <= maxchans,
714166124Srafan	    ("nchans %d maxchans %d", ci->ic_nchans, maxchans));
715166124Srafan	ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans);
716166124Srafan	error = copyout(dc, ireq->i_data, IEEE80211_DEVCAPS_SPACE(dc));
717166124Srafan	free(dc, M_TEMP);
718166124Srafan	return error;
719166124Srafan}
720166124Srafan
721166124Srafanstatic __noinline int
722166124Srafanieee80211_ioctl_getstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
723166124Srafan{
724166124Srafan	struct ieee80211_node *ni;
725166124Srafan	struct ieee80211req_sta_vlan vlan;
726166124Srafan	int error;
727166124Srafan
728166124Srafan	if (ireq->i_len != sizeof(vlan))
729166124Srafan		return EINVAL;
730166124Srafan	error = copyin(ireq->i_data, &vlan, sizeof(vlan));
731166124Srafan	if (error != 0)
732166124Srafan		return error;
733166124Srafan	if (!IEEE80211_ADDR_EQ(vlan.sv_macaddr, zerobssid)) {
734166124Srafan		ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
735166124Srafan		    vlan.sv_macaddr);
736166124Srafan		if (ni == NULL)
737166124Srafan			return ENOENT;
738166124Srafan	} else
739166124Srafan		ni = ieee80211_ref_node(vap->iv_bss);
740166124Srafan	vlan.sv_vlan = ni->ni_vlan;
741166124Srafan	error = copyout(&vlan, ireq->i_data, sizeof(vlan));
74262449Speter	ieee80211_free_node(ni);
74362449Speter	return error;
744166124Srafan}
745166124Srafan
746166124Srafan/*
747166124Srafan * Dummy ioctl get handler so the linker set is defined.
748166124Srafan */
749166124Srafanstatic int
750166124Srafandummy_ioctl_get(struct ieee80211vap *vap, struct ieee80211req *ireq)
751166124Srafan{
752166124Srafan	return ENOSYS;
753166124Srafan}
754166124SrafanIEEE80211_IOCTL_GET(dummy, dummy_ioctl_get);
755166124Srafan
756166124Srafanstatic int
75750276Speterieee80211_ioctl_getdefault(struct ieee80211vap *vap, struct ieee80211req *ireq)
75850276Speter{
75950276Speter	ieee80211_ioctl_getfunc * const *get;
760166124Srafan	int error;
761166124Srafan
762166124Srafan	SET_FOREACH(get, ieee80211_ioctl_getset) {
76350276Speter		error = (*get)(vap, ireq);
764184989Srafan		if (error != ENOSYS)
765184989Srafan			return error;
766184989Srafan	}
767184989Srafan	return EINVAL;
768184989Srafan}
769184989Srafan
770184989Srafan/*
771184989Srafan * When building the kernel with -O2 on the i386 architecture, gcc
772184989Srafan * seems to want to inline this function into ieee80211_ioctl()
77350276Speter * (which is the only routine that calls it). When this happens,
774166124Srafan * ieee80211_ioctl() ends up consuming an additional 2K of stack
775166124Srafan * space. (Exactly why it needs so much is unclear.) The problem
77650276Speter * is that it's possible for ieee80211_ioctl() to invoke other
77750276Speter * routines (including driver init functions) which could then find
77850276Speter * themselves perilously close to exhausting the stack.
779166124Srafan *
780166124Srafan * To avoid this, we deliberately prevent gcc from inlining this
781166124Srafan * routine. Another way to avoid this is to use less agressive
78250276Speter * optimization when compiling this file (i.e. -O instead of -O2)
78350276Speter * but special-casing the compilation of this one module in the
78450276Speter * build system would be awkward.
785166124Srafan */
786166124Srafanstatic __noinline int
78750276Speterieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
78862449Speter    struct ieee80211req *ireq)
789166124Srafan{
790166124Srafan#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
791166124Srafan	struct ieee80211com *ic = vap->iv_ic;
79262449Speter	u_int kid, len;
793166124Srafan	uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
794166124Srafan	char tmpssid[IEEE80211_NWID_LEN];
795166124Srafan	int error = 0;
796166124Srafan
797166124Srafan	switch (ireq->i_type) {
798166124Srafan	case IEEE80211_IOC_SSID:
799166124Srafan		switch (vap->iv_state) {
800166124Srafan		case IEEE80211_S_INIT:
801166124Srafan		case IEEE80211_S_SCAN:
802166124Srafan			ireq->i_len = vap->iv_des_ssid[0].len;
803166124Srafan			memcpy(tmpssid, vap->iv_des_ssid[0].ssid, ireq->i_len);
804166124Srafan			break;
805166124Srafan		default:
806166124Srafan			ireq->i_len = vap->iv_bss->ni_esslen;
807166124Srafan			memcpy(tmpssid, vap->iv_bss->ni_essid, ireq->i_len);
808166124Srafan			break;
809166124Srafan		}
810166124Srafan		error = copyout(tmpssid, ireq->i_data, ireq->i_len);
811166124Srafan		break;
812166124Srafan	case IEEE80211_IOC_NUMSSIDS:
813166124Srafan		ireq->i_val = 1;
814166124Srafan		break;
815166124Srafan	case IEEE80211_IOC_WEP:
816166124Srafan		if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0)
81762449Speter			ireq->i_val = IEEE80211_WEP_OFF;
81862449Speter		else if (vap->iv_flags & IEEE80211_F_DROPUNENC)
81962449Speter			ireq->i_val = IEEE80211_WEP_ON;
82062449Speter		else
821166124Srafan			ireq->i_val = IEEE80211_WEP_MIXED;
822166124Srafan		break;
823166124Srafan	case IEEE80211_IOC_WEPKEY:
824166124Srafan		kid = (u_int) ireq->i_val;
825166124Srafan		if (kid >= IEEE80211_WEP_NKID)
826166124Srafan			return EINVAL;
827166124Srafan		len = (u_int) vap->iv_nw_keys[kid].wk_keylen;
828166124Srafan		/* NB: only root can read WEP keys */
829166124Srafan		if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
830166124Srafan			bcopy(vap->iv_nw_keys[kid].wk_key, tmpkey, len);
831166124Srafan		} else {
832166124Srafan			bzero(tmpkey, len);
833166124Srafan		}
834166124Srafan		ireq->i_len = len;
835166124Srafan		error = copyout(tmpkey, ireq->i_data, len);
836166124Srafan		break;
837166124Srafan	case IEEE80211_IOC_NUMWEPKEYS:
838166124Srafan		ireq->i_val = IEEE80211_WEP_NKID;
839166124Srafan		break;
840166124Srafan	case IEEE80211_IOC_WEPTXKEY:
84150276Speter		ireq->i_val = vap->iv_def_txkey;
842166124Srafan		break;
843166124Srafan	case IEEE80211_IOC_AUTHMODE:
844166124Srafan		if (vap->iv_flags & IEEE80211_F_WPA)
845166124Srafan			ireq->i_val = IEEE80211_AUTH_WPA;
846166124Srafan		else
847166124Srafan			ireq->i_val = vap->iv_bss->ni_authmode;
848166124Srafan		break;
849166124Srafan	case IEEE80211_IOC_CHANNEL:
850166124Srafan		ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
851166124Srafan		break;
852166124Srafan	case IEEE80211_IOC_POWERSAVE:
853166124Srafan		if (vap->iv_flags & IEEE80211_F_PMGTON)
854166124Srafan			ireq->i_val = IEEE80211_POWERSAVE_ON;
855166124Srafan		else
856166124Srafan			ireq->i_val = IEEE80211_POWERSAVE_OFF;
857166124Srafan		break;
858166124Srafan	case IEEE80211_IOC_POWERSAVESLEEP:
859166124Srafan		ireq->i_val = ic->ic_lintval;
860166124Srafan		break;
861166124Srafan	case IEEE80211_IOC_RTSTHRESHOLD:
862166124Srafan		ireq->i_val = vap->iv_rtsthreshold;
863166124Srafan		break;
864166124Srafan	case IEEE80211_IOC_PROTMODE:
865166124Srafan		ireq->i_val = ic->ic_protmode;
866166124Srafan		break;
867166124Srafan	case IEEE80211_IOC_TXPOWER:
868166124Srafan		/*
869166124Srafan		 * Tx power limit is the min of max regulatory
870166124Srafan		 * power, any user-set limit, and the max the
871166124Srafan		 * radio can do.
872166124Srafan		 */
873166124Srafan		ireq->i_val = 2*ic->ic_curchan->ic_maxregpower;
874166124Srafan		if (ireq->i_val > ic->ic_txpowlimit)
875166124Srafan			ireq->i_val = ic->ic_txpowlimit;
876166124Srafan		if (ireq->i_val > ic->ic_curchan->ic_maxpower)
877166124Srafan			ireq->i_val = ic->ic_curchan->ic_maxpower;
878166124Srafan		break;
879166124Srafan	case IEEE80211_IOC_WPA:
880166124Srafan		switch (vap->iv_flags & IEEE80211_F_WPA) {
881166124Srafan		case IEEE80211_F_WPA1:
882166124Srafan			ireq->i_val = 1;
883166124Srafan			break;
884166124Srafan		case IEEE80211_F_WPA2:
885166124Srafan			ireq->i_val = 2;
886166124Srafan			break;
887166124Srafan		case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
888166124Srafan			ireq->i_val = 3;
889166124Srafan			break;
890166124Srafan		default:
891166124Srafan			ireq->i_val = 0;
892166124Srafan			break;
893166124Srafan		}
894166124Srafan		break;
895166124Srafan	case IEEE80211_IOC_CHANLIST:
896166124Srafan		error = ieee80211_ioctl_getchanlist(vap, ireq);
897166124Srafan		break;
898166124Srafan	case IEEE80211_IOC_ROAMING:
89962449Speter		ireq->i_val = vap->iv_roaming;
90062449Speter		break;
90150276Speter	case IEEE80211_IOC_PRIVACY:
90262449Speter		ireq->i_val = (vap->iv_flags & IEEE80211_F_PRIVACY) != 0;
903166124Srafan		break;
904166124Srafan	case IEEE80211_IOC_DROPUNENCRYPTED:
905166124Srafan		ireq->i_val = (vap->iv_flags & IEEE80211_F_DROPUNENC) != 0;
906166124Srafan		break;
907166124Srafan	case IEEE80211_IOC_COUNTERMEASURES:
908166124Srafan		ireq->i_val = (vap->iv_flags & IEEE80211_F_COUNTERM) != 0;
90962449Speter		break;
91050276Speter	case IEEE80211_IOC_WME:
91150276Speter		ireq->i_val = (vap->iv_flags & IEEE80211_F_WME) != 0;
91250276Speter		break;
91350276Speter	case IEEE80211_IOC_HIDESSID:
91450276Speter		ireq->i_val = (vap->iv_flags & IEEE80211_F_HIDESSID) != 0;
91550276Speter		break;
91650276Speter	case IEEE80211_IOC_APBRIDGE:
91750276Speter		ireq->i_val = (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0;
91850276Speter		break;
91950276Speter	case IEEE80211_IOC_WPAKEY:
92056639Speter		error = ieee80211_ioctl_getkey(vap, ireq);
92156639Speter		break;
92298503Speter	case IEEE80211_IOC_CHANINFO:
92398503Speter		error = ieee80211_ioctl_getchaninfo(vap, ireq);
92450276Speter		break;
92550276Speter	case IEEE80211_IOC_BSSID:
92650276Speter		if (ireq->i_len != IEEE80211_ADDR_LEN)
92776726Speter			return EINVAL;
92876726Speter		if (vap->iv_state == IEEE80211_S_RUN) {
92976726Speter			error = copyout(vap->iv_opmode == IEEE80211_M_WDS ?
93076726Speter			    vap->iv_bss->ni_macaddr : vap->iv_bss->ni_bssid,
93176726Speter			    ireq->i_data, ireq->i_len);
93276726Speter		} else
93376726Speter			error = copyout(vap->iv_des_bssid, ireq->i_data,
93476726Speter			    ireq->i_len);
93576726Speter		break;
93676726Speter	case IEEE80211_IOC_WPAIE:
93776726Speter		error = ieee80211_ioctl_getwpaie(vap, ireq, ireq->i_type);
938166124Srafan		break;
939166124Srafan	case IEEE80211_IOC_WPAIE2:
940166124Srafan		error = ieee80211_ioctl_getwpaie(vap, ireq, ireq->i_type);
941166124Srafan		break;
942166124Srafan	case IEEE80211_IOC_SCAN_RESULTS:
943166124Srafan		error = ieee80211_ioctl_getscanresults(vap, ireq);
944166124Srafan		break;
945166124Srafan	case IEEE80211_IOC_STA_STATS:
946166124Srafan		error = ieee80211_ioctl_getstastats(vap, ireq);
947166124Srafan		break;
948166124Srafan	case IEEE80211_IOC_TXPOWMAX:
949166124Srafan		ireq->i_val = vap->iv_bss->ni_txpower;
950166124Srafan		break;
951166124Srafan	case IEEE80211_IOC_STA_TXPOW:
952166124Srafan		error = ieee80211_ioctl_getstatxpow(vap, ireq);
953166124Srafan		break;
954166124Srafan	case IEEE80211_IOC_STA_INFO:
955166124Srafan		error = ieee80211_ioctl_getstainfo(vap, ireq);
956166124Srafan		break;
957166124Srafan	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
958166124Srafan	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
959166124Srafan	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
960166124Srafan	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
961166124Srafan	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
962166124Srafan	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
963166124Srafan		error = ieee80211_ioctl_getwmeparam(vap, ireq);
964166124Srafan		break;
965166124Srafan	case IEEE80211_IOC_DTIM_PERIOD:
966166124Srafan		ireq->i_val = vap->iv_dtim_period;
967166124Srafan		break;
968166124Srafan	case IEEE80211_IOC_BEACON_INTERVAL:
969166124Srafan		/* NB: get from ic_bss for station mode */
970166124Srafan		ireq->i_val = vap->iv_bss->ni_intval;
971166124Srafan		break;
972166124Srafan	case IEEE80211_IOC_PUREG:
973166124Srafan		ireq->i_val = (vap->iv_flags & IEEE80211_F_PUREG) != 0;
974166124Srafan		break;
975166124Srafan	case IEEE80211_IOC_QUIET:
976166124Srafan		ireq->i_val = vap->iv_quiet;
977166124Srafan		break;
978166124Srafan	case IEEE80211_IOC_QUIET_COUNT:
97998503Speter		ireq->i_val = vap->iv_quiet_count;
980166124Srafan		break;
981166124Srafan	case IEEE80211_IOC_QUIET_PERIOD:
98250276Speter		ireq->i_val = vap->iv_quiet_period;
98350276Speter		break;
98450276Speter	case IEEE80211_IOC_QUIET_DUR:
98550276Speter		ireq->i_val = vap->iv_quiet_duration;
986166124Srafan		break;
987166124Srafan	case IEEE80211_IOC_QUIET_OFFSET:
988166124Srafan		ireq->i_val = vap->iv_quiet_offset;
989166124Srafan		break;
990166124Srafan	case IEEE80211_IOC_BGSCAN:
991166124Srafan		ireq->i_val = (vap->iv_flags & IEEE80211_F_BGSCAN) != 0;
992166124Srafan		break;
993166124Srafan	case IEEE80211_IOC_BGSCAN_IDLE:
994166124Srafan		ireq->i_val = vap->iv_bgscanidle*hz/1000;	/* ms */
995166124Srafan		break;
996166124Srafan	case IEEE80211_IOC_BGSCAN_INTERVAL:
997166124Srafan		ireq->i_val = vap->iv_bgscanintvl/hz;		/* seconds */
998166124Srafan		break;
999166124Srafan	case IEEE80211_IOC_SCANVALID:
1000166124Srafan		ireq->i_val = vap->iv_scanvalid/hz;		/* seconds */
1001166124Srafan		break;
1002166124Srafan	case IEEE80211_IOC_FRAGTHRESHOLD:
1003166124Srafan		ireq->i_val = vap->iv_fragthreshold;
1004166124Srafan		break;
1005166124Srafan	case IEEE80211_IOC_MACCMD:
1006166124Srafan		error = ieee80211_ioctl_getmaccmd(vap, ireq);
1007166124Srafan		break;
1008166124Srafan	case IEEE80211_IOC_BURST:
100950276Speter		ireq->i_val = (vap->iv_flags & IEEE80211_F_BURST) != 0;
1010166124Srafan		break;
1011166124Srafan	case IEEE80211_IOC_BMISSTHRESHOLD:
1012166124Srafan		ireq->i_val = vap->iv_bmissthreshold;
1013166124Srafan		break;
1014166124Srafan	case IEEE80211_IOC_CURCHAN:
1015166124Srafan		error = ieee80211_ioctl_getcurchan(vap, ireq);
1016166124Srafan		break;
1017166124Srafan	case IEEE80211_IOC_SHORTGI:
1018166124Srafan		ireq->i_val = 0;
1019166124Srafan		if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
1020166124Srafan			ireq->i_val |= IEEE80211_HTCAP_SHORTGI20;
1021166124Srafan		if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
1022166124Srafan			ireq->i_val |= IEEE80211_HTCAP_SHORTGI40;
102350276Speter		break;
102450276Speter	case IEEE80211_IOC_AMPDU:
102550276Speter		ireq->i_val = 0;
102650276Speter		if (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)
102750276Speter			ireq->i_val |= 1;
102850276Speter		if (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)
102950276Speter			ireq->i_val |= 2;
1030166124Srafan		break;
103150276Speter	case IEEE80211_IOC_AMPDU_LIMIT:
103250276Speter		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
103350276Speter			ireq->i_val = vap->iv_ampdu_rxmax;
103450276Speter		else if (vap->iv_state == IEEE80211_S_RUN)
103550276Speter			ireq->i_val = MS(vap->iv_bss->ni_htparam,
1036166124Srafan			    IEEE80211_HTCAP_MAXRXAMPDU);
1037166124Srafan		else
103850276Speter			ireq->i_val = vap->iv_ampdu_limit;
103950276Speter		break;
104050276Speter	case IEEE80211_IOC_AMPDU_DENSITY:
104150276Speter		if (vap->iv_opmode == IEEE80211_M_STA &&
104250276Speter		    vap->iv_state == IEEE80211_S_RUN)
104350276Speter			ireq->i_val = MS(vap->iv_bss->ni_htparam,
104450276Speter			    IEEE80211_HTCAP_MPDUDENSITY);
104550276Speter		else
104650276Speter			ireq->i_val = vap->iv_ampdu_density;
104750276Speter		break;
104850276Speter	case IEEE80211_IOC_AMSDU:
104950276Speter		ireq->i_val = 0;
105050276Speter		if (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_TX)
105150276Speter			ireq->i_val |= 1;
105250276Speter		if (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_RX)
1053166124Srafan			ireq->i_val |= 2;
1054166124Srafan		break;
105550276Speter	case IEEE80211_IOC_AMSDU_LIMIT:
105650276Speter		ireq->i_val = vap->iv_amsdu_limit;	/* XXX truncation? */
105750276Speter		break;
105850276Speter	case IEEE80211_IOC_PUREN:
1059166124Srafan		ireq->i_val = (vap->iv_flags_ht & IEEE80211_FHT_PUREN) != 0;
1060166124Srafan		break;
1061166124Srafan	case IEEE80211_IOC_DOTH:
1062166124Srafan		ireq->i_val = (vap->iv_flags & IEEE80211_F_DOTH) != 0;
106350276Speter		break;
106450276Speter	case IEEE80211_IOC_REGDOMAIN:
106550276Speter		error = ieee80211_ioctl_getregdomain(vap, ireq);
106650276Speter		break;
106750276Speter	case IEEE80211_IOC_ROAM:
1068166124Srafan		error = ieee80211_ioctl_getroam(vap, ireq);
1069166124Srafan		break;
1070166124Srafan	case IEEE80211_IOC_TXPARAMS:
107150276Speter		error = ieee80211_ioctl_gettxparams(vap, ireq);
107250276Speter		break;
107350276Speter	case IEEE80211_IOC_HTCOMPAT:
107450276Speter		ireq->i_val = (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) != 0;
107550276Speter		break;
1076166124Srafan	case IEEE80211_IOC_DWDS:
107750276Speter		ireq->i_val = (vap->iv_flags & IEEE80211_F_DWDS) != 0;
107850276Speter		break;
107950276Speter	case IEEE80211_IOC_INACTIVITY:
108050276Speter		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_INACT) != 0;
1081166124Srafan		break;
108250276Speter	case IEEE80211_IOC_APPIE:
108350276Speter		error = ieee80211_ioctl_getappie(vap, ireq);
1084166124Srafan		break;
108550276Speter	case IEEE80211_IOC_WPS:
108650276Speter		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_WPS) != 0;
108750276Speter		break;
108850276Speter	case IEEE80211_IOC_TSN:
1089166124Srafan		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_TSN) != 0;
1090166124Srafan		break;
109150276Speter	case IEEE80211_IOC_DFS:
109250276Speter		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_DFS) != 0;
109350276Speter		break;
109450276Speter	case IEEE80211_IOC_DOTD:
109550276Speter		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_DOTD) != 0;
109650276Speter		break;
109750276Speter	case IEEE80211_IOC_DEVCAPS:
109850276Speter		error = ieee80211_ioctl_getdevcaps(ic, ireq);
109950276Speter		break;
110050276Speter	case IEEE80211_IOC_HTPROTMODE:
110150276Speter		ireq->i_val = ic->ic_htprotmode;
110250276Speter		break;
110350276Speter	case IEEE80211_IOC_HTCONF:
110450276Speter		if (vap->iv_flags_ht & IEEE80211_FHT_HT) {
1105166124Srafan			ireq->i_val = 1;
1106166124Srafan			if (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)
110750276Speter				ireq->i_val |= 2;
110850276Speter		} else
110950276Speter			ireq->i_val = 0;
111050276Speter		break;
111150276Speter	case IEEE80211_IOC_STA_VLAN:
111250276Speter		error = ieee80211_ioctl_getstavlan(vap, ireq);
111350276Speter		break;
111450276Speter	case IEEE80211_IOC_SMPS:
111550276Speter		if (vap->iv_opmode == IEEE80211_M_STA &&
111650276Speter		    vap->iv_state == IEEE80211_S_RUN) {
111750276Speter			if (vap->iv_bss->ni_flags & IEEE80211_NODE_MIMO_RTS)
111850276Speter				ireq->i_val = IEEE80211_HTCAP_SMPS_DYNAMIC;
111950276Speter			else if (vap->iv_bss->ni_flags & IEEE80211_NODE_MIMO_PS)
112050276Speter				ireq->i_val = IEEE80211_HTCAP_SMPS_ENA;
1121166124Srafan			else
112250276Speter				ireq->i_val = IEEE80211_HTCAP_SMPS_OFF;
112350276Speter		} else
112450276Speter			ireq->i_val = vap->iv_htcaps & IEEE80211_HTCAP_SMPS;
112550276Speter		break;
112650276Speter	case IEEE80211_IOC_RIFS:
112750276Speter		if (vap->iv_opmode == IEEE80211_M_STA &&
112850276Speter		    vap->iv_state == IEEE80211_S_RUN)
112950276Speter			ireq->i_val =
113050276Speter			    (vap->iv_bss->ni_flags & IEEE80211_NODE_RIFS) != 0;
113150276Speter		else
113250276Speter			ireq->i_val =
113350276Speter			    (vap->iv_flags_ht & IEEE80211_FHT_RIFS) != 0;
113450276Speter		break;
113550276Speter	default:
113650276Speter		error = ieee80211_ioctl_getdefault(vap, ireq);
113750276Speter		break;
113850276Speter	}
113950276Speter	return error;
114050276Speter#undef MS
1141166124Srafan}
1142166124Srafan
1143166124Srafanstatic __noinline int
1144166124Srafanieee80211_ioctl_setkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
1145166124Srafan{
1146166124Srafan	struct ieee80211req_key ik;
1147166124Srafan	struct ieee80211_node *ni;
1148166124Srafan	struct ieee80211_key *wk;
1149166124Srafan	uint16_t kid;
1150166124Srafan	int error, i;
1151166124Srafan
1152166124Srafan	if (ireq->i_len != sizeof(ik))
1153166124Srafan		return EINVAL;
1154166124Srafan	error = copyin(ireq->i_data, &ik, sizeof(ik));
1155166124Srafan	if (error)
1156166124Srafan		return error;
1157166124Srafan	/* NB: cipher support is verified by ieee80211_crypt_newkey */
1158166124Srafan	/* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
1159166124Srafan	if (ik.ik_keylen > sizeof(ik.ik_keydata))
1160166124Srafan		return E2BIG;
1161166124Srafan	kid = ik.ik_keyix;
1162166124Srafan	if (kid == IEEE80211_KEYIX_NONE) {
1163166124Srafan		/* XXX unicast keys currently must be tx/rx */
1164166124Srafan		if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
1165166124Srafan			return EINVAL;
1166166124Srafan		if (vap->iv_opmode == IEEE80211_M_STA) {
116750276Speter			ni = ieee80211_ref_node(vap->iv_bss);
116850276Speter			if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
116950276Speter				ieee80211_free_node(ni);
117050276Speter				return EADDRNOTAVAIL;
117150276Speter			}
117250276Speter		} else {
117350276Speter			ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
117450276Speter				ik.ik_macaddr);
117550276Speter			if (ni == NULL)
117650276Speter				return ENOENT;
117750276Speter		}
117850276Speter		wk = &ni->ni_ucastkey;
117950276Speter	} else {
118050276Speter		if (kid >= IEEE80211_WEP_NKID)
118150276Speter			return EINVAL;
118250276Speter		wk = &vap->iv_nw_keys[kid];
118350276Speter		/*
118450276Speter		 * Global slots start off w/o any assigned key index.
118550276Speter		 * Force one here for consistency with IEEE80211_IOC_WEPKEY.
118650276Speter		 */
118750276Speter		if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
118850276Speter			wk->wk_keyix = kid;
118950276Speter		ni = NULL;
119050276Speter	}
119150276Speter	error = 0;
119250276Speter	ieee80211_key_update_begin(vap);
119350276Speter	if (ieee80211_crypto_newkey(vap, ik.ik_type, ik.ik_flags, wk)) {
119450276Speter		wk->wk_keylen = ik.ik_keylen;
119550276Speter		/* NB: MIC presence is implied by cipher type */
119650276Speter		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
119750276Speter			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
119850276Speter		for (i = 0; i < IEEE80211_TID_SIZE; i++)
119950276Speter			wk->wk_keyrsc[i] = ik.ik_keyrsc;
120050276Speter		wk->wk_keytsc = 0;			/* new key, reset */
1201166124Srafan		memset(wk->wk_key, 0, sizeof(wk->wk_key));
1202166124Srafan		memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
1203166124Srafan		IEEE80211_ADDR_COPY(wk->wk_macaddr,
1204166124Srafan		    ni != NULL ?  ni->ni_macaddr : ik.ik_macaddr);
1205166124Srafan		if (!ieee80211_crypto_setkey(vap, wk))
1206166124Srafan			error = EIO;
1207166124Srafan		else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
1208166124Srafan			vap->iv_def_txkey = kid;
1209166124Srafan	} else
1210166124Srafan		error = ENXIO;
1211166124Srafan	ieee80211_key_update_end(vap);
1212166124Srafan	if (ni != NULL)
1213166124Srafan		ieee80211_free_node(ni);
1214166124Srafan	return error;
1215166124Srafan}
1216166124Srafan
1217166124Srafanstatic __noinline int
1218166124Srafanieee80211_ioctl_delkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
1219166124Srafan{
1220166124Srafan	struct ieee80211req_del_key dk;
1221166124Srafan	int kid, error;
1222166124Srafan
1223166124Srafan	if (ireq->i_len != sizeof(dk))
1224166124Srafan		return EINVAL;
1225166124Srafan	error = copyin(ireq->i_data, &dk, sizeof(dk));
1226166124Srafan	if (error)
122750276Speter		return error;
122850276Speter	kid = dk.idk_keyix;
122950276Speter	/* XXX uint8_t -> uint16_t */
1230166124Srafan	if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
1231166124Srafan		struct ieee80211_node *ni;
1232166124Srafan
1233166124Srafan		if (vap->iv_opmode == IEEE80211_M_STA) {
1234166124Srafan			ni = ieee80211_ref_node(vap->iv_bss);
1235166124Srafan			if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
1236166124Srafan				ieee80211_free_node(ni);
1237166124Srafan				return EADDRNOTAVAIL;
123850276Speter			}
123950276Speter		} else {
124050276Speter			ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
124150276Speter				dk.idk_macaddr);
124250276Speter			if (ni == NULL)
124350276Speter				return ENOENT;
124450276Speter		}
124550276Speter		/* XXX error return */
1246166124Srafan		ieee80211_node_delucastkey(ni);
1247166124Srafan		ieee80211_free_node(ni);
1248166124Srafan	} else {
1249166124Srafan		if (kid >= IEEE80211_WEP_NKID)
1250166124Srafan			return EINVAL;
1251166124Srafan		/* XXX error return */
1252166124Srafan		ieee80211_crypto_delkey(vap, &vap->iv_nw_keys[kid]);
125350276Speter	}
125450276Speter	return 0;
125550276Speter}
125650276Speter
125750276Speterstruct mlmeop {
125850276Speter	struct ieee80211vap *vap;
125950276Speter	int	op;
126050276Speter	int	reason;
126150276Speter};
126250276Speter
126350276Speterstatic void
126450276Spetermlmedebug(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
1265166124Srafan	int op, int reason)
1266166124Srafan{
1267166124Srafan#ifdef IEEE80211_DEBUG
1268166124Srafan	static const struct {
1269166124Srafan		int mask;
1270166124Srafan		const char *opstr;
1271166124Srafan	} ops[] = {
1272166124Srafan		{ 0, "op#0" },
1273166124Srafan		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
127450276Speter		  IEEE80211_MSG_ASSOC, "assoc" },
127562449Speter		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
127662449Speter		  IEEE80211_MSG_ASSOC, "disassoc" },
127750276Speter		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
127850276Speter		  IEEE80211_MSG_AUTH, "deauth" },
127950276Speter		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
128050276Speter		  IEEE80211_MSG_AUTH, "authorize" },
128150276Speter		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
128250276Speter		  IEEE80211_MSG_AUTH, "unauthorize" },
128350276Speter	};
128450276Speter
128550276Speter	if (op == IEEE80211_MLME_AUTH) {
1286166124Srafan		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_IOCTL |
1287166124Srafan		    IEEE80211_MSG_STATE | IEEE80211_MSG_AUTH, mac,
1288166124Srafan		    "station authenticate %s via MLME (reason %d)",
1289166124Srafan		    reason == IEEE80211_STATUS_SUCCESS ? "ACCEPT" : "REJECT",
1290166124Srafan		    reason);
1291166124Srafan	} else if (!(IEEE80211_MLME_ASSOC <= op && op <= IEEE80211_MLME_AUTH)) {
1292166124Srafan		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ANY, mac,
1293166124Srafan		    "unknown MLME request %d (reason %d)", op, reason);
1294166124Srafan	} else if (reason == IEEE80211_STATUS_SUCCESS) {
1295166124Srafan		IEEE80211_NOTE_MAC(vap, ops[op].mask, mac,
1296166124Srafan		    "station %s via MLME", ops[op].opstr);
1297166124Srafan	} else {
1298166124Srafan		IEEE80211_NOTE_MAC(vap, ops[op].mask, mac,
1299166124Srafan		    "station %s via MLME (reason %d)", ops[op].opstr, reason);
1300166124Srafan	}
1301166124Srafan#endif /* IEEE80211_DEBUG */
1302166124Srafan}
1303166124Srafan
1304166124Srafanstatic void
1305166124Srafandomlme(void *arg, struct ieee80211_node *ni)
1306166124Srafan{
1307166124Srafan	struct mlmeop *mop = arg;
1308166124Srafan	struct ieee80211vap *vap = ni->ni_vap;
1309166124Srafan
1310166124Srafan	if (vap != mop->vap)
1311166124Srafan		return;
1312166124Srafan	/*
1313166124Srafan	 * NB: if ni_associd is zero then the node is already cleaned
1314166124Srafan	 * up and we don't need to do this (we're safely holding a
1315166124Srafan	 * reference but should otherwise not modify it's state).
1316166124Srafan	 */
1317166124Srafan	if (ni->ni_associd == 0)
1318166124Srafan		return;
1319166124Srafan	mlmedebug(vap, ni->ni_macaddr, mop->op, mop->reason);
1320166124Srafan	if (mop->op == IEEE80211_MLME_DEAUTH) {
1321166124Srafan		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
1322166124Srafan		    mop->reason);
1323166124Srafan	} else {
1324166124Srafan		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC,
1325166124Srafan		    mop->reason);
1326166124Srafan	}
1327166124Srafan	ieee80211_node_leave(ni);
1328166124Srafan}
1329166124Srafan
1330166124Srafanstatic int
1331166124Srafansetmlme_dropsta(struct ieee80211vap *vap,
1332166124Srafan	const uint8_t mac[IEEE80211_ADDR_LEN], struct mlmeop *mlmeop)
1333166124Srafan{
1334166124Srafan	struct ieee80211com *ic = vap->iv_ic;
1335166124Srafan	struct ieee80211_node_table *nt = &ic->ic_sta;
1336166124Srafan	struct ieee80211_node *ni;
1337166124Srafan	int error = 0;
1338166124Srafan
133966963Speter	/* NB: the broadcast address means do 'em all */
134066963Speter	if (!IEEE80211_ADDR_EQ(mac, ic->ic_ifp->if_broadcastaddr)) {
1341166124Srafan		IEEE80211_NODE_LOCK(nt);
1342166124Srafan		ni = ieee80211_find_node_locked(nt, mac);
134366963Speter		IEEE80211_NODE_UNLOCK(nt);
1344166124Srafan		/*
1345166124Srafan		 * Don't do the node update inside the node
1346166124Srafan		 * table lock.  This unfortunately causes LORs
1347166124Srafan		 * with drivers and their TX paths.
1348166124Srafan		 */
1349166124Srafan		if (ni != NULL) {
135066963Speter			domlme(mlmeop, ni);
1351166124Srafan			ieee80211_free_node(ni);
1352166124Srafan		} else
135366963Speter			error = ENOENT;
135466963Speter	} else {
135566963Speter		ieee80211_iterate_nodes(nt, domlme, mlmeop);
135666963Speter	}
135766963Speter	return error;
135866963Speter}
135966963Speter
1360166124Srafanstatic __noinline int
1361166124Srafansetmlme_common(struct ieee80211vap *vap, int op,
1362166124Srafan	const uint8_t mac[IEEE80211_ADDR_LEN], int reason)
136350276Speter{
136450276Speter	struct ieee80211com *ic = vap->iv_ic;
136550276Speter	struct ieee80211_node_table *nt = &ic->ic_sta;
136650276Speter	struct ieee80211_node *ni;
1367166124Srafan	struct mlmeop mlmeop;
1368166124Srafan	int error;
1369166124Srafan
1370166124Srafan	error = 0;
137150276Speter	switch (op) {
137266963Speter	case IEEE80211_MLME_DISASSOC:
1373166124Srafan	case IEEE80211_MLME_DEAUTH:
1374166124Srafan		switch (vap->iv_opmode) {
1375166124Srafan		case IEEE80211_M_STA:
1376166124Srafan			mlmedebug(vap, vap->iv_bss->ni_macaddr, op, reason);
1377166124Srafan			/* XXX not quite right */
1378166124Srafan			ieee80211_new_state(vap, IEEE80211_S_INIT, reason);
1379166124Srafan			break;
1380166124Srafan		case IEEE80211_M_HOSTAP:
1381166124Srafan			mlmeop.vap = vap;
1382166124Srafan			mlmeop.op = op;
1383166124Srafan			mlmeop.reason = reason;
1384166124Srafan			error = setmlme_dropsta(vap, mac, &mlmeop);
1385166124Srafan			break;
1386166124Srafan		case IEEE80211_M_WDS:
1387166124Srafan			/* XXX user app should send raw frame? */
1388166124Srafan			if (op != IEEE80211_MLME_DEAUTH) {
1389166124Srafan				error = EINVAL;
1390166124Srafan				break;
1391166124Srafan			}
1392166124Srafan#if 0
1393166124Srafan			/* XXX accept any address, simplifies user code */
1394166124Srafan			if (!IEEE80211_ADDR_EQ(mac, vap->iv_bss->ni_macaddr)) {
1395166124Srafan				error = EINVAL;
1396166124Srafan				break;
1397166124Srafan			}
1398166124Srafan#endif
1399166124Srafan			mlmedebug(vap, vap->iv_bss->ni_macaddr, op, reason);
1400166124Srafan			ni = ieee80211_ref_node(vap->iv_bss);
1401166124Srafan			IEEE80211_SEND_MGMT(ni,
1402166124Srafan			    IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
1403166124Srafan			ieee80211_free_node(ni);
1404166124Srafan			break;
1405166124Srafan		case IEEE80211_M_MBSS:
1406166124Srafan			IEEE80211_NODE_LOCK(nt);
1407166124Srafan			ni = ieee80211_find_node_locked(nt, mac);
1408166124Srafan			/*
1409166124Srafan			 * Don't do the node update inside the node
1410166124Srafan			 * table lock.  This unfortunately causes LORs
1411166124Srafan			 * with drivers and their TX paths.
1412166124Srafan			 */
1413166124Srafan			IEEE80211_NODE_UNLOCK(nt);
1414166124Srafan			if (ni != NULL) {
1415166124Srafan				ieee80211_node_leave(ni);
1416166124Srafan				ieee80211_free_node(ni);
1417166124Srafan			} else {
1418166124Srafan				error = ENOENT;
1419166124Srafan			}
1420166124Srafan			break;
142166963Speter		default:
1422166124Srafan			error = EINVAL;
1423166124Srafan			break;
142466963Speter		}
1425166124Srafan		break;
1426166124Srafan	case IEEE80211_MLME_AUTHORIZE:
142766963Speter	case IEEE80211_MLME_UNAUTHORIZE:
1428166124Srafan		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
1429166124Srafan		    vap->iv_opmode != IEEE80211_M_WDS) {
1430166124Srafan			error = EINVAL;
1431166124Srafan			break;
1432166124Srafan		}
1433166124Srafan		IEEE80211_NODE_LOCK(nt);
143466963Speter		ni = ieee80211_find_vap_node_locked(nt, vap, mac);
1435166124Srafan		/*
1436166124Srafan		 * Don't do the node update inside the node
143766963Speter		 * table lock.  This unfortunately causes LORs
143850276Speter		 * with drivers and their TX paths.
143950276Speter		 */
144050276Speter		IEEE80211_NODE_UNLOCK(nt);
144150276Speter		if (ni != NULL) {
144250276Speter			mlmedebug(vap, mac, op, reason);
144350276Speter			if (op == IEEE80211_MLME_AUTHORIZE)
144450276Speter				ieee80211_node_authorize(ni);
144550276Speter			else
144650276Speter				ieee80211_node_unauthorize(ni);
144750276Speter			ieee80211_free_node(ni);
144850276Speter		} else
144950276Speter			error = ENOENT;
145050276Speter		break;
1451166124Srafan	case IEEE80211_MLME_AUTH:
1452166124Srafan		if (vap->iv_opmode != IEEE80211_M_HOSTAP) {
1453166124Srafan			error = EINVAL;
1454166124Srafan			break;
1455166124Srafan		}
1456166124Srafan		IEEE80211_NODE_LOCK(nt);
1457166124Srafan		ni = ieee80211_find_vap_node_locked(nt, vap, mac);
1458166124Srafan		/*
1459166124Srafan		 * Don't do the node update inside the node
1460166124Srafan		 * table lock.  This unfortunately causes LORs
1461166124Srafan		 * with drivers and their TX paths.
1462166124Srafan		 */
1463166124Srafan		IEEE80211_NODE_UNLOCK(nt);
1464166124Srafan		if (ni != NULL) {
1465166124Srafan			mlmedebug(vap, mac, op, reason);
1466166124Srafan			if (reason == IEEE80211_STATUS_SUCCESS) {
1467166124Srafan				IEEE80211_SEND_MGMT(ni,
1468166124Srafan				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
1469166124Srafan				/*
1470166124Srafan				 * For shared key auth, just continue the
1471166124Srafan				 * exchange.  Otherwise when 802.1x is not in
1472166124Srafan				 * use mark the port authorized at this point
1473166124Srafan				 * so traffic can flow.
147450276Speter				 */
147550276Speter				if (ni->ni_authmode != IEEE80211_AUTH_8021X &&
147650276Speter				    ni->ni_challenge == NULL)
147750276Speter				      ieee80211_node_authorize(ni);
1478166124Srafan			} else {
1479166124Srafan				vap->iv_stats.is_rx_acl++;
1480166124Srafan				ieee80211_send_error(ni, ni->ni_macaddr,
1481166124Srafan				    IEEE80211_FC0_SUBTYPE_AUTH, 2|(reason<<16));
1482166124Srafan				ieee80211_node_leave(ni);
1483166124Srafan			}
1484166124Srafan			ieee80211_free_node(ni);
1485166124Srafan		} else
1486166124Srafan			error = ENOENT;
1487166124Srafan		break;
1488166124Srafan	default:
1489166124Srafan		error = EINVAL;
1490166124Srafan		break;
1491166124Srafan	}
1492166124Srafan	return error;
1493166124Srafan}
1494166124Srafan
1495166124Srafanstruct scanlookup {
149650276Speter	const uint8_t *mac;
149750276Speter	int esslen;
149850276Speter	const uint8_t *essid;
149950276Speter	const struct ieee80211_scan_entry *se;
1500166124Srafan};
1501166124Srafan
1502166124Srafan/*
1503166124Srafan * Match mac address and any ssid.
1504166124Srafan */
1505166124Srafanstatic void
1506166124Srafanmlmelookup(void *arg, const struct ieee80211_scan_entry *se)
1507166124Srafan{
1508166124Srafan	struct scanlookup *look = arg;
1509166124Srafan
1510166124Srafan	if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
1511166124Srafan		return;
1512166124Srafan	if (look->esslen != 0) {
1513166124Srafan		if (se->se_ssid[1] != look->esslen)
1514166124Srafan			return;
1515166124Srafan		if (memcmp(look->essid, se->se_ssid+2, look->esslen))
1516166124Srafan			return;
1517166124Srafan	}
151850276Speter	look->se = se;
151998503Speter}
1520166124Srafan
1521166124Srafanstatic __noinline int
1522166124Srafansetmlme_assoc_sta(struct ieee80211vap *vap,
1523166124Srafan	const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
1524166124Srafan	const uint8_t ssid[IEEE80211_NWID_LEN])
1525166124Srafan{
1526166124Srafan	struct scanlookup lookup;
1527166124Srafan
152898503Speter	KASSERT(vap->iv_opmode == IEEE80211_M_STA,
152950276Speter	    ("expected opmode STA not %s",
153050276Speter	    ieee80211_opmode_name[vap->iv_opmode]));
153150276Speter
153250276Speter	/* NB: this is racey if roaming is !manual */
153350276Speter	lookup.se = NULL;
1534166124Srafan	lookup.mac = mac;
1535166124Srafan	lookup.esslen = ssid_len;
1536166124Srafan	lookup.essid = ssid;
1537166124Srafan	ieee80211_scan_iterate(vap, mlmelookup, &lookup);
1538166124Srafan	if (lookup.se == NULL)
1539166124Srafan		return ENOENT;
1540166124Srafan	mlmedebug(vap, mac, IEEE80211_MLME_ASSOC, 0);
1541166124Srafan	if (!ieee80211_sta_join(vap, lookup.se->se_chan, lookup.se))
1542166124Srafan		return EIO;		/* XXX unique but could be better */
1543166124Srafan	return 0;
1544166124Srafan}
1545166124Srafan
1546166124Srafanstatic __noinline int
1547166124Srafansetmlme_assoc_adhoc(struct ieee80211vap *vap,
1548166124Srafan	const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
1549166124Srafan	const uint8_t ssid[IEEE80211_NWID_LEN])
1550166124Srafan{
1551166124Srafan	struct ieee80211_scan_req sr;
1552166124Srafan
1553166124Srafan	KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
1554166124Srafan	    vap->iv_opmode == IEEE80211_M_AHDEMO,
1555166124Srafan	    ("expected opmode IBSS or AHDEMO not %s",
1556166124Srafan	    ieee80211_opmode_name[vap->iv_opmode]));
155750276Speter
1558166124Srafan	if (ssid_len == 0)
1559166124Srafan		return EINVAL;
156050276Speter
156150276Speter	/* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */
156250276Speter	memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
156350276Speter	vap->iv_des_ssid[0].len = ssid_len;
1564166124Srafan	memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len);
1565166124Srafan	vap->iv_des_nssid = 1;
1566166124Srafan
156750276Speter	memset(&sr, 0, sizeof(sr));
156856639Speter	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE;
156956639Speter	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
157056639Speter	memcpy(sr.sr_ssid[0].ssid, ssid, ssid_len);
157156639Speter	sr.sr_ssid[0].len = ssid_len;
1572166124Srafan	sr.sr_nssid = 1;
1573166124Srafan
1574166124Srafan	return ieee80211_scanreq(vap, &sr);
1575166124Srafan}
1576166124Srafan
1577166124Srafanstatic __noinline int
1578166124Srafanieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq)
1579166124Srafan{
1580166124Srafan	struct ieee80211req_mlme mlme;
1581166124Srafan	int error;
1582166124Srafan
1583166124Srafan	if (ireq->i_len != sizeof(mlme))
1584166124Srafan		return EINVAL;
1585166124Srafan	error = copyin(ireq->i_data, &mlme, sizeof(mlme));
1586166124Srafan	if (error)
1587166124Srafan		return error;
1588166124Srafan	if  (vap->iv_opmode == IEEE80211_M_STA &&
158956639Speter	    mlme.im_op == IEEE80211_MLME_ASSOC)
1590166124Srafan		return setmlme_assoc_sta(vap, mlme.im_macaddr,
1591166124Srafan		    vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid);
1592166124Srafan	else if ((vap->iv_opmode == IEEE80211_M_IBSS ||
1593166124Srafan	    vap->iv_opmode == IEEE80211_M_AHDEMO) &&
1594166124Srafan	    mlme.im_op == IEEE80211_MLME_ASSOC)
1595166124Srafan		return setmlme_assoc_adhoc(vap, mlme.im_macaddr,
1596166124Srafan		    mlme.im_ssid_len, mlme.im_ssid);
1597166124Srafan	else
1598166124Srafan		return setmlme_common(vap, mlme.im_op,
1599166124Srafan		    mlme.im_macaddr, mlme.im_reason);
1600166124Srafan}
1601166124Srafan
1602166124Srafanstatic __noinline int
1603166124Srafanieee80211_ioctl_macmac(struct ieee80211vap *vap, struct ieee80211req *ireq)
1604166124Srafan{
1605166124Srafan	uint8_t mac[IEEE80211_ADDR_LEN];
1606166124Srafan	const struct ieee80211_aclator *acl = vap->iv_acl;
1607166124Srafan	int error;
1608166124Srafan
1609166124Srafan	if (ireq->i_len != sizeof(mac))
161056639Speter		return EINVAL;
1611166124Srafan	error = copyin(ireq->i_data, mac, ireq->i_len);
1612166124Srafan	if (error)
161356639Speter		return error;
1614166124Srafan	if (acl == NULL) {
161556639Speter		acl = ieee80211_aclator_get("mac");
1616166124Srafan		if (acl == NULL || !acl->iac_attach(vap))
1617166124Srafan			return EINVAL;
1618166124Srafan		vap->iv_acl = acl;
1619166124Srafan	}
1620166124Srafan	if (ireq->i_type == IEEE80211_IOC_ADDMAC)
1621166124Srafan		acl->iac_add(vap, mac);
1622166124Srafan	else
162356639Speter		acl->iac_remove(vap, mac);
162462449Speter	return 0;
162562449Speter}
162662449Speter
162762449Speterstatic __noinline int
1628166124Srafanieee80211_ioctl_setmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq)
1629166124Srafan{
1630166124Srafan	const struct ieee80211_aclator *acl = vap->iv_acl;
1631166124Srafan
1632166124Srafan	switch (ireq->i_val) {
1633166124Srafan	case IEEE80211_MACCMD_POLICY_OPEN:
1634166124Srafan	case IEEE80211_MACCMD_POLICY_ALLOW:
1635166124Srafan	case IEEE80211_MACCMD_POLICY_DENY:
1636166124Srafan	case IEEE80211_MACCMD_POLICY_RADIUS:
1637166124Srafan		if (acl == NULL) {
1638166124Srafan			acl = ieee80211_aclator_get("mac");
1639166124Srafan			if (acl == NULL || !acl->iac_attach(vap))
1640166124Srafan				return EINVAL;
1641166124Srafan			vap->iv_acl = acl;
1642166124Srafan		}
1643166124Srafan		acl->iac_setpolicy(vap, ireq->i_val);
1644166124Srafan		break;
1645166124Srafan	case IEEE80211_MACCMD_FLUSH:
1646166124Srafan		if (acl != NULL)
164762449Speter			acl->iac_flush(vap);
164850276Speter		/* NB: silently ignore when not in use */
164950276Speter		break;
165050276Speter	case IEEE80211_MACCMD_DETACH:
165150276Speter		if (acl != NULL) {
165250276Speter			vap->iv_acl = NULL;
165350276Speter			acl->iac_detach(vap);
165450276Speter		}
165550276Speter		break;
165650276Speter	default:
165750276Speter		if (acl == NULL)
165850276Speter			return EINVAL;
165950276Speter		else
166050276Speter			return acl->iac_setioctl(vap, ireq);
166150276Speter	}
166250276Speter	return 0;
166350276Speter}
166450276Speter
166550276Speterstatic __noinline int
166650276Speterieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
166750276Speter{
166850276Speter	struct ieee80211com *ic = vap->iv_ic;
166950276Speter	uint8_t *chanlist, *list;
167050276Speter	int i, nchan, maxchan, error;
167198503Speter
167298503Speter	if (ireq->i_len > sizeof(ic->ic_chan_active))
167398503Speter		ireq->i_len = sizeof(ic->ic_chan_active);
167498503Speter	list = malloc(ireq->i_len + IEEE80211_CHAN_BYTES, M_TEMP,
167598503Speter	    M_NOWAIT | M_ZERO);
167698503Speter	if (list == NULL)
1677166124Srafan		return ENOMEM;
1678166124Srafan	error = copyin(ireq->i_data, list, ireq->i_len);
1679166124Srafan	if (error) {
1680166124Srafan		free(list, M_TEMP);
1681166124Srafan		return error;
1682166124Srafan	}
1683166124Srafan	nchan = 0;
1684166124Srafan	chanlist = list + ireq->i_len;		/* NB: zero'd already */
1685166124Srafan	maxchan = ireq->i_len * NBBY;
1686166124Srafan	for (i = 0; i < ic->ic_nchans; i++) {
1687166124Srafan		const struct ieee80211_channel *c = &ic->ic_channels[i];
1688166124Srafan		/*
1689166124Srafan		 * Calculate the intersection of the user list and the
1690166124Srafan		 * available channels so users can do things like specify
1691166124Srafan		 * 1-255 to get all available channels.
1692166124Srafan		 */
1693166124Srafan		if (c->ic_ieee < maxchan && isset(list, c->ic_ieee)) {
1694166124Srafan			setbit(chanlist, c->ic_ieee);
1695166124Srafan			nchan++;
1696166124Srafan		}
1697166124Srafan	}
1698166124Srafan	if (nchan == 0) {
1699166124Srafan		free(list, M_TEMP);
1700166124Srafan		return EINVAL;
1701166124Srafan	}
1702166124Srafan	if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&	/* XXX */
1703166124Srafan	    isclr(chanlist, ic->ic_bsschan->ic_ieee))
1704166124Srafan		ic->ic_bsschan = IEEE80211_CHAN_ANYC;
1705166124Srafan	memcpy(ic->ic_chan_active, chanlist, IEEE80211_CHAN_BYTES);
1706166124Srafan	ieee80211_scan_flush(vap);
1707166124Srafan	free(list, M_TEMP);
1708166124Srafan	return ENETRESET;
1709166124Srafan}
1710166124Srafan
1711166124Srafanstatic __noinline int
1712166124Srafanieee80211_ioctl_setstastats(struct ieee80211vap *vap, struct ieee80211req *ireq)
1713166124Srafan{
1714166124Srafan	struct ieee80211_node *ni;
1715166124Srafan	uint8_t macaddr[IEEE80211_ADDR_LEN];
1716166124Srafan	int error;
1717166124Srafan
1718166124Srafan	/*
1719166124Srafan	 * NB: we could copyin ieee80211req_sta_stats so apps
1720166124Srafan	 *     could make selective changes but that's overkill;
1721166124Srafan	 *     just clear all stats for now.
1722166124Srafan	 */
1723166124Srafan	if (ireq->i_len < IEEE80211_ADDR_LEN)
1724166124Srafan		return EINVAL;
1725166124Srafan	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1726166124Srafan	if (error != 0)
1727166124Srafan		return error;
1728166124Srafan	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
1729166124Srafan	if (ni == NULL)
1730166124Srafan		return ENOENT;
1731166124Srafan	/* XXX require ni_vap == vap? */
1732166124Srafan	memset(&ni->ni_stats, 0, sizeof(ni->ni_stats));
1733166124Srafan	ieee80211_free_node(ni);
1734166124Srafan	return 0;
1735166124Srafan}
1736166124Srafan
1737166124Srafanstatic __noinline int
1738166124Srafanieee80211_ioctl_setstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq)
1739166124Srafan{
1740166124Srafan	struct ieee80211_node *ni;
1741166124Srafan	struct ieee80211req_sta_txpow txpow;
1742166124Srafan	int error;
1743166124Srafan
1744166124Srafan	if (ireq->i_len != sizeof(txpow))
174550276Speter		return EINVAL;
1746166124Srafan	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1747166124Srafan	if (error != 0)
1748166124Srafan		return error;
1749166124Srafan	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, txpow.it_macaddr);
1750166124Srafan	if (ni == NULL)
1751166124Srafan		return ENOENT;
1752166124Srafan	ni->ni_txpower = txpow.it_txpow;
1753166124Srafan	ieee80211_free_node(ni);
1754166124Srafan	return error;
1755166124Srafan}
1756166124Srafan
1757166124Srafanstatic __noinline int
1758166124Srafanieee80211_ioctl_setwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq)
1759166124Srafan{
1760166124Srafan	struct ieee80211com *ic = vap->iv_ic;
1761166124Srafan	struct ieee80211_wme_state *wme = &ic->ic_wme;
176250276Speter	struct wmeParams *wmep, *chanp;
176350276Speter	int isbss, ac;
176450276Speter
176550276Speter	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1766166124Srafan		return EOPNOTSUPP;
176750276Speter
176850276Speter	isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
1769166124Srafan	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1770166124Srafan	if (ac >= WME_NUM_AC)
1771166124Srafan		ac = WME_AC_BE;
1772166124Srafan	if (isbss) {
1773166124Srafan		chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
1774166124Srafan		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1775166124Srafan	} else {
1776166124Srafan		chanp = &wme->wme_chanParams.cap_wmeParams[ac];
1777166124Srafan		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1778166124Srafan	}
177950276Speter	switch (ireq->i_type) {
178050276Speter	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1781166124Srafan		if (isbss) {
1782166124Srafan			wmep->wmep_logcwmin = ireq->i_val;
1783166124Srafan			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1784166124Srafan				chanp->wmep_logcwmin = ireq->i_val;
1785166124Srafan		} else {
1786166124Srafan			wmep->wmep_logcwmin = chanp->wmep_logcwmin =
1787166124Srafan				ireq->i_val;
178850276Speter		}
178950276Speter		break;
179050276Speter	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
179150276Speter		if (isbss) {
179250276Speter			wmep->wmep_logcwmax = ireq->i_val;
179350276Speter			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
179450276Speter				chanp->wmep_logcwmax = ireq->i_val;
1795166124Srafan		} else {
179650276Speter			wmep->wmep_logcwmax = chanp->wmep_logcwmax =
1797166124Srafan				ireq->i_val;
1798166124Srafan		}
1799166124Srafan		break;
180062449Speter	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1801166124Srafan		if (isbss) {
1802166124Srafan			wmep->wmep_aifsn = ireq->i_val;
180362449Speter			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1804166124Srafan				chanp->wmep_aifsn = ireq->i_val;
1805166124Srafan		} else {
1806166124Srafan			wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
1807166124Srafan		}
1808166124Srafan		break;
1809166124Srafan	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1810166124Srafan		if (isbss) {
1811166124Srafan			wmep->wmep_txopLimit = ireq->i_val;
1812166124Srafan			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1813166124Srafan				chanp->wmep_txopLimit = ireq->i_val;
1814166124Srafan		} else {
1815166124Srafan			wmep->wmep_txopLimit = chanp->wmep_txopLimit =
181650276Speter				ireq->i_val;
1817166124Srafan		}
1818166124Srafan		break;
1819166124Srafan	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1820166124Srafan		wmep->wmep_acm = ireq->i_val;
1821166124Srafan		if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
182250276Speter			chanp->wmep_acm = ireq->i_val;
1823166124Srafan		break;
1824166124Srafan	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
1825166124Srafan		wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
1826166124Srafan			(ireq->i_val) == 0;
1827166124Srafan		break;
1828166124Srafan	}
1829166124Srafan	ieee80211_wme_updateparams(vap);
1830166124Srafan	return 0;
183162449Speter}
183262449Speter
1833166124Srafanstatic int
1834166124Srafanfind11gchannel(struct ieee80211com *ic, int start, int freq)
1835166124Srafan{
1836166124Srafan	const struct ieee80211_channel *c;
1837166124Srafan	int i;
1838166124Srafan
1839166124Srafan	for (i = start+1; i < ic->ic_nchans; i++) {
1840166124Srafan		c = &ic->ic_channels[i];
1841166124Srafan		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
1842166124Srafan			return 1;
1843166124Srafan	}
1844166124Srafan	/* NB: should not be needed but in case things are mis-sorted */
1845166124Srafan	for (i = 0; i < start; i++) {
1846166124Srafan		c = &ic->ic_channels[i];
1847166124Srafan		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
1848166124Srafan			return 1;
1849166124Srafan	}
1850166124Srafan	return 0;
1851166124Srafan}
1852166124Srafan
1853166124Srafanstatic struct ieee80211_channel *
1854166124Srafanfindchannel(struct ieee80211com *ic, int ieee, int mode)
1855166124Srafan{
1856166124Srafan	static const u_int chanflags[IEEE80211_MODE_MAX] = {
185762449Speter	    [IEEE80211_MODE_AUTO]	= 0,
185850276Speter	    [IEEE80211_MODE_11A]	= IEEE80211_CHAN_A,
185950276Speter	    [IEEE80211_MODE_11B]	= IEEE80211_CHAN_B,
186062449Speter	    [IEEE80211_MODE_11G]	= IEEE80211_CHAN_G,
186162449Speter	    [IEEE80211_MODE_FH]		= IEEE80211_CHAN_FHSS,
186250276Speter	    [IEEE80211_MODE_TURBO_A]	= IEEE80211_CHAN_108A,
186350276Speter	    [IEEE80211_MODE_TURBO_G]	= IEEE80211_CHAN_108G,
186450276Speter	    [IEEE80211_MODE_STURBO_A]	= IEEE80211_CHAN_STURBO,
186550276Speter	    [IEEE80211_MODE_HALF]	= IEEE80211_CHAN_HALF,
186650276Speter	    [IEEE80211_MODE_QUARTER]	= IEEE80211_CHAN_QUARTER,
1867166124Srafan	    /* NB: handled specially below */
186850276Speter	    [IEEE80211_MODE_11NA]	= IEEE80211_CHAN_A,
186950276Speter	    [IEEE80211_MODE_11NG]	= IEEE80211_CHAN_G,
187050276Speter	};
187150276Speter	u_int modeflags;
187250276Speter	int i;
187350276Speter
187450276Speter	modeflags = chanflags[mode];
187550276Speter	for (i = 0; i < ic->ic_nchans; i++) {
187650276Speter		struct ieee80211_channel *c = &ic->ic_channels[i];
187750276Speter
187850276Speter		if (c->ic_ieee != ieee)
187950276Speter			continue;
188050276Speter		if (mode == IEEE80211_MODE_AUTO) {
188150276Speter			/* ignore turbo channels for autoselect */
188250276Speter			if (IEEE80211_IS_CHAN_TURBO(c))
188350276Speter				continue;
188450276Speter			/*
188550276Speter			 * XXX special-case 11b/g channels so we
188650276Speter			 *     always select the g channel if both
188750276Speter			 *     are present.
1888166124Srafan			 * XXX prefer HT to non-HT?
188950276Speter			 */
189050276Speter			if (!IEEE80211_IS_CHAN_B(c) ||
1891166124Srafan			    !find11gchannel(ic, i, c->ic_freq))
189250276Speter				return c;
1893166124Srafan		} else {
189450276Speter			/* must check HT specially */
189550276Speter			if ((mode == IEEE80211_MODE_11NA ||
1896166124Srafan			    mode == IEEE80211_MODE_11NG) &&
1897166124Srafan			    !IEEE80211_IS_CHAN_HT(c))
1898166124Srafan				continue;
1899166124Srafan			if ((c->ic_flags & modeflags) == modeflags)
190050276Speter				return c;
190150276Speter		}
190262449Speter	}
190362449Speter	return NULL;
190462449Speter}
190562449Speter
190662449Speter/*
190762449Speter * Check the specified against any desired mode (aka netband).
190862449Speter * This is only used (presently) when operating in hostap mode
190962449Speter * to enforce consistency.
191062449Speter */
191162449Speterstatic int
191262449Spetercheck_mode_consistency(const struct ieee80211_channel *c, int mode)
191362449Speter{
191462449Speter	KASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
191562449Speter
191662449Speter	switch (mode) {
191762449Speter	case IEEE80211_MODE_11B:
191862449Speter		return (IEEE80211_IS_CHAN_B(c));
191962449Speter	case IEEE80211_MODE_11G:
192062449Speter		return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
192162449Speter	case IEEE80211_MODE_11A:
192262449Speter		return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
1923166124Srafan	case IEEE80211_MODE_STURBO_A:
192462449Speter		return (IEEE80211_IS_CHAN_STURBO(c));
192562449Speter	case IEEE80211_MODE_11NA:
192662449Speter		return (IEEE80211_IS_CHAN_HTA(c));
192762449Speter	case IEEE80211_MODE_11NG:
192862449Speter		return (IEEE80211_IS_CHAN_HTG(c));
192962449Speter	}
193062449Speter	return 1;
193162449Speter
193262449Speter}
193362449Speter
193462449Speter/*
193562449Speter * Common code to set the current channel.  If the device
193662449Speter * is up and running this may result in an immediate channel
193762449Speter * change or a kick of the state machine.
193862449Speter */
193962449Speterstatic int
194062449Spetersetcurchan(struct ieee80211vap *vap, struct ieee80211_channel *c)
194150276Speter{
194250276Speter	struct ieee80211com *ic = vap->iv_ic;
194350276Speter	int error;
194450276Speter
194550276Speter	if (c != IEEE80211_CHAN_ANYC) {
194650276Speter		if (IEEE80211_IS_CHAN_RADAR(c))
194750276Speter			return EBUSY;	/* XXX better code? */
194850276Speter		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
194950276Speter			if (IEEE80211_IS_CHAN_NOHOSTAP(c))
195050276Speter				return EINVAL;
195150276Speter			if (!check_mode_consistency(c, vap->iv_des_mode))
195250276Speter				return EINVAL;
195350276Speter		} else if (vap->iv_opmode == IEEE80211_M_IBSS) {
195450276Speter			if (IEEE80211_IS_CHAN_NOADHOC(c))
195550276Speter				return EINVAL;
195650276Speter		}
195750276Speter		if (vap->iv_state == IEEE80211_S_RUN &&
195850276Speter		    vap->iv_bss->ni_chan == c)
195950276Speter			return 0;	/* NB: nothing to do */
196050276Speter	}
196150276Speter	vap->iv_des_chan = c;
196250276Speter
196350276Speter	error = 0;
196450276Speter	if (vap->iv_opmode == IEEE80211_M_MONITOR &&
1965166124Srafan	    vap->iv_des_chan != IEEE80211_CHAN_ANYC) {
1966166124Srafan		/*
1967166124Srafan		 * Monitor mode can switch directly.
1968166124Srafan		 */
1969166124Srafan		if (IFNET_IS_UP_RUNNING(vap->iv_ifp)) {
1970166124Srafan			/* XXX need state machine for other vap's to follow */
1971166124Srafan			ieee80211_setcurchan(ic, vap->iv_des_chan);
1972166124Srafan			vap->iv_bss->ni_chan = ic->ic_curchan;
1973166124Srafan		} else
1974166124Srafan			ic->ic_curchan = vap->iv_des_chan;
1975166124Srafan			ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
1976166124Srafan	} else {
1977166124Srafan		/*
1978166124Srafan		 * Need to go through the state machine in case we
1979166124Srafan		 * need to reassociate or the like.  The state machine
1980166124Srafan		 * will pickup the desired channel and avoid scanning.
1981166124Srafan		 */
1982166124Srafan		if (IS_UP_AUTO(vap))
1983166124Srafan			ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
1984166124Srafan		else if (vap->iv_des_chan != IEEE80211_CHAN_ANYC) {
1985166124Srafan			/*
1986166124Srafan			 * When not up+running and a real channel has
1987166124Srafan			 * been specified fix the current channel so
1988166124Srafan			 * there is immediate feedback; e.g. via ifconfig.
1989166124Srafan			 */
1990166124Srafan			ic->ic_curchan = vap->iv_des_chan;
1991166124Srafan			ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
1992166124Srafan		}
1993166124Srafan	}
1994166124Srafan	return error;
1995166124Srafan}
1996166124Srafan
1997166124Srafan/*
1998166124Srafan * Old api for setting the current channel; this is
1999166124Srafan * deprecated because channel numbers are ambiguous.
2000166124Srafan */
2001166124Srafanstatic __noinline int
2002166124Srafanieee80211_ioctl_setchannel(struct ieee80211vap *vap,
2003166124Srafan	const struct ieee80211req *ireq)
2004166124Srafan{
2005166124Srafan	struct ieee80211com *ic = vap->iv_ic;
2006166124Srafan	struct ieee80211_channel *c;
2007166124Srafan
2008166124Srafan	/* XXX 0xffff overflows 16-bit signed */
200950276Speter	if (ireq->i_val == 0 ||
201050276Speter	    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
2011166124Srafan		c = IEEE80211_CHAN_ANYC;
201250276Speter	} else {
201350276Speter		struct ieee80211_channel *c2;
201450276Speter
201550276Speter		c = findchannel(ic, ireq->i_val, vap->iv_des_mode);
201650276Speter		if (c == NULL) {
201750276Speter			c = findchannel(ic, ireq->i_val,
201850276Speter				IEEE80211_MODE_AUTO);
201950276Speter			if (c == NULL)
202050276Speter				return EINVAL;
202150276Speter		}
202250276Speter		/*
202350276Speter		 * Fine tune channel selection based on desired mode:
202450276Speter		 *   if 11b is requested, find the 11b version of any
202550276Speter		 *      11g channel returned,
202650276Speter		 *   if static turbo, find the turbo version of any
202750276Speter		 *	11a channel return,
202850276Speter		 *   if 11na is requested, find the ht version of any
202950276Speter		 *      11a channel returned,
203050276Speter		 *   if 11ng is requested, find the ht version of any
203150276Speter		 *      11g channel returned,
203250276Speter		 *   otherwise we should be ok with what we've got.
203350276Speter		 */
203450276Speter		switch (vap->iv_des_mode) {
203550276Speter		case IEEE80211_MODE_11B:
203650276Speter			if (IEEE80211_IS_CHAN_ANYG(c)) {
203750276Speter				c2 = findchannel(ic, ireq->i_val,
203850276Speter					IEEE80211_MODE_11B);
203950276Speter				/* NB: should not happen, =>'s 11g w/o 11b */
204050276Speter				if (c2 != NULL)
204150276Speter					c = c2;
204250276Speter			}
2043166124Srafan			break;
2044166124Srafan		case IEEE80211_MODE_TURBO_A:
2045166124Srafan			if (IEEE80211_IS_CHAN_A(c)) {
2046166124Srafan				c2 = findchannel(ic, ireq->i_val,
2047166124Srafan					IEEE80211_MODE_TURBO_A);
2048166124Srafan				if (c2 != NULL)
2049166124Srafan					c = c2;
2050166124Srafan			}
2051166124Srafan			break;
2052166124Srafan		case IEEE80211_MODE_11NA:
2053166124Srafan			if (IEEE80211_IS_CHAN_A(c)) {
2054166124Srafan				c2 = findchannel(ic, ireq->i_val,
2055166124Srafan					IEEE80211_MODE_11NA);
2056166124Srafan				if (c2 != NULL)
2057166124Srafan					c = c2;
2058166124Srafan			}
2059166124Srafan			break;
2060166124Srafan		case IEEE80211_MODE_11NG:
2061166124Srafan			if (IEEE80211_IS_CHAN_ANYG(c)) {
2062166124Srafan				c2 = findchannel(ic, ireq->i_val,
2063166124Srafan					IEEE80211_MODE_11NG);
2064166124Srafan				if (c2 != NULL)
2065166124Srafan					c = c2;
2066166124Srafan			}
206750276Speter			break;
206850276Speter		default:		/* NB: no static turboG */
2069166124Srafan			break;
2070166124Srafan		}
2071166124Srafan	}
2072166124Srafan	return setcurchan(vap, c);
2073166124Srafan}
2074166124Srafan
207550276Speter/*
207650276Speter * New/current api for setting the current channel; a complete
2077166124Srafan * channel description is provide so there is no ambiguity in
2078166124Srafan * identifying the channel.
2079166124Srafan */
2080166124Srafanstatic __noinline int
2081166124Srafanieee80211_ioctl_setcurchan(struct ieee80211vap *vap,
2082166124Srafan	const struct ieee80211req *ireq)
208350276Speter{
208450276Speter	struct ieee80211com *ic = vap->iv_ic;
208550276Speter	struct ieee80211_channel chan, *c;
2086166124Srafan	int error;
2087166124Srafan
2088166124Srafan	if (ireq->i_len != sizeof(chan))
2089166124Srafan		return EINVAL;
2090166124Srafan	error = copyin(ireq->i_data, &chan, sizeof(chan));
2091166124Srafan	if (error != 0)
2092166124Srafan		return error;
209350276Speter	/* XXX 0xffff overflows 16-bit signed */
2094166124Srafan	if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
209550276Speter		c = IEEE80211_CHAN_ANYC;
2096166124Srafan	} else {
2097166124Srafan		c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
2098166124Srafan		if (c == NULL)
2099166124Srafan			return EINVAL;
2100166124Srafan	}
210150276Speter	return setcurchan(vap, c);
210250276Speter}
210350276Speter
2104166124Srafanstatic __noinline int
2105166124Srafanieee80211_ioctl_setregdomain(struct ieee80211vap *vap,
2106166124Srafan	const struct ieee80211req *ireq)
2107166124Srafan{
2108166124Srafan	struct ieee80211_regdomain_req *reg;
2109166124Srafan	int nchans, error;
2110166124Srafan
211150276Speter	nchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_regdomain_req)) /
211250276Speter	    sizeof(struct ieee80211_channel));
211350276Speter	if (!(1 <= nchans && nchans <= IEEE80211_CHAN_MAX)) {
211450276Speter		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
211550276Speter		    "%s: bad # chans, i_len %d nchans %d\n", __func__,
211650276Speter		    ireq->i_len, nchans);
2117166124Srafan		return EINVAL;
211850276Speter	}
211950276Speter	reg = (struct ieee80211_regdomain_req *)
2120166124Srafan	    malloc(IEEE80211_REGDOMAIN_SIZE(nchans), M_TEMP, M_NOWAIT);
2121166124Srafan	if (reg == NULL) {
212250276Speter		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
212350276Speter		    "%s: no memory, nchans %d\n", __func__, nchans);
2124166124Srafan		return ENOMEM;
2125166124Srafan	}
2126166124Srafan	error = copyin(ireq->i_data, reg, IEEE80211_REGDOMAIN_SIZE(nchans));
2127166124Srafan	if (error == 0) {
212850276Speter		/* NB: validate inline channel count against storage size */
212950276Speter		if (reg->chaninfo.ic_nchans != nchans) {
213050276Speter			IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
2131166124Srafan			    "%s: chan cnt mismatch, %d != %d\n", __func__,
2132166124Srafan				reg->chaninfo.ic_nchans, nchans);
2133166124Srafan			error = EINVAL;
2134166124Srafan		} else
2135166124Srafan			error = ieee80211_setregdomain(vap, reg);
2136166124Srafan	}
2137166124Srafan	free(reg, M_TEMP);
2138166124Srafan
2139166124Srafan	return (error == 0 ? ENETRESET : error);
2140166124Srafan}
2141166124Srafan
2142166124Srafanstatic int
2143166124Srafanieee80211_ioctl_setroam(struct ieee80211vap *vap,
2144166124Srafan	const struct ieee80211req *ireq)
2145166124Srafan{
2146166124Srafan	if (ireq->i_len != sizeof(vap->iv_roamparms))
214750276Speter		return EINVAL;
214850276Speter	/* XXX validate params */
214950276Speter	/* XXX? ENETRESET to push to device? */
2150166124Srafan	return copyin(ireq->i_data, vap->iv_roamparms,
2151166124Srafan	    sizeof(vap->iv_roamparms));
215250276Speter}
215350276Speter
2154166124Srafanstatic int
2155166124Srafancheckrate(const struct ieee80211_rateset *rs, int rate)
2156166124Srafan{
2157166124Srafan	int i;
215850276Speter
215950276Speter	if (rate == IEEE80211_FIXED_RATE_NONE)
216050276Speter		return 1;
216150276Speter	for (i = 0; i < rs->rs_nrates; i++)
216250276Speter		if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
216350276Speter			return 1;
2164166124Srafan	return 0;
2165166124Srafan}
2166166124Srafan
2167166124Srafanstatic int
2168166124Srafancheckmcs(int mcs)
2169166124Srafan{
2170166124Srafan	if (mcs == IEEE80211_FIXED_RATE_NONE)
2171166124Srafan		return 1;
2172166124Srafan	if ((mcs & IEEE80211_RATE_MCS) == 0)	/* MCS always have 0x80 set */
2173166124Srafan		return 0;
2174166124Srafan	return (mcs & 0x7f) <= 15;	/* XXX could search ht rate set */
2175166124Srafan}
2176166124Srafan
2177166124Srafanstatic __noinline int
2178166124Srafanieee80211_ioctl_settxparams(struct ieee80211vap *vap,
2179166124Srafan	const struct ieee80211req *ireq)
2180166124Srafan{
2181166124Srafan	struct ieee80211com *ic = vap->iv_ic;
2182166124Srafan	struct ieee80211_txparams_req parms;	/* XXX stack use? */
2183166124Srafan	struct ieee80211_txparam *src, *dst;
2184166124Srafan	const struct ieee80211_rateset *rs;
2185166124Srafan	int error, mode, changed, is11n, nmodes;
2186166124Srafan
218750276Speter	/* NB: accept short requests for backwards compat */
218862449Speter	if (ireq->i_len > sizeof(parms))
218962449Speter		return EINVAL;
219062449Speter	error = copyin(ireq->i_data, &parms, ireq->i_len);
2191166124Srafan	if (error != 0)
2192166124Srafan		return error;
2193166124Srafan	nmodes = ireq->i_len / sizeof(struct ieee80211_txparam);
2194166124Srafan	changed = 0;
2195166124Srafan	/* validate parameters and check if anything changed */
2196166124Srafan	for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) {
2197166124Srafan		if (isclr(ic->ic_modecaps, mode))
2198166124Srafan			continue;
2199166124Srafan		src = &parms.params[mode];
2200166124Srafan		dst = &vap->iv_txparms[mode];
2201166124Srafan		rs = &ic->ic_sup_rates[mode];	/* NB: 11n maps to legacy */
2202166124Srafan		is11n = (mode == IEEE80211_MODE_11NA ||
2203166124Srafan			 mode == IEEE80211_MODE_11NG);
2204166124Srafan		if (src->ucastrate != dst->ucastrate) {
2205166124Srafan			if (!checkrate(rs, src->ucastrate) &&
2206166124Srafan			    (!is11n || !checkmcs(src->ucastrate)))
2207166124Srafan				return EINVAL;
2208166124Srafan			changed++;
2209166124Srafan		}
2210166124Srafan		if (src->mcastrate != dst->mcastrate) {
2211166124Srafan			if (!checkrate(rs, src->mcastrate) &&
2212166124Srafan			    (!is11n || !checkmcs(src->mcastrate)))
2213166124Srafan				return EINVAL;
2214166124Srafan			changed++;
2215166124Srafan		}
2216166124Srafan		if (src->mgmtrate != dst->mgmtrate) {
2217166124Srafan			if (!checkrate(rs, src->mgmtrate) &&
2218166124Srafan			    (!is11n || !checkmcs(src->mgmtrate)))
2219166124Srafan				return EINVAL;
2220166124Srafan			changed++;
2221166124Srafan		}
2222166124Srafan		if (src->maxretry != dst->maxretry)	/* NB: no bounds */
2223166124Srafan			changed++;
2224166124Srafan	}
2225166124Srafan	if (changed) {
2226166124Srafan		/*
2227166124Srafan		 * Copy new parameters in place and notify the
2228166124Srafan		 * driver so it can push state to the device.
2229166124Srafan		 */
2230166124Srafan		for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) {
2231166124Srafan			if (isset(ic->ic_modecaps, mode))
2232166124Srafan				vap->iv_txparms[mode] = parms.params[mode];
2233166124Srafan		}
2234166124Srafan		/* XXX could be more intelligent,
2235166124Srafan		   e.g. don't reset if setting not being used */
2236166124Srafan		return ENETRESET;
2237166124Srafan	}
2238166124Srafan	return 0;
2239166124Srafan}
2240166124Srafan
2241166124Srafan/*
2242166124Srafan * Application Information Element support.
2243166124Srafan */
2244166124Srafanstatic int
2245166124Srafansetappie(struct ieee80211_appie **aie, const struct ieee80211req *ireq)
2246166124Srafan{
2247166124Srafan	struct ieee80211_appie *app = *aie;
2248166124Srafan	struct ieee80211_appie *napp;
224950276Speter	int error;
225062449Speter
225162449Speter	if (ireq->i_len == 0) {		/* delete any existing ie */
225262449Speter		if (app != NULL) {
225362449Speter			*aie = NULL;	/* XXX racey */
225462449Speter			free(app, M_80211_NODE_IE);
2255166124Srafan		}
225662449Speter		return 0;
2257166124Srafan	}
2258166124Srafan	if (!(2 <= ireq->i_len && ireq->i_len <= IEEE80211_MAX_APPIE))
2259166124Srafan		return EINVAL;
2260166124Srafan	/*
2261166124Srafan	 * Allocate a new appie structure and copy in the user data.
226262449Speter	 * When done swap in the new structure.  Note that we do not
2263166124Srafan	 * guard against users holding a ref to the old structure;
2264166124Srafan	 * this must be handled outside this code.
2265166124Srafan	 *
226662449Speter	 * XXX bad bad bad
226750276Speter	 */
226850276Speter	napp = (struct ieee80211_appie *) malloc(
226950276Speter	    sizeof(struct ieee80211_appie) + ireq->i_len, M_80211_NODE_IE, M_NOWAIT);
227050276Speter	if (napp == NULL)
227150276Speter		return ENOMEM;
227250276Speter	/* XXX holding ic lock */
227350276Speter	error = copyin(ireq->i_data, napp->ie_data, ireq->i_len);
227450276Speter	if (error) {
227550276Speter		free(napp, M_80211_NODE_IE);
227650276Speter		return error;
227750276Speter	}
227850276Speter	napp->ie_len = ireq->i_len;
227950276Speter	*aie = napp;
228050276Speter	if (app != NULL)
228162449Speter		free(app, M_80211_NODE_IE);
2282166124Srafan	return 0;
2283166124Srafan}
2284166124Srafan
2285166124Srafanstatic void
2286166124Srafansetwparsnie(struct ieee80211vap *vap, uint8_t *ie, int space)
2287166124Srafan{
2288166124Srafan	/* validate data is present as best we can */
2289166124Srafan	if (space == 0 || 2+ie[1] > space)
2290166124Srafan		return;
2291166124Srafan	if (ie[0] == IEEE80211_ELEMID_VENDOR)
2292166124Srafan		vap->iv_wpa_ie = ie;
2293166124Srafan	else if (ie[0] == IEEE80211_ELEMID_RSN)
2294166124Srafan		vap->iv_rsn_ie = ie;
2295166124Srafan}
2296166124Srafan
2297166124Srafanstatic __noinline int
229850276Speterieee80211_ioctl_setappie_locked(struct ieee80211vap *vap,
229950276Speter	const struct ieee80211req *ireq, int fc0)
230050276Speter{
230150276Speter	int error;
230250276Speter
2303166124Srafan	IEEE80211_LOCK_ASSERT(vap->iv_ic);
2304166124Srafan
2305166124Srafan	switch (fc0 & IEEE80211_FC0_SUBTYPE_MASK) {
230650276Speter	case IEEE80211_FC0_SUBTYPE_BEACON:
2307166124Srafan		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
230850276Speter		    vap->iv_opmode != IEEE80211_M_IBSS) {
2309166124Srafan			error = EINVAL;
231050276Speter			break;
231150276Speter		}
231250276Speter		error = setappie(&vap->iv_appie_beacon, ireq);
231350276Speter		if (error == 0)
231450276Speter			ieee80211_beacon_notify(vap, IEEE80211_BEACON_APPIE);
231550276Speter		break;
231650276Speter	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
231750276Speter		error = setappie(&vap->iv_appie_proberesp, ireq);
231862449Speter		break;
2319166124Srafan	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
2320166124Srafan		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2321166124Srafan			error = setappie(&vap->iv_appie_assocresp, ireq);
2322166124Srafan		else
2323166124Srafan			error = EINVAL;
2324166124Srafan		break;
2325166124Srafan	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
2326166124Srafan		error = setappie(&vap->iv_appie_probereq, ireq);
2327166124Srafan		break;
2328166124Srafan	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
2329166124Srafan		if (vap->iv_opmode == IEEE80211_M_STA)
2330166124Srafan			error = setappie(&vap->iv_appie_assocreq, ireq);
2331166124Srafan		else
2332166124Srafan			error = EINVAL;
2333166124Srafan		break;
2334166124Srafan	case (IEEE80211_APPIE_WPA & IEEE80211_FC0_SUBTYPE_MASK):
2335166124Srafan		error = setappie(&vap->iv_appie_wpa, ireq);
2336166124Srafan		if (error == 0) {
2337166124Srafan			/*
2338166124Srafan			 * Must split single blob of data into separate
2339166124Srafan			 * WPA and RSN ie's because they go in different
2340166124Srafan			 * locations in the mgt frames.
2341166124Srafan			 * XXX use IEEE80211_IOC_WPA2 so user code does split
2342166124Srafan			 */
2343166124Srafan			vap->iv_wpa_ie = NULL;
2344166124Srafan			vap->iv_rsn_ie = NULL;
2345166124Srafan			if (vap->iv_appie_wpa != NULL) {
2346166124Srafan				struct ieee80211_appie *appie =
2347166124Srafan				    vap->iv_appie_wpa;
2348166124Srafan				uint8_t *data = appie->ie_data;
2349166124Srafan
2350166124Srafan				/* XXX ie length validate is painful, cheat */
2351166124Srafan				setwparsnie(vap, data, appie->ie_len);
2352166124Srafan				setwparsnie(vap, data + 2 + data[1],
2353166124Srafan				    appie->ie_len - (2 + data[1]));
2354166124Srafan			}
2355166124Srafan			if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
235650276Speter			    vap->iv_opmode == IEEE80211_M_IBSS) {
2357166124Srafan				/*
2358166124Srafan				 * Must rebuild beacon frame as the update
2359166124Srafan				 * mechanism doesn't handle WPA/RSN ie's.
2360166124Srafan				 * Could extend it but it doesn't normally
2361166124Srafan				 * change; this is just to deal with hostapd
2362166124Srafan				 * plumbing the ie after the interface is up.
2363166124Srafan				 */
2364166124Srafan				error = ENETRESET;
2365166124Srafan			}
2366166124Srafan		}
236750276Speter		break;
236850276Speter	default:
236950276Speter		error = EINVAL;
237050276Speter		break;
237150276Speter	}
237250276Speter	return error;
237350276Speter}
237450276Speter
237550276Speterstatic __noinline int
237650276Speterieee80211_ioctl_setappie(struct ieee80211vap *vap,
237750276Speter	const struct ieee80211req *ireq)
237850276Speter{
237950276Speter	struct ieee80211com *ic = vap->iv_ic;
238050276Speter	int error;
238150276Speter	uint8_t fc0;
2382166124Srafan
238350276Speter	fc0 = ireq->i_val & 0xff;
238450276Speter	if ((fc0 & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
238550276Speter		return EINVAL;
238650276Speter	/* NB: could check iv_opmode and reject but hardly worth the effort */
238750276Speter	IEEE80211_LOCK(ic);
2388166124Srafan	error = ieee80211_ioctl_setappie_locked(vap, ireq, fc0);
2389166124Srafan	IEEE80211_UNLOCK(ic);
2390166124Srafan	return error;
2391166124Srafan}
2392166124Srafan
2393166124Srafanstatic __noinline int
2394166124Srafanieee80211_ioctl_chanswitch(struct ieee80211vap *vap, struct ieee80211req *ireq)
2395166124Srafan{
2396166124Srafan	struct ieee80211com *ic = vap->iv_ic;
2397166124Srafan	struct ieee80211_chanswitch_req csr;
2398166124Srafan	struct ieee80211_channel *c;
2399166124Srafan	int error;
2400166124Srafan
2401166124Srafan	if (ireq->i_len != sizeof(csr))
2402166124Srafan		return EINVAL;
2403166124Srafan	error = copyin(ireq->i_data, &csr, sizeof(csr));
2404166124Srafan	if (error != 0)
2405166124Srafan		return error;
2406166124Srafan	/* XXX adhoc mode not supported */
2407166124Srafan	if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
2408166124Srafan	    (vap->iv_flags & IEEE80211_F_DOTH) == 0)
2409166124Srafan		return EOPNOTSUPP;
2410166124Srafan	c = ieee80211_find_channel(ic,
2411166124Srafan	    csr.csa_chan.ic_freq, csr.csa_chan.ic_flags);
2412166124Srafan	if (c == NULL)
241350276Speter		return ENOENT;
241450276Speter	IEEE80211_LOCK(ic);
241550276Speter	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0)
2416166124Srafan		ieee80211_csa_startswitch(ic, c, csr.csa_mode, csr.csa_count);
2417166124Srafan	else if (csr.csa_count == 0)
241850276Speter		ieee80211_csa_cancelswitch(ic);
241950276Speter	else
242050276Speter		error = EBUSY;
242150276Speter	IEEE80211_UNLOCK(ic);
242250276Speter	return error;
242350276Speter}
242450276Speter
242550276Speterstatic int
242650276Speterieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr)
242750276Speter{
242850276Speter#define	IEEE80211_IOC_SCAN_FLAGS \
2429166124Srafan	(IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ACTIVE | \
243050276Speter	 IEEE80211_IOC_SCAN_PICK1ST | IEEE80211_IOC_SCAN_BGSCAN | \
243150276Speter	 IEEE80211_IOC_SCAN_ONCE | IEEE80211_IOC_SCAN_NOBCAST | \
243250276Speter	 IEEE80211_IOC_SCAN_NOJOIN | IEEE80211_IOC_SCAN_FLUSH | \
243350276Speter	 IEEE80211_IOC_SCAN_CHECK)
243450276Speter	struct ieee80211com *ic = vap->iv_ic;
2435166124Srafan	int error, i;
2436166124Srafan
2437166124Srafan	/* convert duration */
2438166124Srafan	if (sr->sr_duration == IEEE80211_IOC_SCAN_FOREVER)
2439166124Srafan		sr->sr_duration = IEEE80211_SCAN_FOREVER;
2440166124Srafan	else {
2441166124Srafan		if (sr->sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN ||
2442166124Srafan		    sr->sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX)
2443166124Srafan			return EINVAL;
2444166124Srafan		sr->sr_duration = msecs_to_ticks(sr->sr_duration);
2445166124Srafan		if (sr->sr_duration < 1)
2446166124Srafan			sr->sr_duration = 1;
2447166124Srafan	}
2448166124Srafan	/* convert min/max channel dwell */
2449166124Srafan	if (sr->sr_mindwell != 0) {
2450166124Srafan		sr->sr_mindwell = msecs_to_ticks(sr->sr_mindwell);
2451166124Srafan		if (sr->sr_mindwell < 1)
2452166124Srafan			sr->sr_mindwell = 1;
2453166124Srafan	}
2454166124Srafan	if (sr->sr_maxdwell != 0) {
2455166124Srafan		sr->sr_maxdwell = msecs_to_ticks(sr->sr_maxdwell);
2456166124Srafan		if (sr->sr_maxdwell < 1)
2457166124Srafan			sr->sr_maxdwell = 1;
2458166124Srafan	}
2459166124Srafan	/* NB: silently reduce ssid count to what is supported */
2460166124Srafan	if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID)
246150276Speter		sr->sr_nssid = IEEE80211_SCAN_MAX_SSID;
246250276Speter	for (i = 0; i < sr->sr_nssid; i++)
246350276Speter		if (sr->sr_ssid[i].len > IEEE80211_NWID_LEN)
2464166124Srafan			return EINVAL;
2465166124Srafan	/* cleanse flags just in case, could reject if invalid flags */
2466166124Srafan	sr->sr_flags &= IEEE80211_IOC_SCAN_FLAGS;
2467166124Srafan	/*
2468166124Srafan	 * Add an implicit NOPICK if the vap is not marked UP.  This
2469166124Srafan	 * allows applications to scan without joining a bss (or picking
2470166124Srafan	 * a channel and setting up a bss) and without forcing manual
2471166124Srafan	 * roaming mode--you just need to mark the parent device UP.
2472166124Srafan	 */
2473166124Srafan	if ((vap->iv_ifp->if_flags & IFF_UP) == 0)
2474166124Srafan		sr->sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
2475166124Srafan
2476166124Srafan	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
2477166124Srafan	    "%s: flags 0x%x%s duration 0x%x mindwell %u maxdwell %u nssid %d\n",
2478166124Srafan	    __func__, sr->sr_flags,
2479166124Srafan	    (vap->iv_ifp->if_flags & IFF_UP) == 0 ? " (!IFF_UP)" : "",
2480166124Srafan	    sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, sr->sr_nssid);
2481166124Srafan	/*
2482166124Srafan	 * If we are in INIT state then the driver has never had a chance
2483166124Srafan	 * to setup hardware state to do a scan; we must use the state
2484166124Srafan	 * machine to get us up to the SCAN state but once we reach SCAN
2485166124Srafan	 * state we then want to use the supplied params.  Stash the
2486166124Srafan	 * parameters in the vap and mark IEEE80211_FEXT_SCANREQ; the
248750276Speter	 * state machines will recognize this and use the stashed params
248850276Speter	 * to issue the scan request.
248950276Speter	 *
249050276Speter	 * Otherwise just invoke the scan machinery directly.
249150276Speter	 */
249250276Speter	IEEE80211_LOCK(ic);
249350276Speter	if (vap->iv_state == IEEE80211_S_INIT) {
2494166124Srafan		/* NB: clobbers previous settings */
249550276Speter		vap->iv_scanreq_flags = sr->sr_flags;
249650276Speter		vap->iv_scanreq_duration = sr->sr_duration;
249750276Speter		vap->iv_scanreq_nssid = sr->sr_nssid;
249850276Speter		for (i = 0; i < sr->sr_nssid; i++) {
249950276Speter			vap->iv_scanreq_ssid[i].len = sr->sr_ssid[i].len;
2500166124Srafan			memcpy(vap->iv_scanreq_ssid[i].ssid,
250150276Speter			    sr->sr_ssid[i].ssid, sr->sr_ssid[i].len);
250250276Speter		}
250350276Speter		vap->iv_flags_ext |= IEEE80211_FEXT_SCANREQ;
2504166124Srafan		IEEE80211_UNLOCK(ic);
2505166124Srafan		ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
2506166124Srafan	} else {
2507166124Srafan		vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
2508166124Srafan		IEEE80211_UNLOCK(ic);
2509166124Srafan		if (sr->sr_flags & IEEE80211_IOC_SCAN_CHECK) {
2510166124Srafan			error = ieee80211_check_scan(vap, sr->sr_flags,
2511166124Srafan			    sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
2512166124Srafan			    sr->sr_nssid,
2513166124Srafan			    /* NB: cheat, we assume structures are compatible */
2514166124Srafan			    (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]);
2515166124Srafan		} else {
2516166124Srafan			error = ieee80211_start_scan(vap, sr->sr_flags,
2517166124Srafan			    sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
2518166124Srafan			    sr->sr_nssid,
2519166124Srafan			    /* NB: cheat, we assume structures are compatible */
2520166124Srafan			    (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]);
2521166124Srafan		}
252250276Speter		if (error == 0)
2523166124Srafan			return EINPROGRESS;
2524166124Srafan	}
2525166124Srafan	return 0;
2526166124Srafan#undef IEEE80211_IOC_SCAN_FLAGS
2527166124Srafan}
2528166124Srafan
252950276Speterstatic __noinline int
2530166124Srafanieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
2531166124Srafan{
2532166124Srafan	struct ieee80211com *ic = vap->iv_ic;
2533166124Srafan	struct ieee80211_scan_req sr;		/* XXX off stack? */
2534166124Srafan	int error;
2535166124Srafan
2536166124Srafan	/* NB: parent must be running */
2537166124Srafan	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
253850276Speter		return ENXIO;
2539166124Srafan
2540166124Srafan	if (ireq->i_len != sizeof(sr))
2541166124Srafan		return EINVAL;
2542166124Srafan	error = copyin(ireq->i_data, &sr, sizeof(sr));
2543166124Srafan	if (error != 0)
2544166124Srafan		return error;
254550276Speter	return ieee80211_scanreq(vap, &sr);
254650276Speter}
254750276Speter
254850276Speterstatic __noinline int
254950276Speterieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
255050276Speter{
255150276Speter	struct ieee80211_node *ni;
255250276Speter	struct ieee80211req_sta_vlan vlan;
255350276Speter	int error;
255450276Speter
255550276Speter	if (ireq->i_len != sizeof(vlan))
255650276Speter		return EINVAL;
255750276Speter	error = copyin(ireq->i_data, &vlan, sizeof(vlan));
255850276Speter	if (error != 0)
255950276Speter		return error;
2560166124Srafan	if (!IEEE80211_ADDR_EQ(vlan.sv_macaddr, zerobssid)) {
2561166124Srafan		ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
2562166124Srafan		    vlan.sv_macaddr);
2563166124Srafan		if (ni == NULL)
2564166124Srafan			return ENOENT;
2565166124Srafan	} else
2566166124Srafan		ni = ieee80211_ref_node(vap->iv_bss);
2567166124Srafan	ni->ni_vlan = vlan.sv_vlan;
2568166124Srafan	ieee80211_free_node(ni);
2569166124Srafan	return error;
2570166124Srafan}
2571166124Srafan
2572166124Srafanstatic int
2573166124Srafanisvap11g(const struct ieee80211vap *vap)
2574166124Srafan{
2575166124Srafan	const struct ieee80211_node *bss = vap->iv_bss;
2576166124Srafan	return bss->ni_chan != IEEE80211_CHAN_ANYC &&
2577166124Srafan	    IEEE80211_IS_CHAN_ANYG(bss->ni_chan);
2578166124Srafan}
2579166124Srafan
2580166124Srafanstatic int
2581166124Srafanisvapht(const struct ieee80211vap *vap)
2582166124Srafan{
2583166124Srafan	const struct ieee80211_node *bss = vap->iv_bss;
258450276Speter	return bss->ni_chan != IEEE80211_CHAN_ANYC &&
258550276Speter	    IEEE80211_IS_CHAN_HT(bss->ni_chan);
258650276Speter}
2587166124Srafan
2588166124Srafan/*
2589166124Srafan * Dummy ioctl set handler so the linker set is defined.
2590166124Srafan */
2591166124Srafanstatic int
2592166124Srafandummy_ioctl_set(struct ieee80211vap *vap, struct ieee80211req *ireq)
2593166124Srafan{
2594166124Srafan	return ENOSYS;
2595166124Srafan}
2596166124SrafanIEEE80211_IOCTL_SET(dummy, dummy_ioctl_set);
2597166124Srafan
2598166124Srafanstatic int
2599166124Srafanieee80211_ioctl_setdefault(struct ieee80211vap *vap, struct ieee80211req *ireq)
2600166124Srafan{
2601166124Srafan	ieee80211_ioctl_setfunc * const *set;
2602166124Srafan	int error;
2603166124Srafan
2604166124Srafan	SET_FOREACH(set, ieee80211_ioctl_setset) {
2605166124Srafan		error = (*set)(vap, ireq);
2606166124Srafan		if (error != ENOSYS)
2607166124Srafan			return error;
2608166124Srafan	}
2609166124Srafan	return EINVAL;
2610166124Srafan}
261150276Speter
261250276Speterstatic __noinline int
261350276Speterieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211req *ireq)
261450276Speter{
261550276Speter	struct ieee80211com *ic = vap->iv_ic;
261650276Speter	int error;
261750276Speter	const struct ieee80211_authenticator *auth;
261850276Speter	uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
2619166124Srafan	char tmpssid[IEEE80211_NWID_LEN];
2620166124Srafan	uint8_t tmpbssid[IEEE80211_ADDR_LEN];
262150276Speter	struct ieee80211_key *k;
262250276Speter	u_int kid;
2623166124Srafan	uint32_t flags;
2624166124Srafan
262550276Speter	error = 0;
262650276Speter	switch (ireq->i_type) {
262750276Speter	case IEEE80211_IOC_SSID:
262850276Speter		if (ireq->i_val != 0 ||
262950276Speter		    ireq->i_len > IEEE80211_NWID_LEN)
263050276Speter			return EINVAL;
263150276Speter		error = copyin(ireq->i_data, tmpssid, ireq->i_len);
263262449Speter		if (error)
2633166124Srafan			break;
2634166124Srafan		memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
2635166124Srafan		vap->iv_des_ssid[0].len = ireq->i_len;
2636166124Srafan		memcpy(vap->iv_des_ssid[0].ssid, tmpssid, ireq->i_len);
2637166124Srafan		vap->iv_des_nssid = (ireq->i_len > 0);
2638166124Srafan		error = ENETRESET;
2639166124Srafan		break;
2640166124Srafan	case IEEE80211_IOC_WEP:
2641166124Srafan		switch (ireq->i_val) {
2642166124Srafan		case IEEE80211_WEP_OFF:
264350276Speter			vap->iv_flags &= ~IEEE80211_F_PRIVACY;
264450276Speter			vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
2645166124Srafan			break;
2646166124Srafan		case IEEE80211_WEP_ON:
2647166124Srafan			vap->iv_flags |= IEEE80211_F_PRIVACY;
2648166124Srafan			vap->iv_flags |= IEEE80211_F_DROPUNENC;
264950276Speter			break;
2650166124Srafan		case IEEE80211_WEP_MIXED:
265197049Speter			vap->iv_flags |= IEEE80211_F_PRIVACY;
265297049Speter			vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
2653166124Srafan			break;
2654166124Srafan		}
2655166124Srafan		error = ENETRESET;
2656166124Srafan		break;
2657166124Srafan	case IEEE80211_IOC_WEPKEY:
265897049Speter		kid = (u_int) ireq->i_val;
265997049Speter		if (kid >= IEEE80211_WEP_NKID)
2660166124Srafan			return EINVAL;
266197049Speter		k = &vap->iv_nw_keys[kid];
266297049Speter		if (ireq->i_len == 0) {
266397049Speter			/* zero-len =>'s delete any existing key */
266497049Speter			(void) ieee80211_crypto_delkey(vap, k);
266597049Speter			break;
266697049Speter		}
266797049Speter		if (ireq->i_len > sizeof(tmpkey))
266897049Speter			return EINVAL;
266997049Speter		memset(tmpkey, 0, sizeof(tmpkey));
267097049Speter		error = copyin(ireq->i_data, tmpkey, ireq->i_len);
267197049Speter		if (error)
267297049Speter			break;
2673166124Srafan		ieee80211_key_update_begin(vap);
2674166124Srafan		k->wk_keyix = kid;	/* NB: force fixed key id */
2675166124Srafan		if (ieee80211_crypto_newkey(vap, IEEE80211_CIPHER_WEP,
2676166124Srafan		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
2677166124Srafan			k->wk_keylen = ireq->i_len;
2678166124Srafan			memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
2679166124Srafan			IEEE80211_ADDR_COPY(k->wk_macaddr, vap->iv_myaddr);
2680166124Srafan			if  (!ieee80211_crypto_setkey(vap, k))
2681166124Srafan				error = EINVAL;
2682166124Srafan		} else
2683166124Srafan			error = EINVAL;
2684166124Srafan		ieee80211_key_update_end(vap);
2685166124Srafan		break;
2686166124Srafan	case IEEE80211_IOC_WEPTXKEY:
2687166124Srafan		kid = (u_int) ireq->i_val;
2688166124Srafan		if (kid >= IEEE80211_WEP_NKID &&
2689166124Srafan		    (uint16_t) kid != IEEE80211_KEYIX_NONE)
2690166124Srafan			return EINVAL;
2691166124Srafan		vap->iv_def_txkey = kid;
2692166124Srafan		break;
2693166124Srafan	case IEEE80211_IOC_AUTHMODE:
2694166124Srafan		switch (ireq->i_val) {
2695166124Srafan		case IEEE80211_AUTH_WPA:
2696166124Srafan		case IEEE80211_AUTH_8021X:	/* 802.1x */
2697166124Srafan		case IEEE80211_AUTH_OPEN:	/* open */
2698166124Srafan		case IEEE80211_AUTH_SHARED:	/* shared-key */
2699166124Srafan		case IEEE80211_AUTH_AUTO:	/* auto */
2700166124Srafan			auth = ieee80211_authenticator_get(ireq->i_val);
2701166124Srafan			if (auth == NULL)
2702166124Srafan				return EINVAL;
2703166124Srafan			break;
2704166124Srafan		default:
2705166124Srafan			return EINVAL;
2706166124Srafan		}
2707166124Srafan		switch (ireq->i_val) {
2708166124Srafan		case IEEE80211_AUTH_WPA:	/* WPA w/ 802.1x */
2709166124Srafan			vap->iv_flags |= IEEE80211_F_PRIVACY;
2710166124Srafan			ireq->i_val = IEEE80211_AUTH_8021X;
2711166124Srafan			break;
2712166124Srafan		case IEEE80211_AUTH_OPEN:	/* open */
2713174993Srafan			vap->iv_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
2714166124Srafan			break;
2715174993Srafan		case IEEE80211_AUTH_SHARED:	/* shared-key */
2716166124Srafan		case IEEE80211_AUTH_8021X:	/* 802.1x */
2717166124Srafan			vap->iv_flags &= ~IEEE80211_F_WPA;
2718166124Srafan			/* both require a key so mark the PRIVACY capability */
2719166124Srafan			vap->iv_flags |= IEEE80211_F_PRIVACY;
2720166124Srafan			break;
2721166124Srafan		case IEEE80211_AUTH_AUTO:	/* auto */
2722166124Srafan			vap->iv_flags &= ~IEEE80211_F_WPA;
2723166124Srafan			/* XXX PRIVACY handling? */
272450276Speter			/* XXX what's the right way to do this? */
272550276Speter			break;
272650276Speter		}
272750276Speter		/* NB: authenticator attach/detach happens on state change */
272850276Speter		vap->iv_bss->ni_authmode = ireq->i_val;
272950276Speter		/* XXX mixed/mode/usage? */
273050276Speter		vap->iv_auth = auth;
273150276Speter		error = ENETRESET;
273250276Speter		break;
273350276Speter	case IEEE80211_IOC_CHANNEL:
273450276Speter		error = ieee80211_ioctl_setchannel(vap, ireq);
273550276Speter		break;
273650276Speter	case IEEE80211_IOC_POWERSAVE:
273750276Speter		switch (ireq->i_val) {
273850276Speter		case IEEE80211_POWERSAVE_OFF:
273950276Speter			if (vap->iv_flags & IEEE80211_F_PMGTON) {
274050276Speter				ieee80211_syncflag(vap, -IEEE80211_F_PMGTON);
274150276Speter				error = ERESTART;
274250276Speter			}
274350276Speter			break;
274450276Speter		case IEEE80211_POWERSAVE_ON:
274550276Speter			if ((vap->iv_caps & IEEE80211_C_PMGT) == 0)
274650276Speter				error = EOPNOTSUPP;
274750276Speter			else if ((vap->iv_flags & IEEE80211_F_PMGTON) == 0) {
274850276Speter				ieee80211_syncflag(vap, IEEE80211_F_PMGTON);
274950276Speter				error = ERESTART;
275050276Speter			}
275150276Speter			break;
275250276Speter		default:
275350276Speter			error = EINVAL;
275450276Speter			break;
275550276Speter		}
275650276Speter		break;
275750276Speter	case IEEE80211_IOC_POWERSAVESLEEP:
275850276Speter		if (ireq->i_val < 0)
275950276Speter			return EINVAL;
276050276Speter		ic->ic_lintval = ireq->i_val;
276150276Speter		error = ERESTART;
276250276Speter		break;
2763184989Srafan	case IEEE80211_IOC_RTSTHRESHOLD:
2764166124Srafan		if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
2765166124Srafan		      ireq->i_val <= IEEE80211_RTS_MAX))
2766166124Srafan			return EINVAL;
2767166124Srafan		vap->iv_rtsthreshold = ireq->i_val;
2768166124Srafan		error = ERESTART;
2769166124Srafan		break;
2770166124Srafan	case IEEE80211_IOC_PROTMODE:
2771166124Srafan		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2772166124Srafan			return EINVAL;
2773166124Srafan		ic->ic_protmode = (enum ieee80211_protmode)ireq->i_val;
2774166124Srafan		/* NB: if not operating in 11g this can wait */
2775166124Srafan		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2776166124Srafan		    IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
2777166124Srafan			error = ERESTART;
2778166124Srafan		break;
2779166124Srafan	case IEEE80211_IOC_TXPOWER:
2780166124Srafan		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2781166124Srafan			return EOPNOTSUPP;
278250276Speter		if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
2783184989Srafan		      ireq->i_val <= IEEE80211_TXPOWER_MAX))
2784184989Srafan			return EINVAL;
2785184989Srafan		ic->ic_txpowlimit = ireq->i_val;
2786184989Srafan		error = ERESTART;
2787184989Srafan		break;
2788184989Srafan	case IEEE80211_IOC_ROAMING:
2789184989Srafan		if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2790184989Srafan		    ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2791184989Srafan			return EINVAL;
2792184989Srafan		vap->iv_roaming = (enum ieee80211_roamingmode)ireq->i_val;
2793184989Srafan		/* XXXX reset? */
2794184989Srafan		break;
2795184989Srafan	case IEEE80211_IOC_PRIVACY:
2796184989Srafan		if (ireq->i_val) {
2797184989Srafan			/* XXX check for key state? */
2798184989Srafan			vap->iv_flags |= IEEE80211_F_PRIVACY;
2799184989Srafan		} else
2800184989Srafan			vap->iv_flags &= ~IEEE80211_F_PRIVACY;
2801184989Srafan		/* XXX ERESTART? */
2802184989Srafan		break;
2803184989Srafan	case IEEE80211_IOC_DROPUNENCRYPTED:
2804184989Srafan		if (ireq->i_val)
280550276Speter			vap->iv_flags |= IEEE80211_F_DROPUNENC;
280650276Speter		else
280797049Speter			vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
280897049Speter		/* XXX ERESTART? */
280997049Speter		break;
281097049Speter	case IEEE80211_IOC_WPAKEY:
281197049Speter		error = ieee80211_ioctl_setkey(vap, ireq);
281297049Speter		break;
281397049Speter	case IEEE80211_IOC_DELKEY:
2814166124Srafan		error = ieee80211_ioctl_delkey(vap, ireq);
2815166124Srafan		break;
2816166124Srafan	case IEEE80211_IOC_MLME:
2817166124Srafan		error = ieee80211_ioctl_setmlme(vap, ireq);
2818166124Srafan		break;
281950276Speter	case IEEE80211_IOC_COUNTERMEASURES:
282097049Speter		if (ireq->i_val) {
282197049Speter			if ((vap->iv_flags & IEEE80211_F_WPA) == 0)
282297049Speter				return EOPNOTSUPP;
282397049Speter			vap->iv_flags |= IEEE80211_F_COUNTERM;
282497049Speter		} else
282597049Speter			vap->iv_flags &= ~IEEE80211_F_COUNTERM;
282697049Speter		/* XXX ERESTART? */
2827166124Srafan		break;
2828166124Srafan	case IEEE80211_IOC_WPA:
2829166124Srafan		if (ireq->i_val > 3)
2830166124Srafan			return EINVAL;
283197049Speter		/* XXX verify ciphers available */
2832166124Srafan		flags = vap->iv_flags & ~IEEE80211_F_WPA;
2833166124Srafan		switch (ireq->i_val) {
2834166124Srafan		case 1:
2835166124Srafan			if (!(vap->iv_caps & IEEE80211_C_WPA1))
2836166124Srafan				return EOPNOTSUPP;
2837166124Srafan			flags |= IEEE80211_F_WPA1;
2838166124Srafan			break;
2839166124Srafan		case 2:
2840166124Srafan			if (!(vap->iv_caps & IEEE80211_C_WPA2))
2841166124Srafan				return EOPNOTSUPP;
2842166124Srafan			flags |= IEEE80211_F_WPA2;
2843166124Srafan			break;
2844166124Srafan		case 3:
2845166124Srafan			if ((vap->iv_caps & IEEE80211_C_WPA) != IEEE80211_C_WPA)
2846166124Srafan				return EOPNOTSUPP;
2847166124Srafan			flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
2848166124Srafan			break;
2849166124Srafan		default:	/*  Can't set any -> error */
2850166124Srafan			return EOPNOTSUPP;
2851166124Srafan		}
2852166124Srafan		vap->iv_flags = flags;
2853166124Srafan		error = ERESTART;	/* NB: can change beacon frame */
2854166124Srafan		break;
2855166124Srafan	case IEEE80211_IOC_WME:
2856166124Srafan		if (ireq->i_val) {
2857166124Srafan			if ((vap->iv_caps & IEEE80211_C_WME) == 0)
2858166124Srafan				return EOPNOTSUPP;
2859166124Srafan			ieee80211_syncflag(vap, IEEE80211_F_WME);
2860166124Srafan		} else
2861166124Srafan			ieee80211_syncflag(vap, -IEEE80211_F_WME);
2862166124Srafan		error = ERESTART;	/* NB: can change beacon frame */
2863166124Srafan		break;
2864166124Srafan	case IEEE80211_IOC_HIDESSID:
2865166124Srafan		if (ireq->i_val)
2866166124Srafan			vap->iv_flags |= IEEE80211_F_HIDESSID;
2867166124Srafan		else
2868166124Srafan			vap->iv_flags &= ~IEEE80211_F_HIDESSID;
2869166124Srafan		error = ERESTART;		/* XXX ENETRESET? */
2870166124Srafan		break;
2871166124Srafan	case IEEE80211_IOC_APBRIDGE:
2872166124Srafan		if (ireq->i_val == 0)
2873166124Srafan			vap->iv_flags |= IEEE80211_F_NOBRIDGE;
287450276Speter		else
287550276Speter			vap->iv_flags &= ~IEEE80211_F_NOBRIDGE;
287650276Speter		break;
287750276Speter	case IEEE80211_IOC_BSSID:
287850276Speter		if (ireq->i_len != sizeof(tmpbssid))
287950276Speter			return EINVAL;
288050276Speter		error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
288150276Speter		if (error)
288250276Speter			break;
288350276Speter		IEEE80211_ADDR_COPY(vap->iv_des_bssid, tmpbssid);
288450276Speter		if (IEEE80211_ADDR_EQ(vap->iv_des_bssid, zerobssid))
288550276Speter			vap->iv_flags &= ~IEEE80211_F_DESBSSID;
288650276Speter		else
288750276Speter			vap->iv_flags |= IEEE80211_F_DESBSSID;
288850276Speter		error = ENETRESET;
288950276Speter		break;
289050276Speter	case IEEE80211_IOC_CHANLIST:
2891166124Srafan		error = ieee80211_ioctl_setchanlist(vap, ireq);
2892166124Srafan		break;
2893166124Srafan#define	OLD_IEEE80211_IOC_SCAN_REQ	23
2894166124Srafan#ifdef OLD_IEEE80211_IOC_SCAN_REQ
2895166124Srafan	case OLD_IEEE80211_IOC_SCAN_REQ:
2896166124Srafan		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
2897166124Srafan			"%s: active scan request\n", __func__);
2898166124Srafan		/*
2899166124Srafan		 * If we are in INIT state then the driver has never
2900166124Srafan		 * had a chance to setup hardware state to do a scan;
2901166124Srafan		 * use the state machine to get us up the SCAN state.
2902166124Srafan		 * Otherwise just invoke the scan machinery to start
2903166124Srafan		 * a one-time scan.
2904166124Srafan		 */
290550276Speter		if (vap->iv_state == IEEE80211_S_INIT)
290662449Speter			ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
290750276Speter		else
290862449Speter			(void) ieee80211_start_scan(vap,
2909166124Srafan				IEEE80211_SCAN_ACTIVE |
2910166124Srafan				IEEE80211_SCAN_NOPICK |
2911166124Srafan				IEEE80211_SCAN_ONCE,
2912166124Srafan				IEEE80211_SCAN_FOREVER, 0, 0,
2913166124Srafan				/* XXX use ioctl params */
2914166124Srafan				vap->iv_des_nssid, vap->iv_des_ssid);
2915166124Srafan		break;
2916166124Srafan#endif /* OLD_IEEE80211_IOC_SCAN_REQ */
2917166124Srafan	case IEEE80211_IOC_SCAN_REQ:
2918166124Srafan		error = ieee80211_ioctl_scanreq(vap, ireq);
2919166124Srafan		break;
2920166124Srafan	case IEEE80211_IOC_SCAN_CANCEL:
2921166124Srafan		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
2922166124Srafan		    "%s: cancel scan\n", __func__);
2923166124Srafan		ieee80211_cancel_scan(vap);
2924166124Srafan		break;
2925166124Srafan	case IEEE80211_IOC_HTCONF:
2926166124Srafan		if (ireq->i_val & 1)
2927166124Srafan			ieee80211_syncflag_ht(vap, IEEE80211_FHT_HT);
2928166124Srafan		else
2929166124Srafan			ieee80211_syncflag_ht(vap, -IEEE80211_FHT_HT);
2930166124Srafan		if (ireq->i_val & 2)
2931166124Srafan			ieee80211_syncflag_ht(vap, IEEE80211_FHT_USEHT40);
293250276Speter		else
293350276Speter			ieee80211_syncflag_ht(vap, -IEEE80211_FHT_USEHT40);
293462449Speter		error = ENETRESET;
293562449Speter		break;
293662449Speter	case IEEE80211_IOC_ADDMAC:
2937166124Srafan	case IEEE80211_IOC_DELMAC:
2938166124Srafan		error = ieee80211_ioctl_macmac(vap, ireq);
2939166124Srafan		break;
2940166124Srafan	case IEEE80211_IOC_MACCMD:
2941166124Srafan		error = ieee80211_ioctl_setmaccmd(vap, ireq);
2942166124Srafan		break;
2943166124Srafan	case IEEE80211_IOC_STA_STATS:
2944166124Srafan		error = ieee80211_ioctl_setstastats(vap, ireq);
2945166124Srafan		break;
2946166124Srafan	case IEEE80211_IOC_STA_TXPOW:
2947166124Srafan		error = ieee80211_ioctl_setstatxpow(vap, ireq);
2948166124Srafan		break;
2949166124Srafan	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
2950166124Srafan	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
2951166124Srafan	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
2952166124Srafan	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
2953166124Srafan	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
2954166124Srafan	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
2955166124Srafan		error = ieee80211_ioctl_setwmeparam(vap, ireq);
2956166124Srafan		break;
2957166124Srafan	case IEEE80211_IOC_DTIM_PERIOD:
2958166124Srafan		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
2959166124Srafan		    vap->iv_opmode != IEEE80211_M_MBSS &&
2960166124Srafan		    vap->iv_opmode != IEEE80211_M_IBSS)
2961166124Srafan			return EINVAL;
2962166124Srafan		if (IEEE80211_DTIM_MIN <= ireq->i_val &&
296350276Speter		    ireq->i_val <= IEEE80211_DTIM_MAX) {
296450276Speter			vap->iv_dtim_period = ireq->i_val;
2965166124Srafan			error = ENETRESET;		/* requires restart */
2966166124Srafan		} else
2967166124Srafan			error = EINVAL;
2968166124Srafan		break;
2969166124Srafan	case IEEE80211_IOC_BEACON_INTERVAL:
2970166124Srafan		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
2971166124Srafan		    vap->iv_opmode != IEEE80211_M_MBSS &&
2972166124Srafan		    vap->iv_opmode != IEEE80211_M_IBSS)
2973166124Srafan			return EINVAL;
2974166124Srafan		if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
2975166124Srafan		    ireq->i_val <= IEEE80211_BINTVAL_MAX) {
2976166124Srafan			ic->ic_bintval = ireq->i_val;
2977166124Srafan			error = ENETRESET;		/* requires restart */
2978166124Srafan		} else
2979166124Srafan			error = EINVAL;
2980166124Srafan		break;
2981166124Srafan	case IEEE80211_IOC_PUREG:
2982166124Srafan		if (ireq->i_val)
2983166124Srafan			vap->iv_flags |= IEEE80211_F_PUREG;
2984166124Srafan		else
2985166124Srafan			vap->iv_flags &= ~IEEE80211_F_PUREG;
2986166124Srafan		/* NB: reset only if we're operating on an 11g channel */
2987166124Srafan		if (isvap11g(vap))
2988166124Srafan			error = ENETRESET;
2989166124Srafan		break;
2990166124Srafan	case IEEE80211_IOC_QUIET:
2991166124Srafan		vap->iv_quiet= ireq->i_val;
2992166124Srafan		break;
2993166124Srafan	case IEEE80211_IOC_QUIET_COUNT:
2994166124Srafan		vap->iv_quiet_count=ireq->i_val;
2995166124Srafan		break;
2996166124Srafan	case IEEE80211_IOC_QUIET_PERIOD:
2997166124Srafan		vap->iv_quiet_period=ireq->i_val;
2998166124Srafan		break;
299950276Speter	case IEEE80211_IOC_QUIET_OFFSET:
300050276Speter		vap->iv_quiet_offset=ireq->i_val;
300150276Speter		break;
3002166124Srafan	case IEEE80211_IOC_QUIET_DUR:
3003166124Srafan		if(ireq->i_val < vap->iv_bss->ni_intval)
300450276Speter			vap->iv_quiet_duration = ireq->i_val;
300550276Speter		else
300650276Speter			error = EINVAL;
300750276Speter		break;
300862449Speter	case IEEE80211_IOC_BGSCAN:
3009166124Srafan		if (ireq->i_val) {
3010166124Srafan			if ((vap->iv_caps & IEEE80211_C_BGSCAN) == 0)
3011166124Srafan				return EOPNOTSUPP;
3012166124Srafan			vap->iv_flags |= IEEE80211_F_BGSCAN;
3013166124Srafan		} else
3014166124Srafan			vap->iv_flags &= ~IEEE80211_F_BGSCAN;
3015166124Srafan		break;
3016166124Srafan	case IEEE80211_IOC_BGSCAN_IDLE:
301750276Speter		if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
301866963Speter			vap->iv_bgscanidle = ireq->i_val*hz/1000;
3019166124Srafan		else
3020166124Srafan			error = EINVAL;
3021166124Srafan		break;
3022166124Srafan	case IEEE80211_IOC_BGSCAN_INTERVAL:
3023166124Srafan		if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
3024166124Srafan			vap->iv_bgscanintvl = ireq->i_val*hz;
3025166124Srafan		else
3026166124Srafan			error = EINVAL;
3027166124Srafan		break;
3028166124Srafan	case IEEE80211_IOC_SCANVALID:
3029166124Srafan		if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
3030166124Srafan			vap->iv_scanvalid = ireq->i_val*hz;
3031166124Srafan		else
3032166124Srafan			error = EINVAL;
3033166124Srafan		break;
3034166124Srafan	case IEEE80211_IOC_FRAGTHRESHOLD:
3035166124Srafan		if ((vap->iv_caps & IEEE80211_C_TXFRAG) == 0 &&
3036166124Srafan		    ireq->i_val != IEEE80211_FRAG_MAX)
303750276Speter			return EOPNOTSUPP;
3038166124Srafan		if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
3039166124Srafan		      ireq->i_val <= IEEE80211_FRAG_MAX))
3040166124Srafan			return EINVAL;
3041166124Srafan		vap->iv_fragthreshold = ireq->i_val;
3042166124Srafan		error = ERESTART;
3043166124Srafan		break;
3044166124Srafan	case IEEE80211_IOC_BURST:
3045166124Srafan		if (ireq->i_val) {
3046166124Srafan			if ((vap->iv_caps & IEEE80211_C_BURST) == 0)
3047166124Srafan				return EOPNOTSUPP;
3048166124Srafan			ieee80211_syncflag(vap, IEEE80211_F_BURST);
3049166124Srafan		} else
3050166124Srafan			ieee80211_syncflag(vap, -IEEE80211_F_BURST);
3051166124Srafan		error = ERESTART;
3052176187Srafan		break;
3053166124Srafan	case IEEE80211_IOC_BMISSTHRESHOLD:
3054166124Srafan		if (!(IEEE80211_HWBMISS_MIN <= ireq->i_val &&
3055166124Srafan		      ireq->i_val <= IEEE80211_HWBMISS_MAX))
3056166124Srafan			return EINVAL;
3057166124Srafan		vap->iv_bmissthreshold = ireq->i_val;
3058174993Srafan		error = ERESTART;
3059174993Srafan		break;
3060174993Srafan	case IEEE80211_IOC_CURCHAN:
3061174993Srafan		error = ieee80211_ioctl_setcurchan(vap, ireq);
3062166124Srafan		break;
306366963Speter	case IEEE80211_IOC_SHORTGI:
3064166124Srafan		if (ireq->i_val) {
3065166124Srafan#define	IEEE80211_HTCAP_SHORTGI \
3066166124Srafan	(IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
3067166124Srafan			if (((ireq->i_val ^ vap->iv_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
3068166124Srafan				return EINVAL;
3069166124Srafan			if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
3070166124Srafan				vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI20;
3071166124Srafan			if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
3072166124Srafan				vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI40;
3073166124Srafan#undef IEEE80211_HTCAP_SHORTGI
3074166124Srafan		} else
3075166124Srafan			vap->iv_flags_ht &=
3076166124Srafan			    ~(IEEE80211_FHT_SHORTGI20 | IEEE80211_FHT_SHORTGI40);
3077166124Srafan		error = ERESTART;
3078166124Srafan		break;
3079166124Srafan	case IEEE80211_IOC_AMPDU:
3080176187Srafan		if (ireq->i_val && (vap->iv_htcaps & IEEE80211_HTC_AMPDU) == 0)
3081176187Srafan			return EINVAL;
3082166124Srafan		if (ireq->i_val & 1)
3083176187Srafan			vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_TX;
3084176187Srafan		else
3085176187Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_TX;
3086176187Srafan		if (ireq->i_val & 2)
3087176187Srafan			vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_RX;
3088176187Srafan		else
3089176187Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX;
3090176187Srafan		/* NB: reset only if we're operating on an 11n channel */
3091166124Srafan		if (isvapht(vap))
3092166124Srafan			error = ERESTART;
3093166124Srafan		break;
3094166124Srafan	case IEEE80211_IOC_AMPDU_LIMIT:
3095166124Srafan		if (!(IEEE80211_HTCAP_MAXRXAMPDU_8K <= ireq->i_val &&
3096166124Srafan		      ireq->i_val <= IEEE80211_HTCAP_MAXRXAMPDU_64K))
3097166124Srafan			return EINVAL;
3098166124Srafan		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
3099166124Srafan			vap->iv_ampdu_rxmax = ireq->i_val;
3100166124Srafan		else
3101166124Srafan			vap->iv_ampdu_limit = ireq->i_val;
3102166124Srafan		error = ERESTART;
3103166124Srafan		break;
3104166124Srafan	case IEEE80211_IOC_AMPDU_DENSITY:
3105166124Srafan		if (!(IEEE80211_HTCAP_MPDUDENSITY_NA <= ireq->i_val &&
3106166124Srafan		      ireq->i_val <= IEEE80211_HTCAP_MPDUDENSITY_16))
3107166124Srafan			return EINVAL;
3108166124Srafan		vap->iv_ampdu_density = ireq->i_val;
3109166124Srafan		error = ERESTART;
3110166124Srafan		break;
3111174993Srafan	case IEEE80211_IOC_AMSDU:
3112176187Srafan		if (ireq->i_val && (vap->iv_htcaps & IEEE80211_HTC_AMSDU) == 0)
3113176187Srafan			return EINVAL;
3114176187Srafan		if (ireq->i_val & 1)
3115176187Srafan			vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_TX;
3116176187Srafan		else
3117176187Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_AMSDU_TX;
3118176187Srafan		if (ireq->i_val & 2)
3119176187Srafan			vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_RX;
3120166124Srafan		else
3121166124Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_AMSDU_RX;
3122174993Srafan		/* NB: reset only if we're operating on an 11n channel */
3123176187Srafan		if (isvapht(vap))
3124176187Srafan			error = ERESTART;
3125176187Srafan		break;
3126176187Srafan	case IEEE80211_IOC_AMSDU_LIMIT:
3127176187Srafan		/* XXX validate */
3128176187Srafan		vap->iv_amsdu_limit = ireq->i_val;	/* XXX truncation? */
3129166124Srafan		break;
3130166124Srafan	case IEEE80211_IOC_PUREN:
3131174993Srafan		if (ireq->i_val) {
3132176187Srafan			if ((vap->iv_flags_ht & IEEE80211_FHT_HT) == 0)
3133176187Srafan				return EINVAL;
3134176187Srafan			vap->iv_flags_ht |= IEEE80211_FHT_PUREN;
3135176187Srafan		} else
3136176187Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_PUREN;
3137166124Srafan		/* NB: reset only if we're operating on an 11n channel */
3138166124Srafan		if (isvapht(vap))
3139174993Srafan			error = ERESTART;
3140176187Srafan		break;
3141176187Srafan	case IEEE80211_IOC_DOTH:
3142176187Srafan		if (ireq->i_val) {
3143176187Srafan#if 0
3144176187Srafan			/* XXX no capability */
3145174993Srafan			if ((vap->iv_caps & IEEE80211_C_DOTH) == 0)
3146166124Srafan				return EOPNOTSUPP;
3147166124Srafan#endif
3148166124Srafan			vap->iv_flags |= IEEE80211_F_DOTH;
3149166124Srafan		} else
3150166124Srafan			vap->iv_flags &= ~IEEE80211_F_DOTH;
3151166124Srafan		error = ENETRESET;
3152166124Srafan		break;
3153166124Srafan	case IEEE80211_IOC_REGDOMAIN:
3154166124Srafan		error = ieee80211_ioctl_setregdomain(vap, ireq);
3155166124Srafan		break;
3156166124Srafan	case IEEE80211_IOC_ROAM:
3157166124Srafan		error = ieee80211_ioctl_setroam(vap, ireq);
3158166124Srafan		break;
3159166124Srafan	case IEEE80211_IOC_TXPARAMS:
3160166124Srafan		error = ieee80211_ioctl_settxparams(vap, ireq);
3161166124Srafan		break;
3162166124Srafan	case IEEE80211_IOC_HTCOMPAT:
3163166124Srafan		if (ireq->i_val) {
3164166124Srafan			if ((vap->iv_flags_ht & IEEE80211_FHT_HT) == 0)
3165166124Srafan				return EOPNOTSUPP;
3166166124Srafan			vap->iv_flags_ht |= IEEE80211_FHT_HTCOMPAT;
3167166124Srafan		} else
3168174993Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_HTCOMPAT;
3169166124Srafan		/* NB: reset only if we're operating on an 11n channel */
3170174993Srafan		if (isvapht(vap))
3171166124Srafan			error = ERESTART;
3172166124Srafan		break;
3173174993Srafan	case IEEE80211_IOC_DWDS:
3174174993Srafan		if (ireq->i_val) {
3175166124Srafan			/* NB: DWDS only makes sense for WDS-capable devices */
3176166124Srafan			if ((ic->ic_caps & IEEE80211_C_WDS) == 0)
3177174993Srafan				return EOPNOTSUPP;
3178174993Srafan			/* NB: DWDS is used only with ap+sta vaps */
3179166124Srafan			if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
3180174993Srafan			    vap->iv_opmode != IEEE80211_M_STA)
3181174993Srafan				return EINVAL;
3182174993Srafan			vap->iv_flags |= IEEE80211_F_DWDS;
3183174993Srafan			if (vap->iv_opmode == IEEE80211_M_STA)
3184174993Srafan				vap->iv_flags_ext |= IEEE80211_FEXT_4ADDR;
3185174993Srafan		} else {
3186174993Srafan			vap->iv_flags &= ~IEEE80211_F_DWDS;
3187166124Srafan			if (vap->iv_opmode == IEEE80211_M_STA)
3188176187Srafan				vap->iv_flags_ext &= ~IEEE80211_FEXT_4ADDR;
3189176187Srafan		}
3190176187Srafan		break;
3191176187Srafan	case IEEE80211_IOC_INACTIVITY:
3192176187Srafan		if (ireq->i_val)
3193176187Srafan			vap->iv_flags_ext |= IEEE80211_FEXT_INACT;
3194176187Srafan		else
3195176187Srafan			vap->iv_flags_ext &= ~IEEE80211_FEXT_INACT;
3196176187Srafan		break;
3197176187Srafan	case IEEE80211_IOC_APPIE:
3198176187Srafan		error = ieee80211_ioctl_setappie(vap, ireq);
3199176187Srafan		break;
3200176187Srafan	case IEEE80211_IOC_WPS:
3201176187Srafan		if (ireq->i_val) {
3202176187Srafan			if ((vap->iv_caps & IEEE80211_C_WPA) == 0)
3203176187Srafan				return EOPNOTSUPP;
3204176187Srafan			vap->iv_flags_ext |= IEEE80211_FEXT_WPS;
3205176187Srafan		} else
3206176187Srafan			vap->iv_flags_ext &= ~IEEE80211_FEXT_WPS;
3207176187Srafan		break;
3208176187Srafan	case IEEE80211_IOC_TSN:
3209176187Srafan		if (ireq->i_val) {
3210176187Srafan			if ((vap->iv_caps & IEEE80211_C_WPA) == 0)
3211176187Srafan				return EOPNOTSUPP;
3212176187Srafan			vap->iv_flags_ext |= IEEE80211_FEXT_TSN;
3213176187Srafan		} else
3214174993Srafan			vap->iv_flags_ext &= ~IEEE80211_FEXT_TSN;
3215174993Srafan		break;
3216174993Srafan	case IEEE80211_IOC_CHANSWITCH:
3217174993Srafan		error = ieee80211_ioctl_chanswitch(vap, ireq);
3218174993Srafan		break;
3219174993Srafan	case IEEE80211_IOC_DFS:
3220174993Srafan		if (ireq->i_val) {
3221174993Srafan			if ((vap->iv_caps & IEEE80211_C_DFS) == 0)
3222174993Srafan				return EOPNOTSUPP;
3223174993Srafan			/* NB: DFS requires 11h support */
3224174993Srafan			if ((vap->iv_flags & IEEE80211_F_DOTH) == 0)
3225174993Srafan				return EINVAL;
322666963Speter			vap->iv_flags_ext |= IEEE80211_FEXT_DFS;
3227166124Srafan		} else
3228166124Srafan			vap->iv_flags_ext &= ~IEEE80211_FEXT_DFS;
3229166124Srafan		break;
3230166124Srafan	case IEEE80211_IOC_DOTD:
3231166124Srafan		if (ireq->i_val)
3232166124Srafan			vap->iv_flags_ext |= IEEE80211_FEXT_DOTD;
3233166124Srafan		else
3234166124Srafan			vap->iv_flags_ext &= ~IEEE80211_FEXT_DOTD;
3235166124Srafan		if (vap->iv_opmode == IEEE80211_M_STA)
3236166124Srafan			error = ENETRESET;
3237166124Srafan		break;
3238166124Srafan	case IEEE80211_IOC_HTPROTMODE:
3239166124Srafan		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
3240166124Srafan			return EINVAL;
3241176187Srafan		ic->ic_htprotmode = ireq->i_val ?
3242176187Srafan		    IEEE80211_PROT_RTSCTS : IEEE80211_PROT_NONE;
3243166124Srafan		/* NB: if not operating in 11n this can wait */
3244166124Srafan		if (isvapht(vap))
3245166124Srafan			error = ERESTART;
3246166124Srafan		break;
3247166124Srafan	case IEEE80211_IOC_STA_VLAN:
3248166124Srafan		error = ieee80211_ioctl_setstavlan(vap, ireq);
3249166124Srafan		break;
3250166124Srafan	case IEEE80211_IOC_SMPS:
3251166124Srafan		if ((ireq->i_val &~ IEEE80211_HTCAP_SMPS) != 0 ||
3252166124Srafan		    ireq->i_val == 0x0008)	/* value of 2 is reserved */
325350276Speter			return EINVAL;
325450276Speter		if (ireq->i_val != IEEE80211_HTCAP_SMPS_OFF &&
3255166124Srafan		    (vap->iv_htcaps & IEEE80211_HTC_SMPS) == 0)
3256166124Srafan			return EOPNOTSUPP;
3257166124Srafan		vap->iv_htcaps = (vap->iv_htcaps &~ IEEE80211_HTCAP_SMPS) |
325850276Speter			ireq->i_val;
325950276Speter		/* NB: if not operating in 11n this can wait */
3260166124Srafan		if (isvapht(vap))
3261166124Srafan			error = ERESTART;
326250276Speter		break;
3263174993Srafan	case IEEE80211_IOC_RIFS:
3264174993Srafan		if (ireq->i_val != 0) {
3265166124Srafan			if ((vap->iv_htcaps & IEEE80211_HTC_RIFS) == 0)
3266166124Srafan				return EOPNOTSUPP;
3267166124Srafan			vap->iv_flags_ht |= IEEE80211_FHT_RIFS;
3268166124Srafan		} else
3269166124Srafan			vap->iv_flags_ht &= ~IEEE80211_FHT_RIFS;
3270166124Srafan		/* NB: if not operating in 11n this can wait */
3271166124Srafan		if (isvapht(vap))
3272166124Srafan			error = ERESTART;
3273174993Srafan		break;
3274174993Srafan	default:
3275174993Srafan		error = ieee80211_ioctl_setdefault(vap, ireq);
3276174993Srafan		break;
3277174993Srafan	}
3278174993Srafan	/*
3279174993Srafan	 * The convention is that ENETRESET means an operation
3280174993Srafan	 * requires a complete re-initialization of the device (e.g.
3281174993Srafan	 * changing something that affects the association state).
3282174993Srafan	 * ERESTART means the request may be handled with only a
3283174993Srafan	 * reload of the hardware state.  We hand ERESTART requests
3284174993Srafan	 * to the iv_reset callback so the driver can decide.  If
3285184989Srafan	 * a device does not fillin iv_reset then it defaults to one
3286184989Srafan	 * that returns ENETRESET.  Otherwise a driver may return
3287184989Srafan	 * ENETRESET (in which case a full reset will be done) or
3288184989Srafan	 * 0 to mean there's no need to do anything (e.g. when the
3289166124Srafan	 * change has no effect on the driver/device).
3290166124Srafan	 */
3291166124Srafan	if (error == ERESTART)
329262449Speter		error = IFNET_IS_UP_RUNNING(vap->iv_ifp) ?
3293166124Srafan		    vap->iv_reset(vap, ireq->i_type) : 0;
3294166124Srafan	if (error == ENETRESET) {
3295166124Srafan		/* XXX need to re-think AUTO handling */
3296166124Srafan		if (IS_UP_AUTO(vap))
329762449Speter			ieee80211_init(vap);
3298166124Srafan		error = 0;
3299166124Srafan	}
3300166124Srafan	return error;
3301166124Srafan}
3302166124Srafan
3303166124Srafan/*
3304166124Srafan * Rebuild the parent's multicast address list after an add/del
3305166124Srafan * of a multicast address for a vap.  We have no way to tell
330650276Speter * what happened above to optimize the work so we purge the entire
330750276Speter * list and rebuild from scratch.  This is way expensive.
330850276Speter * Note also the half-baked workaround for if_addmulti calling
330950276Speter * back to the parent device; there's no way to insert mcast
331050276Speter * entries quietly and/or cheaply.
331150276Speter */
331250276Speterstatic void
331350276Speterieee80211_ioctl_updatemulti(struct ieee80211com *ic)
331450276Speter{
3315166124Srafan	struct ifnet *parent = ic->ic_ifp;
3316166124Srafan	struct ieee80211vap *vap;
3317166124Srafan	void *ioctl;
3318166124Srafan
3319166124Srafan	IEEE80211_LOCK(ic);
3320166124Srafan	if_delallmulti(parent);
3321166124Srafan	ioctl = parent->if_ioctl;	/* XXX WAR if_allmulti */
3322166124Srafan	parent->if_ioctl = NULL;
3323166124Srafan	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
3324166124Srafan		struct ifnet *ifp = vap->iv_ifp;
3325166124Srafan		struct ifmultiaddr *ifma;
3326166124Srafan
3327166124Srafan		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3328166124Srafan			if (ifma->ifma_addr->sa_family != AF_LINK)
3329166124Srafan				continue;
3330166124Srafan			(void) if_addmulti(parent, ifma->ifma_addr, NULL);
3331166124Srafan		}
3332166124Srafan	}
3333166124Srafan	parent->if_ioctl = ioctl;
3334166124Srafan	ieee80211_runtask(ic, &ic->ic_mcast_task);
3335166124Srafan	IEEE80211_UNLOCK(ic);
3336166124Srafan}
3337166124Srafan
3338166124Srafanint
3339166124Srafanieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3340166124Srafan{
3341166124Srafan	struct ieee80211vap *vap = ifp->if_softc;
3342166124Srafan	struct ieee80211com *ic = vap->iv_ic;
3343166124Srafan	int error = 0;
3344166124Srafan	struct ifreq *ifr;
3345166124Srafan	struct ifaddr *ifa;			/* XXX */
3346166124Srafan
3347166124Srafan	switch (cmd) {
3348166124Srafan	case SIOCSIFFLAGS:
3349166124Srafan		IEEE80211_LOCK(ic);
3350166124Srafan		ieee80211_syncifflag_locked(ic, IFF_PROMISC);
3351166124Srafan		ieee80211_syncifflag_locked(ic, IFF_ALLMULTI);
3352166124Srafan		if (ifp->if_flags & IFF_UP) {
3353166124Srafan			/*
335450276Speter			 * Bring ourself up unless we're already operational.
3355166124Srafan			 * If we're the first vap and the parent is not up
3356166124Srafan			 * then it will automatically be brought up as a
3357166124Srafan			 * side-effect of bringing ourself up.
3358166124Srafan			 */
3359166124Srafan			if (vap->iv_state == IEEE80211_S_INIT)
336062449Speter				ieee80211_start_locked(vap);
3361166124Srafan		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3362166124Srafan			/*
3363166124Srafan			 * Stop ourself.  If we are the last vap to be
3364166124Srafan			 * marked down the parent will also be taken down.
3365166124Srafan			 */
3366166124Srafan			ieee80211_stop_locked(vap);
3367166124Srafan		}
3368166124Srafan		IEEE80211_UNLOCK(ic);
3369166124Srafan		/* Wait for parent ioctl handler if it was queued */
3370166124Srafan		ieee80211_waitfor_parent(ic);
3371166124Srafan		break;
3372166124Srafan	case SIOCADDMULTI:
3373166124Srafan	case SIOCDELMULTI:
3374166124Srafan		ieee80211_ioctl_updatemulti(ic);
337566963Speter		break;
3376166124Srafan	case SIOCSIFMEDIA:
337766963Speter	case SIOCGIFMEDIA:
337866963Speter		ifr = (struct ifreq *)data;
337966963Speter		error = ifmedia_ioctl(ifp, ifr, &vap->iv_media, cmd);
338066963Speter		break;
338166963Speter	case SIOCG80211:
338266963Speter		error = ieee80211_ioctl_get80211(vap, cmd,
338366963Speter				(struct ieee80211req *) data);
3384166124Srafan		break;
3385166124Srafan	case SIOCS80211:
3386166124Srafan		error = priv_check(curthread, PRIV_NET80211_MANAGE);
3387166124Srafan		if (error == 0)
3388166124Srafan			error = ieee80211_ioctl_set80211(vap, cmd,
3389166124Srafan					(struct ieee80211req *) data);
3390166124Srafan		break;
3391166124Srafan	case SIOCG80211STATS:
3392176187Srafan		ifr = (struct ifreq *)data;
3393176187Srafan		copyout(&vap->iv_stats, ifr->ifr_data, sizeof (vap->iv_stats));
339462449Speter		break;
3395166124Srafan	case SIOCSIFMTU:
3396166124Srafan		ifr = (struct ifreq *)data;
3397166124Srafan		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
3398166124Srafan		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
3399166124Srafan			error = EINVAL;
3400166124Srafan		else
3401166124Srafan			ifp->if_mtu = ifr->ifr_mtu;
340262449Speter		break;
3403166124Srafan	case SIOCSIFADDR:
3404176187Srafan		/*
3405176187Srafan		 * XXX Handle this directly so we can supress if_init calls.
340662449Speter		 * XXX This should be done in ether_ioctl but for the moment
3407166124Srafan		 * XXX there are too many other parts of the system that
3408176187Srafan		 * XXX set IFF_UP and so supress if_init being called when
340950276Speter		 * XXX it should be.
341050276Speter		 */
3411166124Srafan		ifa = (struct ifaddr *) data;
3412166124Srafan		switch (ifa->ifa_addr->sa_family) {
341350276Speter#ifdef INET
3414166124Srafan		case AF_INET:
3415166124Srafan			if ((ifp->if_flags & IFF_UP) == 0) {
341650276Speter				ifp->if_flags |= IFF_UP;
341750276Speter				ifp->if_init(ifp->if_softc);
3418166124Srafan			}
3419166124Srafan			arp_ifinit(ifp, ifa);
3420166124Srafan			break;
3421166124Srafan#endif
3422166124Srafan#ifdef IPX
3423166124Srafan		/*
3424166124Srafan		 * XXX - This code is probably wrong,
3425166124Srafan		 *	 but has been copied many times.
342650276Speter		 */
342750276Speter		case AF_IPX: {
342850276Speter			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
342950276Speter
343050276Speter			if (ipx_nullhost(*ina))
3431166124Srafan				ina->x_host = *(union ipx_host *)
3432176187Srafan				    IF_LLADDR(ifp);
343350276Speter			else
343450276Speter				bcopy((caddr_t) ina->x_host.c_host,
343550276Speter				      (caddr_t) IF_LLADDR(ifp),
343676726Speter				      ETHER_ADDR_LEN);
343776726Speter			/* fall thru... */
3438166124Srafan		}
3439166124Srafan#endif
3440166124Srafan		default:
3441166124Srafan			if ((ifp->if_flags & IFF_UP) == 0) {
3442166124Srafan				ifp->if_flags |= IFF_UP;
3443166124Srafan				ifp->if_init(ifp->if_softc);
3444166124Srafan			}
3445166124Srafan			break;
3446166124Srafan		}
3447166124Srafan		break;
3448166124Srafan	/* Pass NDIS ioctls up to the driver */
3449166124Srafan	case SIOCGDRVSPEC:
345050276Speter	case SIOCSDRVSPEC:
3451166124Srafan	case SIOCGPRIVATE_0: {
3452166124Srafan		struct ifnet *parent = vap->iv_ic->ic_ifp;
3453166124Srafan		error = parent->if_ioctl(parent, cmd, data);
3454166124Srafan		break;
3455166124Srafan	}
345650276Speter	default:
345750276Speter		error = ether_ioctl(ifp, cmd, data);
345850276Speter		break;
345950276Speter	}
346050276Speter	return error;
346150276Speter}
346250276Speter