Home | History | Annotate | Line # | Download | only in net80211
ieee80211_ioctl.c revision 1.60.18.10
      1  1.60.18.10       nat /*	$NetBSD: ieee80211_ioctl.c,v 1.60.18.10 2020/04/27 07:45:57 nat Exp $	*/
      2   1.60.18.2      phil 
      3         1.1    dyoung /*-
      4   1.60.18.1      phil  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
      5   1.60.18.1      phil  *
      6         1.1    dyoung  * Copyright (c) 2001 Atsushi Onoe
      7   1.60.18.1      phil  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
      8         1.1    dyoung  * All rights reserved.
      9         1.1    dyoung  *
     10         1.1    dyoung  * Redistribution and use in source and binary forms, with or without
     11         1.1    dyoung  * modification, are permitted provided that the following conditions
     12         1.1    dyoung  * are met:
     13         1.1    dyoung  * 1. Redistributions of source code must retain the above copyright
     14         1.1    dyoung  *    notice, this list of conditions and the following disclaimer.
     15         1.1    dyoung  * 2. Redistributions in binary form must reproduce the above copyright
     16         1.1    dyoung  *    notice, this list of conditions and the following disclaimer in the
     17         1.1    dyoung  *    documentation and/or other materials provided with the distribution.
     18         1.1    dyoung  *
     19         1.1    dyoung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20         1.1    dyoung  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21         1.1    dyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22         1.1    dyoung  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23         1.1    dyoung  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24         1.1    dyoung  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25         1.1    dyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26         1.1    dyoung  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27         1.1    dyoung  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28         1.1    dyoung  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29         1.1    dyoung  */
     30         1.1    dyoung 
     31         1.1    dyoung #include <sys/cdefs.h>
     32   1.60.18.8  christos #ifdef __NetBSD__
     33  1.60.18.10       nat __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.60.18.10 2020/04/27 07:45:57 nat Exp $");
     34   1.60.18.2      phil #endif
     35         1.1    dyoung 
     36         1.1    dyoung /*
     37         1.1    dyoung  * IEEE 802.11 ioctl support (FreeBSD-specific)
     38         1.1    dyoung  */
     39         1.1    dyoung 
     40   1.60.18.8  christos #ifdef _KERNEL_OPT
     41        1.10    dyoung #include "opt_inet.h"
     42   1.60.18.1      phil #include "opt_wlan.h"
     43   1.60.18.8  christos #endif
     44        1.10    dyoung 
     45         1.1    dyoung #include <sys/endian.h>
     46         1.1    dyoung #include <sys/param.h>
     47         1.1    dyoung #include <sys/kernel.h>
     48   1.60.18.1      phil #include <sys/malloc.h>
     49   1.60.18.2      phil #if __FreeBSD__
     50   1.60.18.1      phil #include <sys/priv.h>
     51   1.60.18.2      phil #endif
     52         1.1    dyoung #include <sys/socket.h>
     53         1.1    dyoung #include <sys/sockio.h>
     54         1.1    dyoung #include <sys/systm.h>
     55   1.60.18.8  christos #include <sys/proc.h>
     56   1.60.18.8  christos #include <sys/kauth.h>
     57   1.60.18.8  christos #include <sys/module.h>
     58   1.60.18.8  christos #include <sys/compat_stub.h>
     59        1.19    dyoung 
     60         1.1    dyoung #include <net/if.h>
     61   1.60.18.2      phil #if __FreeBSD__
     62   1.60.18.1      phil #include <net/if_var.h>
     63   1.60.18.2      phil #endif
     64   1.60.18.1      phil #include <net/if_dl.h>
     65         1.1    dyoung #include <net/if_media.h>
     66   1.60.18.2      phil #if __FreeBSD__
     67   1.60.18.1      phil #include <net/ethernet.h>
     68   1.60.18.2      phil #endif
     69   1.60.18.2      phil #if __NetBSD__
     70   1.60.18.2      phil #include <net/if_ether.h>
     71   1.60.18.2      phil #endif
     72         1.1    dyoung 
     73        1.10    dyoung #ifdef INET
     74        1.10    dyoung #include <netinet/in.h>
     75   1.60.18.2      phil #if __FreeBSD__
     76   1.60.18.1      phil #include <netinet/if_ether.h>
     77        1.10    dyoung #endif
     78   1.60.18.2      phil #if __NetBSD__
     79   1.60.18.2      phil #include <netinet/if_inarp.h>
     80   1.60.18.2      phil #endif
     81   1.60.18.2      phil #endif
     82        1.10    dyoung 
     83         1.1    dyoung #include <net80211/ieee80211_var.h>
     84         1.1    dyoung #include <net80211/ieee80211_ioctl.h>
     85   1.60.18.1      phil #include <net80211/ieee80211_regdomain.h>
     86   1.60.18.1      phil #include <net80211/ieee80211_input.h>
     87         1.1    dyoung 
     88   1.60.18.2      phil #ifdef __NetBSD__
     89   1.60.18.2      phil #undef  KASSERT
     90   1.60.18.2      phil #define KASSERT(__cond, __complaint) FBSDKASSERT(__cond, __complaint)
     91   1.60.18.2      phil #endif
     92   1.60.18.2      phil 
     93   1.60.18.1      phil #define	IS_UP_AUTO(_vap) \
     94   1.60.18.1      phil 	(IFNET_IS_UP_RUNNING((_vap)->iv_ifp) && \
     95   1.60.18.1      phil 	 (_vap)->iv_roaming == IEEE80211_ROAMING_AUTO)
     96        1.19    dyoung 
     97   1.60.18.1      phil static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
     98   1.60.18.1      phil static struct ieee80211_channel *findchannel(struct ieee80211com *,
     99   1.60.18.1      phil 		int ieee, int mode);
    100   1.60.18.1      phil static int ieee80211_scanreq(struct ieee80211vap *,
    101   1.60.18.1      phil 		struct ieee80211_scan_req *);
    102        1.19    dyoung 
    103        1.19    dyoung static int
    104   1.60.18.1      phil ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
    105        1.19    dyoung {
    106   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    107        1.19    dyoung 	struct ieee80211_node *ni;
    108        1.19    dyoung 	struct ieee80211req_key ik;
    109        1.19    dyoung 	struct ieee80211_key *wk;
    110        1.19    dyoung 	const struct ieee80211_cipher *cip;
    111        1.19    dyoung 	u_int kid;
    112        1.19    dyoung 	int error;
    113        1.19    dyoung 
    114        1.19    dyoung 	if (ireq->i_len != sizeof(ik))
    115        1.19    dyoung 		return EINVAL;
    116        1.19    dyoung 	error = copyin(ireq->i_data, &ik, sizeof(ik));
    117        1.19    dyoung 	if (error)
    118        1.19    dyoung 		return error;
    119        1.19    dyoung 	kid = ik.ik_keyix;
    120        1.19    dyoung 	if (kid == IEEE80211_KEYIX_NONE) {
    121   1.60.18.1      phil 		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, ik.ik_macaddr);
    122        1.19    dyoung 		if (ni == NULL)
    123   1.60.18.1      phil 			return ENOENT;
    124        1.19    dyoung 		wk = &ni->ni_ucastkey;
    125        1.19    dyoung 	} else {
    126        1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
    127        1.19    dyoung 			return EINVAL;
    128   1.60.18.1      phil 		wk = &vap->iv_nw_keys[kid];
    129   1.60.18.1      phil 		IEEE80211_ADDR_COPY(&ik.ik_macaddr, vap->iv_bss->ni_macaddr);
    130        1.19    dyoung 		ni = NULL;
    131        1.19    dyoung 	}
    132        1.19    dyoung 	cip = wk->wk_cipher;
    133        1.19    dyoung 	ik.ik_type = cip->ic_cipher;
    134        1.19    dyoung 	ik.ik_keylen = wk->wk_keylen;
    135        1.19    dyoung 	ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
    136   1.60.18.1      phil 	if (wk->wk_keyix == vap->iv_def_txkey)
    137        1.19    dyoung 		ik.ik_flags |= IEEE80211_KEY_DEFAULT;
    138   1.60.18.1      phil 	if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
    139        1.19    dyoung 		/* NB: only root can read key data */
    140   1.60.18.1      phil 		ik.ik_keyrsc = wk->wk_keyrsc[IEEE80211_NONQOS_TID];
    141        1.19    dyoung 		ik.ik_keytsc = wk->wk_keytsc;
    142        1.19    dyoung 		memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
    143        1.19    dyoung 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
    144        1.19    dyoung 			memcpy(ik.ik_keydata+wk->wk_keylen,
    145        1.19    dyoung 				wk->wk_key + IEEE80211_KEYBUF_SIZE,
    146        1.19    dyoung 				IEEE80211_MICBUF_SIZE);
    147        1.19    dyoung 			ik.ik_keylen += IEEE80211_MICBUF_SIZE;
    148        1.19    dyoung 		}
    149        1.19    dyoung 	} else {
    150        1.19    dyoung 		ik.ik_keyrsc = 0;
    151        1.19    dyoung 		ik.ik_keytsc = 0;
    152        1.19    dyoung 		memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
    153        1.19    dyoung 	}
    154        1.19    dyoung 	if (ni != NULL)
    155        1.19    dyoung 		ieee80211_free_node(ni);
    156        1.19    dyoung 	return copyout(&ik, ireq->i_data, sizeof(ik));
    157        1.19    dyoung }
    158        1.19    dyoung 
    159        1.19    dyoung static int
    160   1.60.18.1      phil ieee80211_ioctl_getchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
    161        1.19    dyoung {
    162   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    163        1.19    dyoung 
    164   1.60.18.1      phil 	if (sizeof(ic->ic_chan_active) < ireq->i_len)
    165   1.60.18.1      phil 		ireq->i_len = sizeof(ic->ic_chan_active);
    166   1.60.18.1      phil 	return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
    167        1.19    dyoung }
    168        1.19    dyoung 
    169        1.19    dyoung static int
    170   1.60.18.1      phil ieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq)
    171        1.19    dyoung {
    172   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    173   1.60.18.1      phil 	uint32_t space;
    174        1.35  christos 
    175   1.60.18.1      phil 	space = __offsetof(struct ieee80211req_chaninfo,
    176   1.60.18.1      phil 			ic_chans[ic->ic_nchans]);
    177        1.19    dyoung 	if (space > ireq->i_len)
    178        1.19    dyoung 		space = ireq->i_len;
    179   1.60.18.1      phil 	/* XXX assumes compatible layout */
    180   1.60.18.1      phil 	return copyout(&ic->ic_nchans, ireq->i_data, space);
    181        1.19    dyoung }
    182        1.19    dyoung 
    183        1.19    dyoung static int
    184   1.60.18.1      phil ieee80211_ioctl_getwpaie(struct ieee80211vap *vap,
    185   1.60.18.1      phil 	struct ieee80211req *ireq, int req)
    186        1.19    dyoung {
    187        1.19    dyoung 	struct ieee80211_node *ni;
    188   1.60.18.1      phil 	struct ieee80211req_wpaie2 *wpaie;
    189        1.19    dyoung 	int error;
    190        1.19    dyoung 
    191        1.19    dyoung 	if (ireq->i_len < IEEE80211_ADDR_LEN)
    192        1.19    dyoung 		return EINVAL;
    193   1.60.18.1      phil 	wpaie = IEEE80211_MALLOC(sizeof(*wpaie), M_TEMP,
    194   1.60.18.1      phil 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    195   1.60.18.1      phil 	if (wpaie == NULL)
    196   1.60.18.1      phil 		return ENOMEM;
    197   1.60.18.1      phil 	error = copyin(ireq->i_data, wpaie->wpa_macaddr, IEEE80211_ADDR_LEN);
    198        1.19    dyoung 	if (error != 0)
    199   1.60.18.1      phil 		goto bad;
    200   1.60.18.1      phil 	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, wpaie->wpa_macaddr);
    201   1.60.18.1      phil 	if (ni == NULL) {
    202   1.60.18.1      phil 		error = ENOENT;
    203   1.60.18.1      phil 		goto bad;
    204   1.60.18.1      phil 	}
    205   1.60.18.1      phil 	if (ni->ni_ies.wpa_ie != NULL) {
    206   1.60.18.1      phil 		int ielen = ni->ni_ies.wpa_ie[1] + 2;
    207   1.60.18.1      phil 		if (ielen > sizeof(wpaie->wpa_ie))
    208   1.60.18.1      phil 			ielen = sizeof(wpaie->wpa_ie);
    209   1.60.18.1      phil 		memcpy(wpaie->wpa_ie, ni->ni_ies.wpa_ie, ielen);
    210   1.60.18.1      phil 	}
    211   1.60.18.1      phil 	if (req == IEEE80211_IOC_WPAIE2) {
    212   1.60.18.1      phil 		if (ni->ni_ies.rsn_ie != NULL) {
    213   1.60.18.1      phil 			int ielen = ni->ni_ies.rsn_ie[1] + 2;
    214   1.60.18.1      phil 			if (ielen > sizeof(wpaie->rsn_ie))
    215   1.60.18.1      phil 				ielen = sizeof(wpaie->rsn_ie);
    216   1.60.18.1      phil 			memcpy(wpaie->rsn_ie, ni->ni_ies.rsn_ie, ielen);
    217   1.60.18.1      phil 		}
    218   1.60.18.1      phil 		if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
    219   1.60.18.1      phil 			ireq->i_len = sizeof(struct ieee80211req_wpaie2);
    220   1.60.18.1      phil 	} else {
    221   1.60.18.1      phil 		/* compatibility op, may overwrite wpa ie */
    222   1.60.18.1      phil 		/* XXX check ic_flags? */
    223   1.60.18.1      phil 		if (ni->ni_ies.rsn_ie != NULL) {
    224   1.60.18.1      phil 			int ielen = ni->ni_ies.rsn_ie[1] + 2;
    225   1.60.18.1      phil 			if (ielen > sizeof(wpaie->wpa_ie))
    226   1.60.18.1      phil 				ielen = sizeof(wpaie->wpa_ie);
    227   1.60.18.1      phil 			memcpy(wpaie->wpa_ie, ni->ni_ies.rsn_ie, ielen);
    228   1.60.18.1      phil 		}
    229   1.60.18.1      phil 		if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
    230   1.60.18.1      phil 			ireq->i_len = sizeof(struct ieee80211req_wpaie);
    231        1.19    dyoung 	}
    232        1.19    dyoung 	ieee80211_free_node(ni);
    233   1.60.18.1      phil 	error = copyout(wpaie, ireq->i_data, ireq->i_len);
    234   1.60.18.1      phil bad:
    235   1.60.18.1      phil 	IEEE80211_FREE(wpaie, M_TEMP);
    236   1.60.18.1      phil 	return error;
    237        1.19    dyoung }
    238        1.19    dyoung 
    239        1.19    dyoung static int
    240   1.60.18.1      phil ieee80211_ioctl_getstastats(struct ieee80211vap *vap, struct ieee80211req *ireq)
    241        1.19    dyoung {
    242        1.19    dyoung 	struct ieee80211_node *ni;
    243   1.60.18.1      phil 	uint8_t macaddr[IEEE80211_ADDR_LEN];
    244   1.60.18.1      phil 	const size_t off = __offsetof(struct ieee80211req_sta_stats, is_stats);
    245        1.19    dyoung 	int error;
    246        1.19    dyoung 
    247        1.19    dyoung 	if (ireq->i_len < off)
    248        1.19    dyoung 		return EINVAL;
    249        1.19    dyoung 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
    250        1.19    dyoung 	if (error != 0)
    251        1.19    dyoung 		return error;
    252   1.60.18.1      phil 	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
    253        1.19    dyoung 	if (ni == NULL)
    254   1.60.18.1      phil 		return ENOENT;
    255        1.19    dyoung 	if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
    256        1.19    dyoung 		ireq->i_len = sizeof(struct ieee80211req_sta_stats);
    257        1.19    dyoung 	/* NB: copy out only the statistics */
    258   1.60.18.1      phil 	error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
    259        1.19    dyoung 			ireq->i_len - off);
    260        1.19    dyoung 	ieee80211_free_node(ni);
    261        1.19    dyoung 	return error;
    262        1.19    dyoung }
    263        1.19    dyoung 
    264   1.60.18.1      phil struct scanreq {
    265   1.60.18.1      phil 	struct ieee80211req_scan_result *sr;
    266   1.60.18.1      phil 	size_t space;
    267   1.60.18.1      phil };
    268        1.19    dyoung 
    269   1.60.18.1      phil static size_t
    270   1.60.18.1      phil scan_space(const struct ieee80211_scan_entry *se, int *ielen)
    271   1.60.18.1      phil {
    272   1.60.18.1      phil 	size_t len;
    273        1.28  christos 
    274   1.60.18.1      phil 	*ielen = se->se_ies.len;
    275        1.28  christos 	/*
    276   1.60.18.1      phil 	 * NB: ie's can be no more than 255 bytes and the max 802.11
    277   1.60.18.1      phil 	 * packet is <3Kbytes so we are sure this doesn't overflow
    278   1.60.18.1      phil 	 * 16-bits; if this is a concern we can drop the ie's.
    279        1.28  christos 	 */
    280   1.60.18.1      phil 	len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] +
    281   1.60.18.1      phil 	    se->se_meshid[1] + *ielen;
    282   1.60.18.1      phil 	return roundup(len, sizeof(uint32_t));
    283   1.60.18.1      phil }
    284   1.60.18.1      phil 
    285   1.60.18.1      phil static void
    286   1.60.18.1      phil get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
    287   1.60.18.1      phil {
    288   1.60.18.1      phil 	struct scanreq *req = arg;
    289   1.60.18.1      phil 	int ielen;
    290   1.60.18.1      phil 
    291   1.60.18.1      phil 	req->space += scan_space(se, &ielen);
    292   1.60.18.1      phil }
    293   1.60.18.1      phil 
    294   1.60.18.1      phil static void
    295   1.60.18.1      phil get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
    296   1.60.18.1      phil {
    297   1.60.18.1      phil 	struct scanreq *req = arg;
    298   1.60.18.1      phil 	struct ieee80211req_scan_result *sr;
    299   1.60.18.1      phil 	int ielen, len, nr, nxr;
    300   1.60.18.1      phil 	uint8_t *cp;
    301   1.60.18.1      phil 
    302   1.60.18.1      phil 	len = scan_space(se, &ielen);
    303   1.60.18.1      phil 	if (len > req->space)
    304   1.60.18.1      phil 		return;
    305   1.60.18.1      phil 
    306   1.60.18.1      phil 	sr = req->sr;
    307   1.60.18.1      phil 	KASSERT(len <= 65535 && ielen <= 65535,
    308   1.60.18.1      phil 	    ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
    309   1.60.18.1      phil 	sr->isr_len = len;
    310   1.60.18.1      phil 	sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
    311        1.28  christos 	sr->isr_ie_len = ielen;
    312   1.60.18.1      phil 	sr->isr_freq = se->se_chan->ic_freq;
    313   1.60.18.1      phil 	sr->isr_flags = se->se_chan->ic_flags;
    314   1.60.18.1      phil 	sr->isr_rssi = se->se_rssi;
    315   1.60.18.1      phil 	sr->isr_noise = se->se_noise;
    316   1.60.18.1      phil 	sr->isr_intval = se->se_intval;
    317   1.60.18.1      phil 	sr->isr_capinfo = se->se_capinfo;
    318   1.60.18.1      phil 	sr->isr_erp = se->se_erp;
    319   1.60.18.1      phil 	IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
    320   1.60.18.8  christos 	nr = uimin(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
    321   1.60.18.1      phil 	memcpy(sr->isr_rates, se->se_rates+2, nr);
    322   1.60.18.8  christos 	nxr = uimin(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
    323   1.60.18.1      phil 	memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
    324   1.60.18.1      phil 	sr->isr_nrates = nr + nxr;
    325   1.60.18.1      phil 
    326   1.60.18.1      phil 	/* copy SSID */
    327   1.60.18.1      phil 	sr->isr_ssid_len = se->se_ssid[1];
    328   1.60.18.1      phil 	cp = ((uint8_t *)sr) + sr->isr_ie_off;
    329   1.60.18.1      phil 	memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
    330   1.60.18.1      phil 
    331   1.60.18.1      phil 	/* copy mesh id */
    332   1.60.18.1      phil 	cp += sr->isr_ssid_len;
    333   1.60.18.1      phil 	sr->isr_meshid_len = se->se_meshid[1];
    334   1.60.18.1      phil 	memcpy(cp, se->se_meshid+2, sr->isr_meshid_len);
    335   1.60.18.1      phil 	cp += sr->isr_meshid_len;
    336   1.60.18.1      phil 
    337   1.60.18.1      phil 	if (ielen)
    338   1.60.18.1      phil 		memcpy(cp, se->se_ies.data, ielen);
    339   1.60.18.1      phil 
    340   1.60.18.1      phil 	req->space -= len;
    341   1.60.18.1      phil 	req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
    342        1.19    dyoung }
    343        1.19    dyoung 
    344        1.19    dyoung static int
    345   1.60.18.1      phil ieee80211_ioctl_getscanresults(struct ieee80211vap *vap,
    346   1.60.18.1      phil 	struct ieee80211req *ireq)
    347   1.60.18.1      phil {
    348   1.60.18.1      phil 	struct scanreq req;
    349        1.56  christos 	int error;
    350        1.19    dyoung 
    351   1.60.18.1      phil 	if (ireq->i_len < sizeof(struct scanreq))
    352   1.60.18.1      phil 		return EFAULT;
    353   1.60.18.1      phil 
    354        1.19    dyoung 	error = 0;
    355   1.60.18.1      phil 	req.space = 0;
    356   1.60.18.1      phil 	ieee80211_scan_iterate(vap, get_scan_space, &req);
    357   1.60.18.1      phil 	if (req.space > ireq->i_len)
    358   1.60.18.1      phil 		req.space = ireq->i_len;
    359   1.60.18.1      phil 	if (req.space > 0) {
    360   1.60.18.1      phil 		uint32_t space;
    361   1.60.18.1      phil 		void *p;
    362   1.60.18.1      phil 
    363   1.60.18.1      phil 		space = req.space;
    364   1.60.18.1      phil 		/* XXX M_WAITOK after driver lock released */
    365   1.60.18.1      phil 		p = IEEE80211_MALLOC(space, M_TEMP,
    366   1.60.18.1      phil 		    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    367   1.60.18.1      phil 		if (p == NULL)
    368   1.60.18.1      phil 			return ENOMEM;
    369   1.60.18.1      phil 		req.sr = p;
    370   1.60.18.1      phil 		ieee80211_scan_iterate(vap, get_scan_result, &req);
    371   1.60.18.1      phil 		ireq->i_len = space - req.space;
    372   1.60.18.1      phil 		error = copyout(p, ireq->i_data, ireq->i_len);
    373   1.60.18.1      phil 		IEEE80211_FREE(p, M_TEMP);
    374   1.60.18.1      phil 	} else
    375   1.60.18.1      phil 		ireq->i_len = 0;
    376   1.60.18.1      phil 
    377        1.19    dyoung 	return error;
    378        1.19    dyoung }
    379        1.19    dyoung 
    380   1.60.18.7      phil #ifdef OLD_IEEE80211_IOC_SCAN_RESULTS
    381   1.60.18.7      phil /* Code to get the old version of scan results, for NetBSD 8.0 and earlier. */
    382   1.60.18.7      phil 
    383   1.60.18.7      phil static size_t
    384   1.60.18.7      phil old_scan_space(const struct ieee80211_scan_entry *se, int *ielen)
    385   1.60.18.7      phil {
    386   1.60.18.7      phil 	size_t len;
    387   1.60.18.7      phil 
    388   1.60.18.7      phil 	*ielen = se->se_ies.len;
    389   1.60.18.7      phil 	/*
    390   1.60.18.7      phil 	 * NB: ie's can be no more than 255 bytes and the max 802.11
    391   1.60.18.7      phil 	 * packet is <3Kbytes so we are sure this doesn't overflow
    392   1.60.18.7      phil 	 * 16-bits; if this is a concern we can drop the ie's.
    393   1.60.18.7      phil 	 */
    394   1.60.18.7      phil 	len = sizeof(struct old_ieee80211req_scan_result) + se->se_ssid[1] +
    395   1.60.18.7      phil 	    se->se_meshid[1] + *ielen;
    396   1.60.18.7      phil 	return roundup(len, sizeof(uint32_t));
    397   1.60.18.7      phil }
    398   1.60.18.7      phil 
    399   1.60.18.7      phil static void
    400   1.60.18.7      phil old_get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
    401   1.60.18.7      phil {
    402   1.60.18.7      phil 	struct scanreq *req = arg;
    403   1.60.18.7      phil 	int ielen;
    404   1.60.18.7      phil 
    405   1.60.18.7      phil 	req->space += old_scan_space(se, &ielen);
    406   1.60.18.7      phil }
    407   1.60.18.7      phil 
    408   1.60.18.7      phil static void
    409   1.60.18.7      phil old_get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
    410   1.60.18.7      phil {
    411   1.60.18.7      phil 	struct scanreq *req = arg;
    412   1.60.18.7      phil 	struct old_ieee80211req_scan_result *sr;
    413   1.60.18.7      phil 	int ielen, len, nr, nxr;
    414   1.60.18.7      phil 	uint8_t *cp;
    415   1.60.18.7      phil 
    416   1.60.18.7      phil 	len = old_scan_space(se, &ielen);
    417   1.60.18.7      phil 	if (len > req->space)
    418   1.60.18.7      phil 		return;
    419   1.60.18.7      phil 
    420   1.60.18.7      phil 	sr = (struct old_ieee80211req_scan_result *)req->sr;
    421   1.60.18.7      phil 	KASSERT(len <= 65535 && ielen <= 65535,
    422   1.60.18.7      phil 	    ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
    423   1.60.18.7      phil 	sr->isr_len = len;
    424   1.60.18.7      phil 	sr->isr_ie_len = ielen;
    425   1.60.18.7      phil 	sr->isr_freq = se->se_chan->ic_freq;
    426   1.60.18.7      phil 	sr->isr_flags = se->se_chan->ic_flags;
    427   1.60.18.7      phil 	sr->isr_rssi = se->se_rssi;
    428   1.60.18.7      phil 	sr->isr_noise = se->se_noise;
    429   1.60.18.7      phil 	sr->isr_intval = se->se_intval;
    430   1.60.18.7      phil 	sr->isr_capinfo = se->se_capinfo;
    431   1.60.18.7      phil 	sr->isr_erp = se->se_erp;
    432   1.60.18.7      phil 	IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
    433   1.60.18.8  christos 	nr = uimin(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
    434   1.60.18.7      phil 	memcpy(sr->isr_rates, se->se_rates+2, nr);
    435   1.60.18.8  christos 	nxr = uimin(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
    436   1.60.18.7      phil 	memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
    437   1.60.18.7      phil 	sr->isr_nrates = nr + nxr;
    438   1.60.18.7      phil 	if (sr->isr_nrates > 15)
    439   1.60.18.7      phil 		sr->isr_nrates = 15;
    440   1.60.18.7      phil 
    441   1.60.18.7      phil 	printf ("old_get_scan_results: ssid=%.*s\n", se->se_ssid[1], &se->se_ssid[2]);
    442   1.60.18.7      phil 
    443   1.60.18.7      phil 	/* copy SSID */
    444   1.60.18.7      phil 	sr->isr_ssid_len = se->se_ssid[1];
    445   1.60.18.7      phil 	cp = ((uint8_t *)sr) + sizeof(struct old_ieee80211req_scan_result);
    446   1.60.18.7      phil 	memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
    447   1.60.18.7      phil 
    448   1.60.18.7      phil 	if (ielen)
    449   1.60.18.7      phil 		memcpy(cp+sr->isr_ssid_len, se->se_ies.data, ielen);
    450   1.60.18.7      phil 
    451   1.60.18.7      phil 	req->space -= len;
    452   1.60.18.7      phil 	req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
    453   1.60.18.7      phil }
    454   1.60.18.7      phil 
    455   1.60.18.7      phil static int
    456   1.60.18.7      phil old_ieee80211_ioctl_getscanresults(struct ieee80211vap *vap,
    457   1.60.18.7      phil 	struct ieee80211req *ireq)
    458   1.60.18.7      phil {
    459   1.60.18.7      phil 	struct scanreq req;
    460   1.60.18.7      phil 	int error;
    461   1.60.18.7      phil 
    462   1.60.18.7      phil 	if (ireq->i_len < sizeof(struct scanreq))
    463   1.60.18.7      phil 		return EFAULT;
    464   1.60.18.7      phil 
    465   1.60.18.7      phil 	error = 0;
    466   1.60.18.7      phil 	req.space = 0;
    467   1.60.18.7      phil 	ieee80211_scan_iterate(vap, old_get_scan_space, &req);
    468   1.60.18.7      phil 	if (req.space > ireq->i_len)
    469   1.60.18.7      phil 		req.space = ireq->i_len;
    470   1.60.18.7      phil 	if (req.space > 0) {
    471   1.60.18.7      phil 		uint32_t space;
    472   1.60.18.7      phil 		void *p;
    473   1.60.18.7      phil 
    474   1.60.18.7      phil 		space = req.space;
    475   1.60.18.7      phil 		/* XXX M_WAITOK after driver lock released */
    476   1.60.18.7      phil 		p = IEEE80211_MALLOC(space, M_TEMP,
    477   1.60.18.7      phil 		    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    478   1.60.18.7      phil 		if (p == NULL)
    479   1.60.18.7      phil 			return ENOMEM;
    480   1.60.18.7      phil 		req.sr = p;
    481   1.60.18.7      phil 		ieee80211_scan_iterate(vap, old_get_scan_result, &req);
    482   1.60.18.7      phil 		ireq->i_len = space - req.space;
    483   1.60.18.7      phil 		error = copyout(p, ireq->i_data, ireq->i_len);
    484   1.60.18.7      phil 		IEEE80211_FREE(p, M_TEMP);
    485   1.60.18.7      phil 	} else
    486   1.60.18.7      phil 		ireq->i_len = 0;
    487   1.60.18.7      phil 
    488   1.60.18.7      phil 	return error;
    489   1.60.18.7      phil }
    490   1.60.18.7      phil 
    491   1.60.18.7      phil #endif
    492   1.60.18.7      phil 
    493        1.26     skrll struct stainforeq {
    494        1.26     skrll 	struct ieee80211req_sta_info *si;
    495        1.26     skrll 	size_t	space;
    496        1.26     skrll };
    497        1.26     skrll 
    498        1.26     skrll static size_t
    499        1.26     skrll sta_space(const struct ieee80211_node *ni, size_t *ielen)
    500        1.26     skrll {
    501   1.60.18.1      phil 	*ielen = ni->ni_ies.len;
    502        1.26     skrll 	return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
    503   1.60.18.1      phil 		      sizeof(uint32_t));
    504        1.26     skrll }
    505        1.26     skrll 
    506        1.19    dyoung static void
    507        1.26     skrll get_sta_space(void *arg, struct ieee80211_node *ni)
    508        1.19    dyoung {
    509        1.26     skrll 	struct stainforeq *req = arg;
    510        1.26     skrll 	size_t ielen;
    511        1.19    dyoung 
    512   1.60.18.1      phil 	if (ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP &&
    513        1.26     skrll 	    ni->ni_associd == 0)	/* only associated stations */
    514        1.26     skrll 		return;
    515        1.26     skrll 	req->space += sta_space(ni, &ielen);
    516        1.26     skrll }
    517        1.26     skrll 
    518        1.26     skrll static void
    519        1.26     skrll get_sta_info(void *arg, struct ieee80211_node *ni)
    520        1.26     skrll {
    521        1.26     skrll 	struct stainforeq *req = arg;
    522   1.60.18.1      phil 	struct ieee80211vap *vap = ni->ni_vap;
    523        1.26     skrll 	struct ieee80211req_sta_info *si;
    524        1.26     skrll 	size_t ielen, len;
    525   1.60.18.1      phil 	uint8_t *cp;
    526        1.26     skrll 
    527   1.60.18.1      phil 	if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
    528        1.26     skrll 	    ni->ni_associd == 0)	/* only associated stations */
    529        1.26     skrll 		return;
    530        1.26     skrll 	if (ni->ni_chan == IEEE80211_CHAN_ANYC)	/* XXX bogus entry */
    531        1.26     skrll 		return;
    532        1.26     skrll 	len = sta_space(ni, &ielen);
    533        1.26     skrll 	if (len > req->space)
    534        1.26     skrll 		return;
    535        1.26     skrll 	si = req->si;
    536        1.26     skrll 	si->isi_len = len;
    537   1.60.18.1      phil 	si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
    538        1.26     skrll 	si->isi_ie_len = ielen;
    539        1.19    dyoung 	si->isi_freq = ni->ni_chan->ic_freq;
    540        1.19    dyoung 	si->isi_flags = ni->ni_chan->ic_flags;
    541        1.19    dyoung 	si->isi_state = ni->ni_flags;
    542        1.19    dyoung 	si->isi_authmode = ni->ni_authmode;
    543   1.60.18.1      phil 	vap->iv_ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
    544   1.60.18.1      phil 	vap->iv_ic->ic_node_getmimoinfo(ni, &si->isi_mimo);
    545        1.19    dyoung 	si->isi_capinfo = ni->ni_capinfo;
    546        1.19    dyoung 	si->isi_erp = ni->ni_erp;
    547        1.19    dyoung 	IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
    548        1.19    dyoung 	si->isi_nrates = ni->ni_rates.rs_nrates;
    549        1.19    dyoung 	if (si->isi_nrates > 15)
    550        1.19    dyoung 		si->isi_nrates = 15;
    551        1.19    dyoung 	memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
    552        1.19    dyoung 	si->isi_txrate = ni->ni_txrate;
    553   1.60.18.1      phil 	if (si->isi_txrate & IEEE80211_RATE_MCS) {
    554   1.60.18.1      phil 		const struct ieee80211_mcs_rates *mcs =
    555   1.60.18.1      phil 		    &ieee80211_htrates[ni->ni_txrate &~ IEEE80211_RATE_MCS];
    556   1.60.18.1      phil 		if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
    557   1.60.18.1      phil 			if (ni->ni_flags & IEEE80211_NODE_SGI40)
    558   1.60.18.1      phil 				si->isi_txmbps = mcs->ht40_rate_800ns;
    559   1.60.18.1      phil 			else
    560   1.60.18.1      phil 				si->isi_txmbps = mcs->ht40_rate_400ns;
    561   1.60.18.1      phil 		} else {
    562   1.60.18.1      phil 			if (ni->ni_flags & IEEE80211_NODE_SGI20)
    563   1.60.18.1      phil 				si->isi_txmbps = mcs->ht20_rate_800ns;
    564   1.60.18.1      phil 			else
    565   1.60.18.1      phil 				si->isi_txmbps = mcs->ht20_rate_400ns;
    566   1.60.18.1      phil 		}
    567   1.60.18.1      phil 	} else
    568   1.60.18.1      phil 		si->isi_txmbps = si->isi_txrate;
    569        1.19    dyoung 	si->isi_associd = ni->ni_associd;
    570        1.19    dyoung 	si->isi_txpower = ni->ni_txpower;
    571        1.19    dyoung 	si->isi_vlan = ni->ni_vlan;
    572        1.19    dyoung 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
    573        1.19    dyoung 		memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
    574        1.19    dyoung 		memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
    575        1.19    dyoung 	} else {
    576   1.60.18.1      phil 		si->isi_txseqs[0] = ni->ni_txseqs[IEEE80211_NONQOS_TID];
    577   1.60.18.1      phil 		si->isi_rxseqs[0] = ni->ni_rxseqs[IEEE80211_NONQOS_TID];
    578        1.19    dyoung 	}
    579        1.26     skrll 	/* NB: leave all cases in case we relax ni_associd == 0 check */
    580        1.26     skrll 	if (ieee80211_node_is_authorized(ni))
    581   1.60.18.1      phil 		si->isi_inact = vap->iv_inact_run;
    582   1.60.18.1      phil 	else if (ni->ni_associd != 0 ||
    583   1.60.18.1      phil 	    (vap->iv_opmode == IEEE80211_M_WDS &&
    584   1.60.18.1      phil 	     (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)))
    585   1.60.18.1      phil 		si->isi_inact = vap->iv_inact_auth;
    586        1.19    dyoung 	else
    587   1.60.18.1      phil 		si->isi_inact = vap->iv_inact_init;
    588        1.19    dyoung 	si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
    589   1.60.18.1      phil 	si->isi_localid = ni->ni_mllid;
    590   1.60.18.1      phil 	si->isi_peerid = ni->ni_mlpid;
    591   1.60.18.1      phil 	si->isi_peerstate = ni->ni_mlstate;
    592        1.26     skrll 
    593   1.60.18.1      phil 	if (ielen) {
    594   1.60.18.1      phil 		cp = ((uint8_t *)si) + si->isi_ie_off;
    595   1.60.18.1      phil 		memcpy(cp, ni->ni_ies.data, ielen);
    596        1.26     skrll 	}
    597        1.26     skrll 
    598   1.60.18.1      phil 	req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
    599        1.26     skrll 	req->space -= len;
    600        1.19    dyoung }
    601        1.19    dyoung 
    602        1.19    dyoung static int
    603   1.60.18.1      phil getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq,
    604   1.60.18.1      phil 	struct ieee80211_node *ni, size_t off)
    605        1.19    dyoung {
    606   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    607        1.26     skrll 	struct stainforeq req;
    608   1.60.18.1      phil 	size_t space;
    609   1.60.18.1      phil 	void *p;
    610        1.26     skrll 	int error;
    611        1.26     skrll 
    612        1.19    dyoung 	error = 0;
    613        1.26     skrll 	req.space = 0;
    614   1.60.18.1      phil 	if (ni == NULL) {
    615   1.60.18.1      phil 		ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_sta_space,
    616   1.60.18.1      phil 		    &req);
    617   1.60.18.1      phil 	} else
    618   1.60.18.1      phil 		get_sta_space(&req, ni);
    619        1.26     skrll 	if (req.space > ireq->i_len)
    620        1.26     skrll 		req.space = ireq->i_len;
    621        1.26     skrll 	if (req.space > 0) {
    622        1.26     skrll 		space = req.space;
    623        1.26     skrll 		/* XXX M_WAITOK after driver lock released */
    624   1.60.18.1      phil 		p = IEEE80211_MALLOC(space, M_TEMP,
    625   1.60.18.1      phil 		    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    626   1.60.18.1      phil 		if (p == NULL) {
    627   1.60.18.1      phil 			error = ENOMEM;
    628   1.60.18.1      phil 			goto bad;
    629   1.60.18.1      phil 		}
    630        1.26     skrll 		req.si = p;
    631   1.60.18.1      phil 		if (ni == NULL) {
    632   1.60.18.1      phil 			ieee80211_iterate_nodes_vap(&ic->ic_sta, vap,
    633   1.60.18.1      phil 			    get_sta_info, &req);
    634   1.60.18.1      phil 		} else
    635   1.60.18.1      phil 			get_sta_info(&req, ni);
    636        1.26     skrll 		ireq->i_len = space - req.space;
    637   1.60.18.1      phil 		error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
    638   1.60.18.1      phil 		IEEE80211_FREE(p, M_TEMP);
    639        1.26     skrll 	} else
    640        1.26     skrll 		ireq->i_len = 0;
    641   1.60.18.1      phil bad:
    642   1.60.18.1      phil 	if (ni != NULL)
    643   1.60.18.1      phil 		ieee80211_free_node(ni);
    644   1.60.18.1      phil 	return error;
    645   1.60.18.1      phil }
    646   1.60.18.1      phil 
    647   1.60.18.1      phil static int
    648   1.60.18.1      phil ieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq)
    649   1.60.18.1      phil {
    650   1.60.18.1      phil 	uint8_t macaddr[IEEE80211_ADDR_LEN];
    651   1.60.18.1      phil 	const size_t off = __offsetof(struct ieee80211req_sta_req, info);
    652   1.60.18.1      phil 	struct ieee80211_node *ni;
    653   1.60.18.1      phil 	int error;
    654   1.60.18.1      phil 
    655   1.60.18.1      phil 	if (ireq->i_len < sizeof(struct ieee80211req_sta_req))
    656   1.60.18.1      phil 		return EFAULT;
    657   1.60.18.1      phil 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
    658   1.60.18.1      phil 	if (error != 0)
    659   1.60.18.1      phil 		return error;
    660   1.60.18.1      phil 	if (IEEE80211_ADDR_EQ(macaddr, vap->iv_ifp->if_broadcastaddr)) {
    661   1.60.18.1      phil 		ni = NULL;
    662   1.60.18.1      phil 	} else {
    663   1.60.18.1      phil 		ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
    664   1.60.18.1      phil 		if (ni == NULL)
    665   1.60.18.1      phil 			return ENOENT;
    666   1.60.18.1      phil 	}
    667   1.60.18.1      phil 	return getstainfo_common(vap, ireq, ni, off);
    668        1.19    dyoung }
    669        1.19    dyoung 
    670        1.19    dyoung static int
    671   1.60.18.1      phil ieee80211_ioctl_getstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq)
    672        1.19    dyoung {
    673        1.19    dyoung 	struct ieee80211_node *ni;
    674        1.19    dyoung 	struct ieee80211req_sta_txpow txpow;
    675        1.19    dyoung 	int error;
    676        1.19    dyoung 
    677        1.19    dyoung 	if (ireq->i_len != sizeof(txpow))
    678        1.19    dyoung 		return EINVAL;
    679        1.19    dyoung 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
    680        1.19    dyoung 	if (error != 0)
    681        1.19    dyoung 		return error;
    682   1.60.18.1      phil 	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, txpow.it_macaddr);
    683        1.19    dyoung 	if (ni == NULL)
    684   1.60.18.1      phil 		return ENOENT;
    685        1.19    dyoung 	txpow.it_txpow = ni->ni_txpower;
    686        1.19    dyoung 	error = copyout(&txpow, ireq->i_data, sizeof(txpow));
    687        1.19    dyoung 	ieee80211_free_node(ni);
    688         1.1    dyoung 	return error;
    689         1.1    dyoung }
    690         1.1    dyoung 
    691        1.19    dyoung static int
    692   1.60.18.1      phil ieee80211_ioctl_getwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq)
    693        1.19    dyoung {
    694   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    695        1.19    dyoung 	struct ieee80211_wme_state *wme = &ic->ic_wme;
    696        1.19    dyoung 	struct wmeParams *wmep;
    697        1.19    dyoung 	int ac;
    698        1.19    dyoung 
    699        1.19    dyoung 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
    700        1.19    dyoung 		return EINVAL;
    701        1.19    dyoung 
    702        1.19    dyoung 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
    703        1.19    dyoung 	if (ac >= WME_NUM_AC)
    704        1.19    dyoung 		ac = WME_AC_BE;
    705        1.19    dyoung 	if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
    706        1.19    dyoung 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
    707        1.19    dyoung 	else
    708        1.19    dyoung 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
    709        1.19    dyoung 	switch (ireq->i_type) {
    710        1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
    711        1.19    dyoung 		ireq->i_val = wmep->wmep_logcwmin;
    712        1.19    dyoung 		break;
    713        1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
    714        1.19    dyoung 		ireq->i_val = wmep->wmep_logcwmax;
    715        1.19    dyoung 		break;
    716        1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
    717        1.19    dyoung 		ireq->i_val = wmep->wmep_aifsn;
    718        1.19    dyoung 		break;
    719        1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
    720        1.19    dyoung 		ireq->i_val = wmep->wmep_txopLimit;
    721        1.19    dyoung 		break;
    722        1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
    723        1.19    dyoung 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
    724        1.19    dyoung 		ireq->i_val = wmep->wmep_acm;
    725        1.19    dyoung 		break;
    726        1.19    dyoung 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
    727        1.19    dyoung 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
    728        1.19    dyoung 		ireq->i_val = !wmep->wmep_noackPolicy;
    729        1.19    dyoung 		break;
    730        1.19    dyoung 	}
    731        1.19    dyoung 	return 0;
    732        1.19    dyoung }
    733        1.19    dyoung 
    734        1.26     skrll static int
    735   1.60.18.1      phil ieee80211_ioctl_getmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq)
    736   1.60.18.1      phil {
    737   1.60.18.1      phil 	const struct ieee80211_aclator *acl = vap->iv_acl;
    738   1.60.18.1      phil 
    739   1.60.18.1      phil 	return (acl == NULL ? EINVAL : acl->iac_getioctl(vap, ireq));
    740   1.60.18.1      phil }
    741   1.60.18.1      phil 
    742   1.60.18.1      phil static int
    743   1.60.18.1      phil ieee80211_ioctl_getcurchan(struct ieee80211vap *vap, struct ieee80211req *ireq)
    744   1.60.18.1      phil {
    745   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    746   1.60.18.1      phil 	struct ieee80211_channel *c;
    747   1.60.18.1      phil 
    748   1.60.18.1      phil 	if (ireq->i_len != sizeof(struct ieee80211_channel))
    749   1.60.18.1      phil 		return EINVAL;
    750   1.60.18.1      phil 	/*
    751   1.60.18.1      phil 	 * vap's may have different operating channels when HT is
    752   1.60.18.1      phil 	 * in use.  When in RUN state report the vap-specific channel.
    753   1.60.18.1      phil 	 * Otherwise return curchan.
    754   1.60.18.1      phil 	 */
    755   1.60.18.1      phil 	if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)
    756   1.60.18.1      phil 		c = vap->iv_bss->ni_chan;
    757   1.60.18.1      phil 	else
    758   1.60.18.1      phil 		c = ic->ic_curchan;
    759   1.60.18.1      phil 	return copyout(c, ireq->i_data, sizeof(*c));
    760   1.60.18.1      phil }
    761   1.60.18.1      phil 
    762   1.60.18.1      phil static int
    763   1.60.18.1      phil getappie(const struct ieee80211_appie *aie, struct ieee80211req *ireq)
    764   1.60.18.1      phil {
    765   1.60.18.1      phil 	if (aie == NULL)
    766   1.60.18.1      phil 		return EINVAL;
    767   1.60.18.1      phil 	/* NB: truncate, caller can check length */
    768   1.60.18.1      phil 	if (ireq->i_len > aie->ie_len)
    769   1.60.18.1      phil 		ireq->i_len = aie->ie_len;
    770   1.60.18.1      phil 	return copyout(aie->ie_data, ireq->i_data, ireq->i_len);
    771   1.60.18.1      phil }
    772   1.60.18.1      phil 
    773   1.60.18.1      phil static int
    774   1.60.18.1      phil ieee80211_ioctl_getappie(struct ieee80211vap *vap, struct ieee80211req *ireq)
    775   1.60.18.1      phil {
    776   1.60.18.1      phil 	uint8_t fc0;
    777   1.60.18.1      phil 
    778   1.60.18.1      phil 	fc0 = ireq->i_val & 0xff;
    779   1.60.18.1      phil 	if ((fc0 & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
    780   1.60.18.1      phil 		return EINVAL;
    781   1.60.18.1      phil 	/* NB: could check iv_opmode and reject but hardly worth the effort */
    782   1.60.18.1      phil 	switch (fc0 & IEEE80211_FC0_SUBTYPE_MASK) {
    783   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_BEACON:
    784   1.60.18.1      phil 		return getappie(vap->iv_appie_beacon, ireq);
    785   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
    786   1.60.18.1      phil 		return getappie(vap->iv_appie_proberesp, ireq);
    787   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
    788   1.60.18.1      phil 		return getappie(vap->iv_appie_assocresp, ireq);
    789   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
    790   1.60.18.1      phil 		return getappie(vap->iv_appie_probereq, ireq);
    791   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
    792   1.60.18.1      phil 		return getappie(vap->iv_appie_assocreq, ireq);
    793   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_BEACON|IEEE80211_FC0_SUBTYPE_PROBE_RESP:
    794   1.60.18.1      phil 		return getappie(vap->iv_appie_wpa, ireq);
    795   1.60.18.1      phil 	}
    796   1.60.18.1      phil 	return EINVAL;
    797   1.60.18.1      phil }
    798   1.60.18.1      phil 
    799   1.60.18.1      phil static int
    800   1.60.18.1      phil ieee80211_ioctl_getregdomain(struct ieee80211vap *vap,
    801   1.60.18.1      phil 	const struct ieee80211req *ireq)
    802   1.60.18.1      phil {
    803   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    804   1.60.18.1      phil 
    805   1.60.18.1      phil 	if (ireq->i_len != sizeof(ic->ic_regdomain))
    806   1.60.18.1      phil 		return EINVAL;
    807   1.60.18.1      phil 	return copyout(&ic->ic_regdomain, ireq->i_data,
    808   1.60.18.1      phil 	    sizeof(ic->ic_regdomain));
    809   1.60.18.1      phil }
    810   1.60.18.1      phil 
    811   1.60.18.1      phil static int
    812   1.60.18.1      phil ieee80211_ioctl_getroam(struct ieee80211vap *vap,
    813   1.60.18.1      phil 	const struct ieee80211req *ireq)
    814   1.60.18.1      phil {
    815   1.60.18.1      phil 	size_t len = ireq->i_len;
    816   1.60.18.1      phil 	/* NB: accept short requests for backwards compat */
    817   1.60.18.1      phil 	if (len > sizeof(vap->iv_roamparms))
    818   1.60.18.1      phil 		len = sizeof(vap->iv_roamparms);
    819   1.60.18.1      phil 	return copyout(vap->iv_roamparms, ireq->i_data, len);
    820   1.60.18.1      phil }
    821   1.60.18.1      phil 
    822   1.60.18.1      phil static int
    823   1.60.18.1      phil ieee80211_ioctl_gettxparams(struct ieee80211vap *vap,
    824   1.60.18.1      phil 	const struct ieee80211req *ireq)
    825   1.60.18.1      phil {
    826   1.60.18.1      phil 	size_t len = ireq->i_len;
    827   1.60.18.1      phil 	/* NB: accept short requests for backwards compat */
    828   1.60.18.1      phil 	if (len > sizeof(vap->iv_txparms))
    829   1.60.18.1      phil 		len = sizeof(vap->iv_txparms);
    830   1.60.18.1      phil 	return copyout(vap->iv_txparms, ireq->i_data, len);
    831   1.60.18.1      phil }
    832   1.60.18.1      phil 
    833   1.60.18.1      phil static int
    834   1.60.18.1      phil ieee80211_ioctl_getdevcaps(struct ieee80211com *ic,
    835   1.60.18.1      phil 	const struct ieee80211req *ireq)
    836   1.60.18.1      phil {
    837   1.60.18.1      phil 	struct ieee80211_devcaps_req *dc;
    838   1.60.18.1      phil 	struct ieee80211req_chaninfo *ci;
    839   1.60.18.1      phil 	int maxchans, error;
    840   1.60.18.1      phil 
    841   1.60.18.1      phil 	maxchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_devcaps_req)) /
    842   1.60.18.1      phil 	    sizeof(struct ieee80211_channel));
    843   1.60.18.1      phil 	/* NB: require 1 so we know ic_nchans is accessible */
    844   1.60.18.1      phil 	if (maxchans < 1)
    845   1.60.18.1      phil 		return EINVAL;
    846   1.60.18.1      phil 	/* constrain max request size, 2K channels is ~24Kbytes */
    847   1.60.18.1      phil 	if (maxchans > 2048)
    848   1.60.18.1      phil 		maxchans = 2048;
    849   1.60.18.1      phil 	dc = (struct ieee80211_devcaps_req *)
    850   1.60.18.1      phil 	    IEEE80211_MALLOC(IEEE80211_DEVCAPS_SIZE(maxchans), M_TEMP,
    851   1.60.18.1      phil 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    852   1.60.18.1      phil 	if (dc == NULL)
    853   1.60.18.1      phil 		return ENOMEM;
    854   1.60.18.1      phil 	dc->dc_drivercaps = ic->ic_caps;
    855   1.60.18.1      phil 	dc->dc_cryptocaps = ic->ic_cryptocaps;
    856   1.60.18.1      phil 	dc->dc_htcaps = ic->ic_htcaps;
    857   1.60.18.1      phil 	dc->dc_vhtcaps = ic->ic_vhtcaps;
    858   1.60.18.1      phil 	ci = &dc->dc_chaninfo;
    859   1.60.18.1      phil 	ic->ic_getradiocaps(ic, maxchans, &ci->ic_nchans, ci->ic_chans);
    860   1.60.18.1      phil 	KASSERT(ci->ic_nchans <= maxchans,
    861   1.60.18.1      phil 	    ("nchans %d maxchans %d", ci->ic_nchans, maxchans));
    862   1.60.18.1      phil 	ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans);
    863   1.60.18.1      phil 	error = copyout(dc, ireq->i_data, IEEE80211_DEVCAPS_SPACE(dc));
    864   1.60.18.1      phil 	IEEE80211_FREE(dc, M_TEMP);
    865   1.60.18.1      phil 	return error;
    866   1.60.18.1      phil }
    867   1.60.18.1      phil 
    868   1.60.18.1      phil static int
    869   1.60.18.1      phil ieee80211_ioctl_getstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
    870   1.60.18.1      phil {
    871   1.60.18.1      phil 	struct ieee80211_node *ni;
    872   1.60.18.1      phil 	struct ieee80211req_sta_vlan vlan;
    873   1.60.18.1      phil 	int error;
    874   1.60.18.1      phil 
    875   1.60.18.1      phil 	if (ireq->i_len != sizeof(vlan))
    876   1.60.18.1      phil 		return EINVAL;
    877   1.60.18.1      phil 	error = copyin(ireq->i_data, &vlan, sizeof(vlan));
    878   1.60.18.1      phil 	if (error != 0)
    879   1.60.18.1      phil 		return error;
    880   1.60.18.1      phil 	if (!IEEE80211_ADDR_EQ(vlan.sv_macaddr, zerobssid)) {
    881   1.60.18.1      phil 		ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
    882   1.60.18.1      phil 		    vlan.sv_macaddr);
    883   1.60.18.1      phil 		if (ni == NULL)
    884   1.60.18.1      phil 			return ENOENT;
    885   1.60.18.1      phil 	} else
    886   1.60.18.1      phil 		ni = ieee80211_ref_node(vap->iv_bss);
    887   1.60.18.1      phil 	vlan.sv_vlan = ni->ni_vlan;
    888   1.60.18.1      phil 	error = copyout(&vlan, ireq->i_data, sizeof(vlan));
    889   1.60.18.1      phil 	ieee80211_free_node(ni);
    890   1.60.18.1      phil 	return error;
    891   1.60.18.1      phil }
    892   1.60.18.1      phil 
    893   1.60.18.1      phil /*
    894   1.60.18.1      phil  * Dummy ioctl get handler so the linker set is defined.
    895   1.60.18.1      phil  */
    896   1.60.18.2      phil static __unused int
    897   1.60.18.1      phil dummy_ioctl_get(struct ieee80211vap *vap, struct ieee80211req *ireq)
    898   1.60.18.1      phil {
    899   1.60.18.1      phil 	return ENOSYS;
    900   1.60.18.1      phil }
    901   1.60.18.1      phil IEEE80211_IOCTL_GET(dummy, dummy_ioctl_get);
    902   1.60.18.1      phil 
    903   1.60.18.1      phil static int
    904   1.60.18.1      phil ieee80211_ioctl_getdefault(struct ieee80211vap *vap, struct ieee80211req *ireq)
    905        1.26     skrll {
    906   1.60.18.4      phil 	int error;
    907   1.60.18.3      phil #if notyet
    908   1.60.18.1      phil 	ieee80211_ioctl_getfunc * const *get;
    909        1.26     skrll 
    910   1.60.18.1      phil 	SET_FOREACH(get, ieee80211_ioctl_getset) {
    911   1.60.18.1      phil 		error = (*get)(vap, ireq);
    912   1.60.18.1      phil 		if (error != ENOSYS)
    913   1.60.18.1      phil 			return error;
    914   1.60.18.1      phil 	}
    915   1.60.18.3      phil #else
    916   1.60.18.4      phil 	printf ("ieee80211_ioctl_getdefault called\n");
    917   1.60.18.4      phil 	error = dummy_ioctl_get(vap, ireq);
    918   1.60.18.2      phil #endif
    919   1.60.18.4      phil 	return error;
    920        1.26     skrll }
    921        1.26     skrll 
    922        1.19    dyoung static int
    923   1.60.18.1      phil ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
    924        1.40  christos     struct ieee80211req *ireq)
    925         1.1    dyoung {
    926   1.60.18.1      phil #define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
    927   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
    928        1.23    dyoung 	u_int kid, len;
    929   1.60.18.1      phil 	uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
    930         1.1    dyoung 	char tmpssid[IEEE80211_NWID_LEN];
    931        1.44    dyoung 	int error = 0;
    932         1.1    dyoung 
    933        1.19    dyoung 	switch (ireq->i_type) {
    934        1.19    dyoung 	case IEEE80211_IOC_SSID:
    935   1.60.18.1      phil 		switch (vap->iv_state) {
    936        1.19    dyoung 		case IEEE80211_S_INIT:
    937        1.19    dyoung 		case IEEE80211_S_SCAN:
    938   1.60.18.1      phil 			ireq->i_len = vap->iv_des_ssid[0].len;
    939   1.60.18.1      phil 			memcpy(tmpssid, vap->iv_des_ssid[0].ssid, ireq->i_len);
    940         1.1    dyoung 			break;
    941        1.19    dyoung 		default:
    942   1.60.18.1      phil 			ireq->i_len = vap->iv_bss->ni_esslen;
    943   1.60.18.1      phil 			memcpy(tmpssid, vap->iv_bss->ni_essid, ireq->i_len);
    944         1.1    dyoung 			break;
    945        1.19    dyoung 		}
    946        1.19    dyoung 		error = copyout(tmpssid, ireq->i_data, ireq->i_len);
    947        1.19    dyoung 		break;
    948        1.19    dyoung 	case IEEE80211_IOC_NUMSSIDS:
    949        1.19    dyoung 		ireq->i_val = 1;
    950        1.19    dyoung 		break;
    951        1.19    dyoung 	case IEEE80211_IOC_WEP:
    952   1.60.18.1      phil 		if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0)
    953        1.19    dyoung 			ireq->i_val = IEEE80211_WEP_OFF;
    954   1.60.18.1      phil 		else if (vap->iv_flags & IEEE80211_F_DROPUNENC)
    955        1.19    dyoung 			ireq->i_val = IEEE80211_WEP_ON;
    956        1.19    dyoung 		else
    957        1.19    dyoung 			ireq->i_val = IEEE80211_WEP_MIXED;
    958        1.19    dyoung 		break;
    959        1.19    dyoung 	case IEEE80211_IOC_WEPKEY:
    960        1.19    dyoung 		kid = (u_int) ireq->i_val;
    961        1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
    962        1.19    dyoung 			return EINVAL;
    963   1.60.18.1      phil 		len = (u_int) vap->iv_nw_keys[kid].wk_keylen;
    964        1.19    dyoung 		/* NB: only root can read WEP keys */
    965   1.60.18.1      phil 		if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
    966   1.60.18.1      phil 			bcopy(vap->iv_nw_keys[kid].wk_key, tmpkey, len);
    967        1.19    dyoung 		} else {
    968   1.60.18.1      phil 			bzero(tmpkey, len);
    969        1.19    dyoung 		}
    970        1.19    dyoung 		ireq->i_len = len;
    971        1.19    dyoung 		error = copyout(tmpkey, ireq->i_data, len);
    972        1.19    dyoung 		break;
    973        1.19    dyoung 	case IEEE80211_IOC_NUMWEPKEYS:
    974        1.19    dyoung 		ireq->i_val = IEEE80211_WEP_NKID;
    975        1.19    dyoung 		break;
    976        1.19    dyoung 	case IEEE80211_IOC_WEPTXKEY:
    977   1.60.18.1      phil 		ireq->i_val = vap->iv_def_txkey;
    978   1.60.18.1      phil 		break;
    979   1.60.18.1      phil 	case IEEE80211_IOC_AUTHMODE:
    980   1.60.18.1      phil 		if (vap->iv_flags & IEEE80211_F_WPA)
    981   1.60.18.1      phil 			ireq->i_val = IEEE80211_AUTH_WPA;
    982   1.60.18.1      phil 		else
    983   1.60.18.1      phil 			ireq->i_val = vap->iv_bss->ni_authmode;
    984        1.19    dyoung 		break;
    985        1.19    dyoung 	case IEEE80211_IOC_CHANNEL:
    986        1.26     skrll 		ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
    987        1.19    dyoung 		break;
    988        1.19    dyoung 	case IEEE80211_IOC_POWERSAVE:
    989   1.60.18.1      phil 		if (vap->iv_flags & IEEE80211_F_PMGTON)
    990        1.19    dyoung 			ireq->i_val = IEEE80211_POWERSAVE_ON;
    991        1.19    dyoung 		else
    992        1.19    dyoung 			ireq->i_val = IEEE80211_POWERSAVE_OFF;
    993        1.19    dyoung 		break;
    994        1.19    dyoung 	case IEEE80211_IOC_POWERSAVESLEEP:
    995        1.19    dyoung 		ireq->i_val = ic->ic_lintval;
    996        1.19    dyoung 		break;
    997        1.19    dyoung 	case IEEE80211_IOC_RTSTHRESHOLD:
    998   1.60.18.1      phil 		ireq->i_val = vap->iv_rtsthreshold;
    999        1.19    dyoung 		break;
   1000        1.19    dyoung 	case IEEE80211_IOC_PROTMODE:
   1001        1.19    dyoung 		ireq->i_val = ic->ic_protmode;
   1002        1.19    dyoung 		break;
   1003        1.19    dyoung 	case IEEE80211_IOC_TXPOWER:
   1004   1.60.18.1      phil 		/*
   1005   1.60.18.1      phil 		 * Tx power limit is the min of max regulatory
   1006   1.60.18.1      phil 		 * power, any user-set limit, and the max the
   1007   1.60.18.1      phil 		 * radio can do.
   1008   1.60.18.1      phil 		 *
   1009   1.60.18.1      phil 		 * TODO: methodize this
   1010   1.60.18.1      phil 		 */
   1011   1.60.18.1      phil 		ireq->i_val = 2*ic->ic_curchan->ic_maxregpower;
   1012   1.60.18.1      phil 		if (ireq->i_val > ic->ic_txpowlimit)
   1013   1.60.18.1      phil 			ireq->i_val = ic->ic_txpowlimit;
   1014   1.60.18.1      phil 		if (ireq->i_val > ic->ic_curchan->ic_maxpower)
   1015   1.60.18.1      phil 			ireq->i_val = ic->ic_curchan->ic_maxpower;
   1016        1.19    dyoung 		break;
   1017        1.19    dyoung 	case IEEE80211_IOC_WPA:
   1018   1.60.18.1      phil 		switch (vap->iv_flags & IEEE80211_F_WPA) {
   1019        1.19    dyoung 		case IEEE80211_F_WPA1:
   1020        1.19    dyoung 			ireq->i_val = 1;
   1021        1.19    dyoung 			break;
   1022        1.19    dyoung 		case IEEE80211_F_WPA2:
   1023        1.19    dyoung 			ireq->i_val = 2;
   1024        1.19    dyoung 			break;
   1025        1.19    dyoung 		case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
   1026        1.19    dyoung 			ireq->i_val = 3;
   1027        1.19    dyoung 			break;
   1028        1.19    dyoung 		default:
   1029        1.19    dyoung 			ireq->i_val = 0;
   1030        1.19    dyoung 			break;
   1031        1.19    dyoung 		}
   1032        1.19    dyoung 		break;
   1033        1.19    dyoung 	case IEEE80211_IOC_CHANLIST:
   1034   1.60.18.1      phil 		error = ieee80211_ioctl_getchanlist(vap, ireq);
   1035        1.19    dyoung 		break;
   1036        1.19    dyoung 	case IEEE80211_IOC_ROAMING:
   1037   1.60.18.1      phil 		ireq->i_val = vap->iv_roaming;
   1038        1.19    dyoung 		break;
   1039        1.19    dyoung 	case IEEE80211_IOC_PRIVACY:
   1040   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_PRIVACY) != 0;
   1041        1.19    dyoung 		break;
   1042        1.19    dyoung 	case IEEE80211_IOC_DROPUNENCRYPTED:
   1043   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_DROPUNENC) != 0;
   1044        1.19    dyoung 		break;
   1045        1.19    dyoung 	case IEEE80211_IOC_COUNTERMEASURES:
   1046   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_COUNTERM) != 0;
   1047        1.19    dyoung 		break;
   1048        1.19    dyoung 	case IEEE80211_IOC_WME:
   1049   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_WME) != 0;
   1050        1.19    dyoung 		break;
   1051        1.19    dyoung 	case IEEE80211_IOC_HIDESSID:
   1052   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_HIDESSID) != 0;
   1053        1.19    dyoung 		break;
   1054        1.19    dyoung 	case IEEE80211_IOC_APBRIDGE:
   1055   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0;
   1056        1.19    dyoung 		break;
   1057        1.19    dyoung 	case IEEE80211_IOC_WPAKEY:
   1058   1.60.18.1      phil 		error = ieee80211_ioctl_getkey(vap, ireq);
   1059        1.19    dyoung 		break;
   1060        1.19    dyoung 	case IEEE80211_IOC_CHANINFO:
   1061   1.60.18.1      phil 		error = ieee80211_ioctl_getchaninfo(vap, ireq);
   1062   1.60.18.1      phil 		break;
   1063   1.60.18.1      phil 	case IEEE80211_IOC_BSSID:
   1064   1.60.18.1      phil 		if (ireq->i_len != IEEE80211_ADDR_LEN)
   1065   1.60.18.1      phil 			return EINVAL;
   1066   1.60.18.1      phil 		if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) {
   1067   1.60.18.1      phil 			error = copyout(vap->iv_opmode == IEEE80211_M_WDS ?
   1068   1.60.18.1      phil 			    vap->iv_bss->ni_macaddr : vap->iv_bss->ni_bssid,
   1069   1.60.18.1      phil 			    ireq->i_data, ireq->i_len);
   1070   1.60.18.1      phil 		} else
   1071   1.60.18.1      phil 			error = copyout(vap->iv_des_bssid, ireq->i_data,
   1072   1.60.18.1      phil 			    ireq->i_len);
   1073        1.19    dyoung 		break;
   1074        1.19    dyoung 	case IEEE80211_IOC_WPAIE:
   1075   1.60.18.1      phil 	case IEEE80211_IOC_WPAIE2:
   1076   1.60.18.1      phil 		error = ieee80211_ioctl_getwpaie(vap, ireq, ireq->i_type);
   1077        1.19    dyoung 		break;
   1078   1.60.18.7      phil #ifdef OLD_IEEE80211_IOC_SCAN_RESULTS
   1079   1.60.18.7      phil 	case OLD_IEEE80211_IOC_SCAN_RESULTS:
   1080   1.60.18.7      phil 		error = old_ieee80211_ioctl_getscanresults(vap, ireq);
   1081   1.60.18.7      phil 		break;
   1082   1.60.18.7      phil #endif
   1083        1.19    dyoung 	case IEEE80211_IOC_SCAN_RESULTS:
   1084   1.60.18.1      phil 		error = ieee80211_ioctl_getscanresults(vap, ireq);
   1085        1.19    dyoung 		break;
   1086        1.19    dyoung 	case IEEE80211_IOC_STA_STATS:
   1087   1.60.18.1      phil 		error = ieee80211_ioctl_getstastats(vap, ireq);
   1088        1.19    dyoung 		break;
   1089        1.19    dyoung 	case IEEE80211_IOC_TXPOWMAX:
   1090   1.60.18.1      phil 		ireq->i_val = vap->iv_bss->ni_txpower;
   1091        1.19    dyoung 		break;
   1092        1.19    dyoung 	case IEEE80211_IOC_STA_TXPOW:
   1093   1.60.18.1      phil 		error = ieee80211_ioctl_getstatxpow(vap, ireq);
   1094        1.19    dyoung 		break;
   1095        1.19    dyoung 	case IEEE80211_IOC_STA_INFO:
   1096   1.60.18.1      phil 		error = ieee80211_ioctl_getstainfo(vap, ireq);
   1097        1.19    dyoung 		break;
   1098        1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   1099        1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   1100        1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   1101        1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   1102        1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   1103   1.60.18.1      phil 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only) */
   1104   1.60.18.1      phil 		error = ieee80211_ioctl_getwmeparam(vap, ireq);
   1105        1.19    dyoung 		break;
   1106        1.19    dyoung 	case IEEE80211_IOC_DTIM_PERIOD:
   1107   1.60.18.1      phil 		ireq->i_val = vap->iv_dtim_period;
   1108        1.19    dyoung 		break;
   1109        1.19    dyoung 	case IEEE80211_IOC_BEACON_INTERVAL:
   1110        1.19    dyoung 		/* NB: get from ic_bss for station mode */
   1111   1.60.18.1      phil 		ireq->i_val = vap->iv_bss->ni_intval;
   1112        1.19    dyoung 		break;
   1113        1.21    dyoung 	case IEEE80211_IOC_PUREG:
   1114   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_PUREG) != 0;
   1115   1.60.18.1      phil 		break;
   1116   1.60.18.1      phil 	case IEEE80211_IOC_QUIET:
   1117   1.60.18.1      phil 		ireq->i_val = vap->iv_quiet;
   1118   1.60.18.1      phil 		break;
   1119   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_COUNT:
   1120   1.60.18.1      phil 		ireq->i_val = vap->iv_quiet_count;
   1121        1.21    dyoung 		break;
   1122   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_PERIOD:
   1123   1.60.18.1      phil 		ireq->i_val = vap->iv_quiet_period;
   1124   1.60.18.1      phil 		break;
   1125   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_DUR:
   1126   1.60.18.1      phil 		ireq->i_val = vap->iv_quiet_duration;
   1127   1.60.18.1      phil 		break;
   1128   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_OFFSET:
   1129   1.60.18.1      phil 		ireq->i_val = vap->iv_quiet_offset;
   1130   1.60.18.1      phil 		break;
   1131   1.60.18.1      phil 	case IEEE80211_IOC_BGSCAN:
   1132   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_BGSCAN) != 0;
   1133   1.60.18.1      phil 		break;
   1134   1.60.18.1      phil 	case IEEE80211_IOC_BGSCAN_IDLE:
   1135   1.60.18.1      phil 		ireq->i_val = vap->iv_bgscanidle*hz/1000;	/* ms */
   1136   1.60.18.1      phil 		break;
   1137   1.60.18.1      phil 	case IEEE80211_IOC_BGSCAN_INTERVAL:
   1138   1.60.18.1      phil 		ireq->i_val = vap->iv_bgscanintvl/hz;		/* seconds */
   1139   1.60.18.1      phil 		break;
   1140   1.60.18.1      phil 	case IEEE80211_IOC_SCANVALID:
   1141   1.60.18.1      phil 		ireq->i_val = vap->iv_scanvalid/hz;		/* seconds */
   1142        1.30    dyoung 		break;
   1143        1.26     skrll 	case IEEE80211_IOC_FRAGTHRESHOLD:
   1144   1.60.18.1      phil 		ireq->i_val = vap->iv_fragthreshold;
   1145        1.26     skrll 		break;
   1146        1.26     skrll 	case IEEE80211_IOC_MACCMD:
   1147   1.60.18.1      phil 		error = ieee80211_ioctl_getmaccmd(vap, ireq);
   1148        1.26     skrll 		break;
   1149   1.60.18.1      phil 	case IEEE80211_IOC_BURST:
   1150   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_BURST) != 0;
   1151   1.60.18.1      phil 		break;
   1152   1.60.18.1      phil 	case IEEE80211_IOC_BMISSTHRESHOLD:
   1153   1.60.18.1      phil 		ireq->i_val = vap->iv_bmissthreshold;
   1154   1.60.18.1      phil 		break;
   1155   1.60.18.1      phil 	case IEEE80211_IOC_CURCHAN:
   1156   1.60.18.1      phil 		error = ieee80211_ioctl_getcurchan(vap, ireq);
   1157   1.60.18.1      phil 		break;
   1158   1.60.18.1      phil 	case IEEE80211_IOC_SHORTGI:
   1159   1.60.18.1      phil 		ireq->i_val = 0;
   1160   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
   1161   1.60.18.1      phil 			ireq->i_val |= IEEE80211_HTCAP_SHORTGI20;
   1162   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
   1163   1.60.18.1      phil 			ireq->i_val |= IEEE80211_HTCAP_SHORTGI40;
   1164   1.60.18.1      phil 		break;
   1165   1.60.18.1      phil 	case IEEE80211_IOC_AMPDU:
   1166   1.60.18.1      phil 		ireq->i_val = 0;
   1167   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)
   1168   1.60.18.1      phil 			ireq->i_val |= 1;
   1169   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)
   1170   1.60.18.1      phil 			ireq->i_val |= 2;
   1171   1.60.18.1      phil 		break;
   1172   1.60.18.1      phil 	case IEEE80211_IOC_AMPDU_LIMIT:
   1173   1.60.18.1      phil 		/* XXX TODO: make this a per-node thing; and leave this as global */
   1174   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
   1175   1.60.18.1      phil 			ireq->i_val = vap->iv_ampdu_rxmax;
   1176   1.60.18.1      phil 		else if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)
   1177   1.60.18.1      phil 			/*
   1178   1.60.18.1      phil 			 * XXX TODO: this isn't completely correct, as we've
   1179   1.60.18.1      phil 			 * negotiated the higher of the two.
   1180   1.60.18.1      phil 			 */
   1181   1.60.18.1      phil 			ireq->i_val = MS(vap->iv_bss->ni_htparam,
   1182   1.60.18.1      phil 			    IEEE80211_HTCAP_MAXRXAMPDU);
   1183   1.60.18.1      phil 		else
   1184   1.60.18.1      phil 			ireq->i_val = vap->iv_ampdu_limit;
   1185   1.60.18.1      phil 		break;
   1186   1.60.18.1      phil 	case IEEE80211_IOC_AMPDU_DENSITY:
   1187   1.60.18.1      phil 		/* XXX TODO: make this a per-node thing; and leave this as global */
   1188   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA &&
   1189   1.60.18.1      phil 		    (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP))
   1190   1.60.18.1      phil 			/*
   1191   1.60.18.1      phil 			 * XXX TODO: this isn't completely correct, as we've
   1192   1.60.18.1      phil 			 * negotiated the higher of the two.
   1193   1.60.18.1      phil 			 */
   1194   1.60.18.1      phil 			ireq->i_val = MS(vap->iv_bss->ni_htparam,
   1195   1.60.18.1      phil 			    IEEE80211_HTCAP_MPDUDENSITY);
   1196   1.60.18.1      phil 		else
   1197   1.60.18.1      phil 			ireq->i_val = vap->iv_ampdu_density;
   1198   1.60.18.1      phil 		break;
   1199   1.60.18.1      phil 	case IEEE80211_IOC_AMSDU:
   1200   1.60.18.1      phil 		ireq->i_val = 0;
   1201   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_TX)
   1202   1.60.18.1      phil 			ireq->i_val |= 1;
   1203   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_RX)
   1204   1.60.18.1      phil 			ireq->i_val |= 2;
   1205   1.60.18.1      phil 		break;
   1206   1.60.18.1      phil 	case IEEE80211_IOC_AMSDU_LIMIT:
   1207   1.60.18.1      phil 		ireq->i_val = vap->iv_amsdu_limit;	/* XXX truncation? */
   1208   1.60.18.1      phil 		break;
   1209   1.60.18.1      phil 	case IEEE80211_IOC_PUREN:
   1210   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ht & IEEE80211_FHT_PUREN) != 0;
   1211   1.60.18.1      phil 		break;
   1212   1.60.18.1      phil 	case IEEE80211_IOC_DOTH:
   1213   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_DOTH) != 0;
   1214   1.60.18.1      phil 		break;
   1215   1.60.18.1      phil 	case IEEE80211_IOC_REGDOMAIN:
   1216   1.60.18.1      phil 		error = ieee80211_ioctl_getregdomain(vap, ireq);
   1217   1.60.18.1      phil 		break;
   1218   1.60.18.1      phil 	case IEEE80211_IOC_ROAM:
   1219   1.60.18.1      phil 		error = ieee80211_ioctl_getroam(vap, ireq);
   1220   1.60.18.1      phil 		break;
   1221   1.60.18.1      phil 	case IEEE80211_IOC_TXPARAMS:
   1222   1.60.18.1      phil 		error = ieee80211_ioctl_gettxparams(vap, ireq);
   1223   1.60.18.1      phil 		break;
   1224   1.60.18.1      phil 	case IEEE80211_IOC_HTCOMPAT:
   1225   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) != 0;
   1226   1.60.18.1      phil 		break;
   1227   1.60.18.1      phil 	case IEEE80211_IOC_DWDS:
   1228   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags & IEEE80211_F_DWDS) != 0;
   1229   1.60.18.1      phil 		break;
   1230   1.60.18.1      phil 	case IEEE80211_IOC_INACTIVITY:
   1231   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_INACT) != 0;
   1232   1.60.18.1      phil 		break;
   1233   1.60.18.1      phil 	case IEEE80211_IOC_APPIE:
   1234   1.60.18.1      phil 		error = ieee80211_ioctl_getappie(vap, ireq);
   1235   1.60.18.1      phil 		break;
   1236   1.60.18.1      phil 	case IEEE80211_IOC_WPS:
   1237   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_WPS) != 0;
   1238   1.60.18.1      phil 		break;
   1239   1.60.18.1      phil 	case IEEE80211_IOC_TSN:
   1240   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_TSN) != 0;
   1241   1.60.18.1      phil 		break;
   1242   1.60.18.1      phil 	case IEEE80211_IOC_DFS:
   1243   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_DFS) != 0;
   1244   1.60.18.1      phil 		break;
   1245   1.60.18.1      phil 	case IEEE80211_IOC_DOTD:
   1246   1.60.18.1      phil 		ireq->i_val = (vap->iv_flags_ext & IEEE80211_FEXT_DOTD) != 0;
   1247   1.60.18.1      phil 		break;
   1248   1.60.18.1      phil 	case IEEE80211_IOC_DEVCAPS:
   1249   1.60.18.1      phil 		error = ieee80211_ioctl_getdevcaps(ic, ireq);
   1250   1.60.18.1      phil 		break;
   1251   1.60.18.1      phil 	case IEEE80211_IOC_HTPROTMODE:
   1252   1.60.18.1      phil 		ireq->i_val = ic->ic_htprotmode;
   1253   1.60.18.1      phil 		break;
   1254   1.60.18.1      phil 	case IEEE80211_IOC_HTCONF:
   1255   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_HT) {
   1256   1.60.18.1      phil 			ireq->i_val = 1;
   1257   1.60.18.1      phil 			if (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)
   1258   1.60.18.1      phil 				ireq->i_val |= 2;
   1259   1.60.18.1      phil 		} else
   1260   1.60.18.1      phil 			ireq->i_val = 0;
   1261   1.60.18.1      phil 		break;
   1262   1.60.18.1      phil 	case IEEE80211_IOC_STA_VLAN:
   1263   1.60.18.1      phil 		error = ieee80211_ioctl_getstavlan(vap, ireq);
   1264   1.60.18.1      phil 		break;
   1265   1.60.18.1      phil 	case IEEE80211_IOC_SMPS:
   1266   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA &&
   1267   1.60.18.1      phil 		    (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) {
   1268   1.60.18.1      phil 			if (vap->iv_bss->ni_flags & IEEE80211_NODE_MIMO_RTS)
   1269   1.60.18.1      phil 				ireq->i_val = IEEE80211_HTCAP_SMPS_DYNAMIC;
   1270   1.60.18.1      phil 			else if (vap->iv_bss->ni_flags & IEEE80211_NODE_MIMO_PS)
   1271   1.60.18.1      phil 				ireq->i_val = IEEE80211_HTCAP_SMPS_ENA;
   1272   1.60.18.1      phil 			else
   1273   1.60.18.1      phil 				ireq->i_val = IEEE80211_HTCAP_SMPS_OFF;
   1274   1.60.18.1      phil 		} else
   1275   1.60.18.1      phil 			ireq->i_val = vap->iv_htcaps & IEEE80211_HTCAP_SMPS;
   1276   1.60.18.1      phil 		break;
   1277   1.60.18.1      phil 	case IEEE80211_IOC_RIFS:
   1278   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA &&
   1279   1.60.18.1      phil 		    (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP))
   1280   1.60.18.1      phil 			ireq->i_val =
   1281   1.60.18.1      phil 			    (vap->iv_bss->ni_flags & IEEE80211_NODE_RIFS) != 0;
   1282   1.60.18.1      phil 		else
   1283   1.60.18.1      phil 			ireq->i_val =
   1284   1.60.18.1      phil 			    (vap->iv_flags_ht & IEEE80211_FHT_RIFS) != 0;
   1285   1.60.18.1      phil 		break;
   1286   1.60.18.1      phil 	case IEEE80211_IOC_STBC:
   1287   1.60.18.1      phil 		ireq->i_val = 0;
   1288   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_STBC_TX)
   1289   1.60.18.1      phil 			ireq->i_val |= 1;
   1290   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_STBC_RX)
   1291   1.60.18.1      phil 			ireq->i_val |= 2;
   1292   1.60.18.1      phil 		break;
   1293   1.60.18.1      phil 	case IEEE80211_IOC_LDPC:
   1294   1.60.18.1      phil 		ireq->i_val = 0;
   1295   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX)
   1296   1.60.18.1      phil 			ireq->i_val |= 1;
   1297   1.60.18.1      phil 		if (vap->iv_flags_ht & IEEE80211_FHT_LDPC_RX)
   1298   1.60.18.1      phil 			ireq->i_val |= 2;
   1299        1.19    dyoung 		break;
   1300        1.19    dyoung 
   1301   1.60.18.1      phil 	/* VHT */
   1302   1.60.18.1      phil 	case IEEE80211_IOC_VHTCONF:
   1303   1.60.18.1      phil 		ireq->i_val = 0;
   1304   1.60.18.1      phil 		if (vap->iv_flags_vht & IEEE80211_FVHT_VHT)
   1305   1.60.18.1      phil 			ireq->i_val |= 1;
   1306   1.60.18.1      phil 		if (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT40)
   1307   1.60.18.1      phil 			ireq->i_val |= 2;
   1308   1.60.18.1      phil 		if (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT80)
   1309   1.60.18.1      phil 			ireq->i_val |= 4;
   1310   1.60.18.1      phil 		if (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT80P80)
   1311   1.60.18.1      phil 			ireq->i_val |= 8;
   1312   1.60.18.1      phil 		if (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT160)
   1313   1.60.18.1      phil 			ireq->i_val |= 16;
   1314   1.60.18.1      phil 		break;
   1315        1.19    dyoung 
   1316   1.60.18.1      phil 	default:
   1317   1.60.18.1      phil 		error = ieee80211_ioctl_getdefault(vap, ireq);
   1318   1.60.18.1      phil 		break;
   1319   1.60.18.1      phil 	}
   1320        1.58    martin 	return error;
   1321   1.60.18.1      phil #undef MS
   1322        1.19    dyoung }
   1323        1.19    dyoung 
   1324        1.19    dyoung static int
   1325   1.60.18.1      phil ieee80211_ioctl_setkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1326        1.19    dyoung {
   1327        1.19    dyoung 	struct ieee80211req_key ik;
   1328        1.19    dyoung 	struct ieee80211_node *ni;
   1329        1.19    dyoung 	struct ieee80211_key *wk;
   1330   1.60.18.1      phil 	uint16_t kid;
   1331   1.60.18.1      phil 	int error, i;
   1332        1.19    dyoung 
   1333        1.19    dyoung 	if (ireq->i_len != sizeof(ik))
   1334        1.19    dyoung 		return EINVAL;
   1335        1.19    dyoung 	error = copyin(ireq->i_data, &ik, sizeof(ik));
   1336        1.19    dyoung 	if (error)
   1337        1.19    dyoung 		return error;
   1338        1.19    dyoung 	/* NB: cipher support is verified by ieee80211_crypt_newkey */
   1339        1.19    dyoung 	/* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
   1340        1.19    dyoung 	if (ik.ik_keylen > sizeof(ik.ik_keydata))
   1341        1.19    dyoung 		return E2BIG;
   1342        1.19    dyoung 	kid = ik.ik_keyix;
   1343        1.19    dyoung 	if (kid == IEEE80211_KEYIX_NONE) {
   1344        1.19    dyoung 		/* XXX unicast keys currently must be tx/rx */
   1345        1.19    dyoung 		if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
   1346        1.19    dyoung 			return EINVAL;
   1347   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA) {
   1348   1.60.18.1      phil 			ni = ieee80211_ref_node(vap->iv_bss);
   1349        1.21    dyoung 			if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
   1350        1.21    dyoung 				ieee80211_free_node(ni);
   1351        1.19    dyoung 				return EADDRNOTAVAIL;
   1352        1.21    dyoung 			}
   1353        1.19    dyoung 		} else {
   1354   1.60.18.1      phil 			ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
   1355   1.60.18.1      phil 				ik.ik_macaddr);
   1356        1.19    dyoung 			if (ni == NULL)
   1357        1.19    dyoung 				return ENOENT;
   1358        1.19    dyoung 		}
   1359        1.19    dyoung 		wk = &ni->ni_ucastkey;
   1360        1.19    dyoung 	} else {
   1361        1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
   1362        1.19    dyoung 			return EINVAL;
   1363   1.60.18.1      phil 		wk = &vap->iv_nw_keys[kid];
   1364   1.60.18.1      phil 		/*
   1365   1.60.18.1      phil 		 * Global slots start off w/o any assigned key index.
   1366   1.60.18.1      phil 		 * Force one here for consistency with IEEE80211_IOC_WEPKEY.
   1367   1.60.18.1      phil 		 */
   1368   1.60.18.1      phil 		if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
   1369   1.60.18.1      phil 			wk->wk_keyix = kid;
   1370        1.19    dyoung 		ni = NULL;
   1371        1.19    dyoung 	}
   1372        1.19    dyoung 	error = 0;
   1373   1.60.18.1      phil 	ieee80211_key_update_begin(vap);
   1374   1.60.18.1      phil 	if (ieee80211_crypto_newkey(vap, ik.ik_type, ik.ik_flags, wk)) {
   1375        1.19    dyoung 		wk->wk_keylen = ik.ik_keylen;
   1376        1.19    dyoung 		/* NB: MIC presence is implied by cipher type */
   1377        1.19    dyoung 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
   1378        1.19    dyoung 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
   1379   1.60.18.1      phil 		for (i = 0; i < IEEE80211_TID_SIZE; i++)
   1380   1.60.18.1      phil 			wk->wk_keyrsc[i] = ik.ik_keyrsc;
   1381        1.19    dyoung 		wk->wk_keytsc = 0;			/* new key, reset */
   1382        1.19    dyoung 		memset(wk->wk_key, 0, sizeof(wk->wk_key));
   1383        1.19    dyoung 		memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
   1384   1.60.18.1      phil 		IEEE80211_ADDR_COPY(wk->wk_macaddr,
   1385   1.60.18.1      phil 		    ni != NULL ?  ni->ni_macaddr : ik.ik_macaddr);
   1386   1.60.18.1      phil 		if (!ieee80211_crypto_setkey(vap, wk))
   1387        1.19    dyoung 			error = EIO;
   1388        1.19    dyoung 		else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
   1389   1.60.18.1      phil 			/*
   1390   1.60.18.1      phil 			 * Inform the driver that this is the default
   1391   1.60.18.1      phil 			 * transmit key.  Now, ideally we'd just set
   1392   1.60.18.1      phil 			 * a flag in the key update that would
   1393   1.60.18.1      phil 			 * say "yes, we're the default key", but
   1394   1.60.18.1      phil 			 * that currently isn't the way the ioctl ->
   1395   1.60.18.1      phil 			 * key interface works.
   1396   1.60.18.1      phil 			 */
   1397   1.60.18.1      phil 			ieee80211_crypto_set_deftxkey(vap, kid);
   1398        1.19    dyoung 	} else
   1399        1.19    dyoung 		error = ENXIO;
   1400   1.60.18.1      phil 	ieee80211_key_update_end(vap);
   1401        1.19    dyoung 	if (ni != NULL)
   1402        1.19    dyoung 		ieee80211_free_node(ni);
   1403        1.19    dyoung 	return error;
   1404        1.19    dyoung }
   1405        1.19    dyoung 
   1406        1.19    dyoung static int
   1407   1.60.18.1      phil ieee80211_ioctl_delkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1408        1.19    dyoung {
   1409        1.19    dyoung 	struct ieee80211req_del_key dk;
   1410        1.19    dyoung 	int kid, error;
   1411        1.19    dyoung 
   1412        1.19    dyoung 	if (ireq->i_len != sizeof(dk))
   1413        1.19    dyoung 		return EINVAL;
   1414        1.19    dyoung 	error = copyin(ireq->i_data, &dk, sizeof(dk));
   1415        1.19    dyoung 	if (error)
   1416        1.19    dyoung 		return error;
   1417        1.19    dyoung 	kid = dk.idk_keyix;
   1418   1.60.18.1      phil 	/* XXX uint8_t -> uint16_t */
   1419   1.60.18.1      phil 	if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
   1420        1.19    dyoung 		struct ieee80211_node *ni;
   1421        1.19    dyoung 
   1422   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA) {
   1423   1.60.18.1      phil 			ni = ieee80211_ref_node(vap->iv_bss);
   1424        1.21    dyoung 			if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
   1425        1.21    dyoung 				ieee80211_free_node(ni);
   1426        1.21    dyoung 				return EADDRNOTAVAIL;
   1427        1.21    dyoung 			}
   1428        1.21    dyoung 		} else {
   1429   1.60.18.1      phil 			ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
   1430   1.60.18.1      phil 				dk.idk_macaddr);
   1431        1.21    dyoung 			if (ni == NULL)
   1432        1.21    dyoung 				return ENOENT;
   1433        1.21    dyoung 		}
   1434        1.19    dyoung 		/* XXX error return */
   1435        1.26     skrll 		ieee80211_node_delucastkey(ni);
   1436        1.19    dyoung 		ieee80211_free_node(ni);
   1437        1.19    dyoung 	} else {
   1438        1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
   1439        1.19    dyoung 			return EINVAL;
   1440        1.19    dyoung 		/* XXX error return */
   1441   1.60.18.1      phil 		ieee80211_crypto_delkey(vap, &vap->iv_nw_keys[kid]);
   1442        1.19    dyoung 	}
   1443        1.19    dyoung 	return 0;
   1444        1.19    dyoung }
   1445        1.19    dyoung 
   1446   1.60.18.1      phil struct mlmeop {
   1447   1.60.18.1      phil 	struct ieee80211vap *vap;
   1448   1.60.18.1      phil 	int	op;
   1449   1.60.18.1      phil 	int	reason;
   1450   1.60.18.1      phil };
   1451   1.60.18.1      phil 
   1452   1.60.18.1      phil static void
   1453   1.60.18.1      phil mlmedebug(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
   1454   1.60.18.1      phil 	int op, int reason)
   1455   1.60.18.1      phil {
   1456   1.60.18.1      phil #ifdef IEEE80211_DEBUG
   1457   1.60.18.1      phil 	static const struct {
   1458   1.60.18.1      phil 		int mask;
   1459   1.60.18.1      phil 		const char *opstr;
   1460   1.60.18.1      phil 	} ops[] = {
   1461   1.60.18.1      phil 		{ 0, "op#0" },
   1462   1.60.18.1      phil 		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
   1463   1.60.18.1      phil 		  IEEE80211_MSG_ASSOC, "assoc" },
   1464   1.60.18.1      phil 		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
   1465   1.60.18.1      phil 		  IEEE80211_MSG_ASSOC, "disassoc" },
   1466   1.60.18.1      phil 		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
   1467   1.60.18.1      phil 		  IEEE80211_MSG_AUTH, "deauth" },
   1468   1.60.18.1      phil 		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
   1469   1.60.18.1      phil 		  IEEE80211_MSG_AUTH, "authorize" },
   1470   1.60.18.1      phil 		{ IEEE80211_MSG_IOCTL | IEEE80211_MSG_STATE |
   1471   1.60.18.1      phil 		  IEEE80211_MSG_AUTH, "unauthorize" },
   1472   1.60.18.1      phil 	};
   1473   1.60.18.1      phil 
   1474   1.60.18.1      phil 	if (op == IEEE80211_MLME_AUTH) {
   1475   1.60.18.1      phil 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_IOCTL |
   1476   1.60.18.1      phil 		    IEEE80211_MSG_STATE | IEEE80211_MSG_AUTH, mac,
   1477   1.60.18.1      phil 		    "station authenticate %s via MLME (reason: %d (%s))",
   1478   1.60.18.1      phil 		    reason == IEEE80211_STATUS_SUCCESS ? "ACCEPT" : "REJECT",
   1479   1.60.18.1      phil 		    reason, ieee80211_reason_to_string(reason));
   1480   1.60.18.1      phil 	} else if (!(IEEE80211_MLME_ASSOC <= op && op <= IEEE80211_MLME_AUTH)) {
   1481   1.60.18.1      phil 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ANY, mac,
   1482   1.60.18.1      phil 		    "unknown MLME request %d (reason: %d (%s))", op, reason,
   1483   1.60.18.1      phil 		    ieee80211_reason_to_string(reason));
   1484   1.60.18.1      phil 	} else if (reason == IEEE80211_STATUS_SUCCESS) {
   1485   1.60.18.1      phil 		IEEE80211_NOTE_MAC(vap, ops[op].mask, mac,
   1486   1.60.18.1      phil 		    "station %s via MLME", ops[op].opstr);
   1487   1.60.18.1      phil 	} else {
   1488   1.60.18.1      phil 		IEEE80211_NOTE_MAC(vap, ops[op].mask, mac,
   1489   1.60.18.1      phil 		    "station %s via MLME (reason: %d (%s))", ops[op].opstr,
   1490   1.60.18.1      phil 		    reason, ieee80211_reason_to_string(reason));
   1491   1.60.18.1      phil 	}
   1492   1.60.18.1      phil #endif /* IEEE80211_DEBUG */
   1493   1.60.18.1      phil }
   1494   1.60.18.1      phil 
   1495        1.19    dyoung static void
   1496        1.19    dyoung domlme(void *arg, struct ieee80211_node *ni)
   1497        1.19    dyoung {
   1498   1.60.18.1      phil 	struct mlmeop *mop = arg;
   1499   1.60.18.1      phil 	struct ieee80211vap *vap = ni->ni_vap;
   1500        1.19    dyoung 
   1501   1.60.18.1      phil 	if (vap != mop->vap)
   1502   1.60.18.1      phil 		return;
   1503   1.60.18.1      phil 	/*
   1504   1.60.18.1      phil 	 * NB: if ni_associd is zero then the node is already cleaned
   1505   1.60.18.1      phil 	 * up and we don't need to do this (we're safely holding a
   1506   1.60.18.1      phil 	 * reference but should otherwise not modify it's state).
   1507   1.60.18.1      phil 	 */
   1508   1.60.18.1      phil 	if (ni->ni_associd == 0)
   1509   1.60.18.1      phil 		return;
   1510   1.60.18.1      phil 	mlmedebug(vap, ni->ni_macaddr, mop->op, mop->reason);
   1511   1.60.18.1      phil 	if (mop->op == IEEE80211_MLME_DEAUTH) {
   1512   1.60.18.1      phil 		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
   1513   1.60.18.1      phil 		    mop->reason);
   1514   1.60.18.1      phil 	} else {
   1515   1.60.18.1      phil 		IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC,
   1516   1.60.18.1      phil 		    mop->reason);
   1517        1.19    dyoung 	}
   1518   1.60.18.1      phil 	ieee80211_node_leave(ni);
   1519        1.19    dyoung }
   1520        1.19    dyoung 
   1521        1.19    dyoung static int
   1522   1.60.18.1      phil setmlme_dropsta(struct ieee80211vap *vap,
   1523   1.60.18.1      phil 	const uint8_t mac[IEEE80211_ADDR_LEN], struct mlmeop *mlmeop)
   1524        1.19    dyoung {
   1525   1.60.18.1      phil 	struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta;
   1526        1.19    dyoung 	struct ieee80211_node *ni;
   1527   1.60.18.1      phil 	int error = 0;
   1528        1.19    dyoung 
   1529   1.60.18.1      phil 	/* NB: the broadcast address means do 'em all */
   1530   1.60.18.1      phil 	if (!IEEE80211_ADDR_EQ(mac, vap->iv_ifp->if_broadcastaddr)) {
   1531   1.60.18.1      phil 		IEEE80211_NODE_LOCK(nt);
   1532   1.60.18.1      phil 		ni = ieee80211_find_node_locked(nt, mac);
   1533   1.60.18.1      phil 		IEEE80211_NODE_UNLOCK(nt);
   1534   1.60.18.1      phil 		/*
   1535   1.60.18.1      phil 		 * Don't do the node update inside the node
   1536   1.60.18.1      phil 		 * table lock.  This unfortunately causes LORs
   1537   1.60.18.1      phil 		 * with drivers and their TX paths.
   1538   1.60.18.1      phil 		 */
   1539   1.60.18.1      phil 		if (ni != NULL) {
   1540   1.60.18.1      phil 			domlme(mlmeop, ni);
   1541        1.19    dyoung 			ieee80211_free_node(ni);
   1542   1.60.18.1      phil 		} else
   1543   1.60.18.1      phil 			error = ENOENT;
   1544   1.60.18.1      phil 	} else {
   1545   1.60.18.1      phil 		ieee80211_iterate_nodes(nt, domlme, mlmeop);
   1546   1.60.18.1      phil 	}
   1547   1.60.18.1      phil 	return error;
   1548   1.60.18.1      phil }
   1549   1.60.18.1      phil 
   1550   1.60.18.1      phil static int
   1551   1.60.18.1      phil setmlme_common(struct ieee80211vap *vap, int op,
   1552   1.60.18.1      phil 	const uint8_t mac[IEEE80211_ADDR_LEN], int reason)
   1553   1.60.18.1      phil {
   1554   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   1555   1.60.18.1      phil 	struct ieee80211_node_table *nt = &ic->ic_sta;
   1556   1.60.18.1      phil 	struct ieee80211_node *ni;
   1557   1.60.18.1      phil 	struct mlmeop mlmeop;
   1558   1.60.18.1      phil 	int error;
   1559   1.60.18.1      phil 
   1560   1.60.18.1      phil 	error = 0;
   1561   1.60.18.1      phil 	switch (op) {
   1562   1.60.18.1      phil 	case IEEE80211_MLME_DISASSOC:
   1563   1.60.18.1      phil 	case IEEE80211_MLME_DEAUTH:
   1564   1.60.18.1      phil 		switch (vap->iv_opmode) {
   1565   1.60.18.1      phil 		case IEEE80211_M_STA:
   1566   1.60.18.1      phil 			mlmedebug(vap, vap->iv_bss->ni_macaddr, op, reason);
   1567        1.19    dyoung 			/* XXX not quite right */
   1568   1.60.18.1      phil 			ieee80211_new_state(vap, IEEE80211_S_INIT, reason);
   1569        1.19    dyoung 			break;
   1570        1.19    dyoung 		case IEEE80211_M_HOSTAP:
   1571   1.60.18.1      phil 			mlmeop.vap = vap;
   1572   1.60.18.1      phil 			mlmeop.op = op;
   1573   1.60.18.1      phil 			mlmeop.reason = reason;
   1574   1.60.18.1      phil 			error = setmlme_dropsta(vap, mac, &mlmeop);
   1575   1.60.18.1      phil 			break;
   1576   1.60.18.1      phil 		case IEEE80211_M_WDS:
   1577   1.60.18.1      phil 			/* XXX user app should send raw frame? */
   1578   1.60.18.1      phil 			if (op != IEEE80211_MLME_DEAUTH) {
   1579   1.60.18.1      phil 				error = EINVAL;
   1580   1.60.18.1      phil 				break;
   1581   1.60.18.1      phil 			}
   1582   1.60.18.1      phil #if 0
   1583   1.60.18.1      phil 			/* XXX accept any address, simplifies user code */
   1584   1.60.18.1      phil 			if (!IEEE80211_ADDR_EQ(mac, vap->iv_bss->ni_macaddr)) {
   1585   1.60.18.1      phil 				error = EINVAL;
   1586   1.60.18.1      phil 				break;
   1587   1.60.18.1      phil 			}
   1588   1.60.18.1      phil #endif
   1589   1.60.18.1      phil 			mlmedebug(vap, vap->iv_bss->ni_macaddr, op, reason);
   1590   1.60.18.1      phil 			ni = ieee80211_ref_node(vap->iv_bss);
   1591   1.60.18.1      phil 			IEEE80211_SEND_MGMT(ni,
   1592   1.60.18.1      phil 			    IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
   1593   1.60.18.1      phil 			ieee80211_free_node(ni);
   1594   1.60.18.1      phil 			break;
   1595   1.60.18.1      phil 		case IEEE80211_M_MBSS:
   1596   1.60.18.1      phil 			IEEE80211_NODE_LOCK(nt);
   1597   1.60.18.1      phil 			ni = ieee80211_find_node_locked(nt, mac);
   1598   1.60.18.1      phil 			/*
   1599   1.60.18.1      phil 			 * Don't do the node update inside the node
   1600   1.60.18.1      phil 			 * table lock.  This unfortunately causes LORs
   1601   1.60.18.1      phil 			 * with drivers and their TX paths.
   1602   1.60.18.1      phil 			 */
   1603   1.60.18.1      phil 			IEEE80211_NODE_UNLOCK(nt);
   1604   1.60.18.1      phil 			if (ni != NULL) {
   1605   1.60.18.1      phil 				ieee80211_node_leave(ni);
   1606        1.19    dyoung 				ieee80211_free_node(ni);
   1607         1.1    dyoung 			} else {
   1608   1.60.18.1      phil 				error = ENOENT;
   1609         1.1    dyoung 			}
   1610         1.1    dyoung 			break;
   1611        1.19    dyoung 		default:
   1612   1.60.18.1      phil 			error = EINVAL;
   1613   1.60.18.1      phil 			break;
   1614        1.19    dyoung 		}
   1615        1.19    dyoung 		break;
   1616        1.19    dyoung 	case IEEE80211_MLME_AUTHORIZE:
   1617        1.19    dyoung 	case IEEE80211_MLME_UNAUTHORIZE:
   1618   1.60.18.1      phil 		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
   1619   1.60.18.1      phil 		    vap->iv_opmode != IEEE80211_M_WDS) {
   1620   1.60.18.1      phil 			error = EINVAL;
   1621   1.60.18.1      phil 			break;
   1622   1.60.18.1      phil 		}
   1623   1.60.18.1      phil 		IEEE80211_NODE_LOCK(nt);
   1624   1.60.18.1      phil 		ni = ieee80211_find_vap_node_locked(nt, vap, mac);
   1625   1.60.18.1      phil 		/*
   1626   1.60.18.1      phil 		 * Don't do the node update inside the node
   1627   1.60.18.1      phil 		 * table lock.  This unfortunately causes LORs
   1628   1.60.18.1      phil 		 * with drivers and their TX paths.
   1629   1.60.18.1      phil 		 */
   1630   1.60.18.1      phil 		IEEE80211_NODE_UNLOCK(nt);
   1631   1.60.18.1      phil 		if (ni != NULL) {
   1632   1.60.18.1      phil 			mlmedebug(vap, mac, op, reason);
   1633   1.60.18.1      phil 			if (op == IEEE80211_MLME_AUTHORIZE)
   1634   1.60.18.1      phil 				ieee80211_node_authorize(ni);
   1635   1.60.18.1      phil 			else
   1636   1.60.18.1      phil 				ieee80211_node_unauthorize(ni);
   1637   1.60.18.1      phil 			ieee80211_free_node(ni);
   1638   1.60.18.1      phil 		} else
   1639   1.60.18.1      phil 			error = ENOENT;
   1640   1.60.18.1      phil 		break;
   1641   1.60.18.1      phil 	case IEEE80211_MLME_AUTH:
   1642   1.60.18.1      phil 		if (vap->iv_opmode != IEEE80211_M_HOSTAP) {
   1643   1.60.18.1      phil 			error = EINVAL;
   1644   1.60.18.1      phil 			break;
   1645   1.60.18.1      phil 		}
   1646   1.60.18.1      phil 		IEEE80211_NODE_LOCK(nt);
   1647   1.60.18.1      phil 		ni = ieee80211_find_vap_node_locked(nt, vap, mac);
   1648   1.60.18.1      phil 		/*
   1649   1.60.18.1      phil 		 * Don't do the node update inside the node
   1650   1.60.18.1      phil 		 * table lock.  This unfortunately causes LORs
   1651   1.60.18.1      phil 		 * with drivers and their TX paths.
   1652   1.60.18.1      phil 		 */
   1653   1.60.18.1      phil 		IEEE80211_NODE_UNLOCK(nt);
   1654   1.60.18.1      phil 		if (ni != NULL) {
   1655   1.60.18.1      phil 			mlmedebug(vap, mac, op, reason);
   1656   1.60.18.1      phil 			if (reason == IEEE80211_STATUS_SUCCESS) {
   1657   1.60.18.1      phil 				IEEE80211_SEND_MGMT(ni,
   1658   1.60.18.1      phil 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
   1659   1.60.18.1      phil 				/*
   1660   1.60.18.1      phil 				 * For shared key auth, just continue the
   1661   1.60.18.1      phil 				 * exchange.  Otherwise when 802.1x is not in
   1662   1.60.18.1      phil 				 * use mark the port authorized at this point
   1663   1.60.18.1      phil 				 * so traffic can flow.
   1664   1.60.18.1      phil 				 */
   1665   1.60.18.1      phil 				if (ni->ni_authmode != IEEE80211_AUTH_8021X &&
   1666   1.60.18.1      phil 				    ni->ni_challenge == NULL)
   1667   1.60.18.1      phil 				      ieee80211_node_authorize(ni);
   1668   1.60.18.1      phil 			} else {
   1669   1.60.18.1      phil 				vap->iv_stats.is_rx_acl++;
   1670   1.60.18.1      phil 				ieee80211_send_error(ni, ni->ni_macaddr,
   1671   1.60.18.1      phil 				    IEEE80211_FC0_SUBTYPE_AUTH, 2|(reason<<16));
   1672   1.60.18.1      phil 				ieee80211_node_leave(ni);
   1673   1.60.18.1      phil 			}
   1674   1.60.18.1      phil 			ieee80211_free_node(ni);
   1675   1.60.18.1      phil 		} else
   1676   1.60.18.1      phil 			error = ENOENT;
   1677        1.19    dyoung 		break;
   1678        1.19    dyoung 	default:
   1679   1.60.18.1      phil 		error = EINVAL;
   1680   1.60.18.1      phil 		break;
   1681        1.19    dyoung 	}
   1682   1.60.18.1      phil 	return error;
   1683   1.60.18.1      phil }
   1684   1.60.18.1      phil 
   1685   1.60.18.1      phil struct scanlookup {
   1686   1.60.18.1      phil 	const uint8_t *mac;
   1687   1.60.18.1      phil 	int esslen;
   1688   1.60.18.1      phil 	const uint8_t *essid;
   1689   1.60.18.1      phil 	const struct ieee80211_scan_entry *se;
   1690   1.60.18.1      phil };
   1691   1.60.18.1      phil 
   1692   1.60.18.1      phil /*
   1693   1.60.18.1      phil  * Match mac address and any ssid.
   1694   1.60.18.1      phil  */
   1695   1.60.18.1      phil static void
   1696   1.60.18.1      phil mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
   1697   1.60.18.1      phil {
   1698   1.60.18.1      phil 	struct scanlookup *look = arg;
   1699   1.60.18.1      phil 
   1700   1.60.18.1      phil 	if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
   1701   1.60.18.1      phil 		return;
   1702   1.60.18.1      phil 	if (look->esslen != 0) {
   1703   1.60.18.1      phil 		if (se->se_ssid[1] != look->esslen)
   1704   1.60.18.1      phil 			return;
   1705   1.60.18.1      phil 		if (memcmp(look->essid, se->se_ssid+2, look->esslen))
   1706   1.60.18.1      phil 			return;
   1707   1.60.18.1      phil 	}
   1708   1.60.18.1      phil 	look->se = se;
   1709   1.60.18.1      phil }
   1710   1.60.18.1      phil 
   1711   1.60.18.1      phil static int
   1712   1.60.18.1      phil setmlme_assoc_sta(struct ieee80211vap *vap,
   1713   1.60.18.1      phil 	const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
   1714   1.60.18.1      phil 	const uint8_t ssid[IEEE80211_NWID_LEN])
   1715   1.60.18.1      phil {
   1716   1.60.18.1      phil 	struct scanlookup lookup;
   1717   1.60.18.1      phil 
   1718   1.60.18.1      phil 	KASSERT(vap->iv_opmode == IEEE80211_M_STA,
   1719   1.60.18.1      phil 	    ("expected opmode STA not %s",
   1720   1.60.18.1      phil 	    ieee80211_opmode_name[vap->iv_opmode]));
   1721   1.60.18.1      phil 
   1722   1.60.18.1      phil 	/* NB: this is racey if roaming is !manual */
   1723   1.60.18.1      phil 	lookup.se = NULL;
   1724   1.60.18.1      phil 	lookup.mac = mac;
   1725   1.60.18.1      phil 	lookup.esslen = ssid_len;
   1726   1.60.18.1      phil 	lookup.essid = ssid;
   1727   1.60.18.1      phil 	ieee80211_scan_iterate(vap, mlmelookup, &lookup);
   1728   1.60.18.1      phil 	if (lookup.se == NULL)
   1729   1.60.18.1      phil 		return ENOENT;
   1730   1.60.18.1      phil 	mlmedebug(vap, mac, IEEE80211_MLME_ASSOC, 0);
   1731   1.60.18.1      phil 	if (!ieee80211_sta_join(vap, lookup.se->se_chan, lookup.se))
   1732   1.60.18.1      phil 		return EIO;		/* XXX unique but could be better */
   1733        1.19    dyoung 	return 0;
   1734        1.19    dyoung }
   1735        1.19    dyoung 
   1736        1.19    dyoung static int
   1737   1.60.18.1      phil setmlme_assoc_adhoc(struct ieee80211vap *vap,
   1738   1.60.18.1      phil 	const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
   1739   1.60.18.1      phil 	const uint8_t ssid[IEEE80211_NWID_LEN])
   1740   1.60.18.1      phil {
   1741   1.60.18.1      phil 	struct ieee80211_scan_req *sr;
   1742   1.60.18.1      phil 	int error;
   1743   1.60.18.1      phil 
   1744   1.60.18.1      phil 	KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
   1745   1.60.18.1      phil 	    vap->iv_opmode == IEEE80211_M_AHDEMO,
   1746   1.60.18.1      phil 	    ("expected opmode IBSS or AHDEMO not %s",
   1747   1.60.18.1      phil 	    ieee80211_opmode_name[vap->iv_opmode]));
   1748   1.60.18.1      phil 
   1749   1.60.18.1      phil 	if (ssid_len == 0)
   1750   1.60.18.1      phil 		return EINVAL;
   1751   1.60.18.1      phil 
   1752   1.60.18.1      phil 	sr = IEEE80211_MALLOC(sizeof(*sr), M_TEMP,
   1753   1.60.18.1      phil 	     IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
   1754   1.60.18.1      phil 	if (sr == NULL)
   1755   1.60.18.1      phil 		return ENOMEM;
   1756   1.60.18.1      phil 
   1757   1.60.18.1      phil 	/* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */
   1758   1.60.18.1      phil 	memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
   1759   1.60.18.1      phil 	vap->iv_des_ssid[0].len = ssid_len;
   1760   1.60.18.1      phil 	memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len);
   1761   1.60.18.1      phil 	vap->iv_des_nssid = 1;
   1762   1.60.18.1      phil 
   1763   1.60.18.1      phil 	sr->sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE;
   1764   1.60.18.1      phil 	sr->sr_duration = IEEE80211_IOC_SCAN_FOREVER;
   1765   1.60.18.1      phil 	memcpy(sr->sr_ssid[0].ssid, ssid, ssid_len);
   1766   1.60.18.1      phil 	sr->sr_ssid[0].len = ssid_len;
   1767   1.60.18.1      phil 	sr->sr_nssid = 1;
   1768   1.60.18.1      phil 
   1769   1.60.18.1      phil 	error = ieee80211_scanreq(vap, sr);
   1770   1.60.18.1      phil 
   1771   1.60.18.1      phil 	IEEE80211_FREE(sr, M_TEMP);
   1772   1.60.18.1      phil 	return error;
   1773   1.60.18.1      phil }
   1774   1.60.18.1      phil 
   1775   1.60.18.1      phil static int
   1776   1.60.18.1      phil ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1777   1.60.18.1      phil {
   1778   1.60.18.1      phil 	struct ieee80211req_mlme mlme;
   1779   1.60.18.1      phil 	int error;
   1780   1.60.18.1      phil 
   1781   1.60.18.1      phil 	if (ireq->i_len != sizeof(mlme))
   1782   1.60.18.1      phil 		return EINVAL;
   1783   1.60.18.1      phil 	error = copyin(ireq->i_data, &mlme, sizeof(mlme));
   1784   1.60.18.1      phil 	if (error)
   1785   1.60.18.1      phil 		return error;
   1786   1.60.18.1      phil 	if  (vap->iv_opmode == IEEE80211_M_STA &&
   1787   1.60.18.1      phil 	    mlme.im_op == IEEE80211_MLME_ASSOC)
   1788   1.60.18.1      phil 		return setmlme_assoc_sta(vap, mlme.im_macaddr,
   1789   1.60.18.1      phil 		    vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid);
   1790   1.60.18.1      phil 	else if ((vap->iv_opmode == IEEE80211_M_IBSS ||
   1791   1.60.18.1      phil 	    vap->iv_opmode == IEEE80211_M_AHDEMO) &&
   1792   1.60.18.1      phil 	    mlme.im_op == IEEE80211_MLME_ASSOC)
   1793   1.60.18.1      phil 		return setmlme_assoc_adhoc(vap, mlme.im_macaddr,
   1794   1.60.18.1      phil 		    mlme.im_ssid_len, mlme.im_ssid);
   1795   1.60.18.1      phil 	else
   1796   1.60.18.1      phil 		return setmlme_common(vap, mlme.im_op,
   1797   1.60.18.1      phil 		    mlme.im_macaddr, mlme.im_reason);
   1798   1.60.18.1      phil }
   1799   1.60.18.1      phil 
   1800   1.60.18.1      phil static int
   1801   1.60.18.1      phil ieee80211_ioctl_macmac(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1802        1.19    dyoung {
   1803   1.60.18.1      phil 	uint8_t mac[IEEE80211_ADDR_LEN];
   1804   1.60.18.1      phil 	const struct ieee80211_aclator *acl = vap->iv_acl;
   1805        1.19    dyoung 	int error;
   1806        1.19    dyoung 
   1807        1.19    dyoung 	if (ireq->i_len != sizeof(mac))
   1808        1.19    dyoung 		return EINVAL;
   1809        1.19    dyoung 	error = copyin(ireq->i_data, mac, ireq->i_len);
   1810        1.19    dyoung 	if (error)
   1811        1.19    dyoung 		return error;
   1812        1.19    dyoung 	if (acl == NULL) {
   1813        1.19    dyoung 		acl = ieee80211_aclator_get("mac");
   1814   1.60.18.1      phil 		if (acl == NULL || !acl->iac_attach(vap))
   1815        1.19    dyoung 			return EINVAL;
   1816   1.60.18.1      phil 		vap->iv_acl = acl;
   1817        1.19    dyoung 	}
   1818        1.19    dyoung 	if (ireq->i_type == IEEE80211_IOC_ADDMAC)
   1819   1.60.18.1      phil 		acl->iac_add(vap, mac);
   1820        1.19    dyoung 	else
   1821   1.60.18.1      phil 		acl->iac_remove(vap, mac);
   1822        1.19    dyoung 	return 0;
   1823        1.19    dyoung }
   1824        1.19    dyoung 
   1825        1.19    dyoung static int
   1826   1.60.18.1      phil ieee80211_ioctl_setmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1827        1.19    dyoung {
   1828   1.60.18.1      phil 	const struct ieee80211_aclator *acl = vap->iv_acl;
   1829        1.19    dyoung 
   1830        1.19    dyoung 	switch (ireq->i_val) {
   1831        1.19    dyoung 	case IEEE80211_MACCMD_POLICY_OPEN:
   1832        1.19    dyoung 	case IEEE80211_MACCMD_POLICY_ALLOW:
   1833        1.19    dyoung 	case IEEE80211_MACCMD_POLICY_DENY:
   1834   1.60.18.1      phil 	case IEEE80211_MACCMD_POLICY_RADIUS:
   1835        1.19    dyoung 		if (acl == NULL) {
   1836        1.19    dyoung 			acl = ieee80211_aclator_get("mac");
   1837   1.60.18.1      phil 			if (acl == NULL || !acl->iac_attach(vap))
   1838        1.19    dyoung 				return EINVAL;
   1839   1.60.18.1      phil 			vap->iv_acl = acl;
   1840        1.19    dyoung 		}
   1841   1.60.18.1      phil 		acl->iac_setpolicy(vap, ireq->i_val);
   1842        1.19    dyoung 		break;
   1843        1.19    dyoung 	case IEEE80211_MACCMD_FLUSH:
   1844        1.19    dyoung 		if (acl != NULL)
   1845   1.60.18.1      phil 			acl->iac_flush(vap);
   1846        1.19    dyoung 		/* NB: silently ignore when not in use */
   1847        1.19    dyoung 		break;
   1848        1.19    dyoung 	case IEEE80211_MACCMD_DETACH:
   1849        1.19    dyoung 		if (acl != NULL) {
   1850   1.60.18.1      phil 			vap->iv_acl = NULL;
   1851   1.60.18.1      phil 			acl->iac_detach(vap);
   1852        1.19    dyoung 		}
   1853        1.19    dyoung 		break;
   1854        1.19    dyoung 	default:
   1855        1.26     skrll 		if (acl == NULL)
   1856        1.26     skrll 			return EINVAL;
   1857        1.26     skrll 		else
   1858   1.60.18.1      phil 			return acl->iac_setioctl(vap, ireq);
   1859        1.19    dyoung 	}
   1860        1.19    dyoung 	return 0;
   1861        1.19    dyoung }
   1862        1.19    dyoung 
   1863        1.19    dyoung static int
   1864   1.60.18.1      phil ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1865        1.19    dyoung {
   1866   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   1867   1.60.18.1      phil 	uint8_t *chanlist, *list;
   1868   1.60.18.1      phil 	int i, nchan, maxchan, error;
   1869   1.60.18.1      phil 
   1870   1.60.18.1      phil 	if (ireq->i_len > sizeof(ic->ic_chan_active))
   1871   1.60.18.1      phil 		ireq->i_len = sizeof(ic->ic_chan_active);
   1872   1.60.18.1      phil 	list = IEEE80211_MALLOC(ireq->i_len + IEEE80211_CHAN_BYTES, M_TEMP,
   1873   1.60.18.1      phil 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
   1874   1.60.18.1      phil 	if (list == NULL)
   1875   1.60.18.1      phil 		return ENOMEM;
   1876   1.60.18.1      phil 	error = copyin(ireq->i_data, list, ireq->i_len);
   1877   1.60.18.1      phil 	if (error) {
   1878   1.60.18.1      phil 		IEEE80211_FREE(list, M_TEMP);
   1879        1.19    dyoung 		return error;
   1880   1.60.18.1      phil 	}
   1881   1.60.18.1      phil 	nchan = 0;
   1882   1.60.18.1      phil 	chanlist = list + ireq->i_len;		/* NB: zero'd already */
   1883   1.60.18.1      phil 	maxchan = ireq->i_len * NBBY;
   1884   1.60.18.1      phil 	for (i = 0; i < ic->ic_nchans; i++) {
   1885   1.60.18.1      phil 		const struct ieee80211_channel *c = &ic->ic_channels[i];
   1886        1.19    dyoung 		/*
   1887   1.60.18.1      phil 		 * Calculate the intersection of the user list and the
   1888   1.60.18.1      phil 		 * available channels so users can do things like specify
   1889   1.60.18.1      phil 		 * 1-255 to get all available channels.
   1890        1.19    dyoung 		 */
   1891   1.60.18.1      phil 		if (c->ic_ieee < maxchan && isset(list, c->ic_ieee)) {
   1892   1.60.18.1      phil 			setbit(chanlist, c->ic_ieee);
   1893   1.60.18.1      phil 			nchan++;
   1894   1.60.18.1      phil 		}
   1895        1.19    dyoung 	}
   1896   1.60.18.1      phil 	if (nchan == 0) {
   1897   1.60.18.1      phil 		IEEE80211_FREE(list, M_TEMP);
   1898   1.60.18.1      phil 		return EINVAL;
   1899        1.19    dyoung 	}
   1900   1.60.18.1      phil 	if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&	/* XXX */
   1901   1.60.18.1      phil 	    isclr(chanlist, ic->ic_bsschan->ic_ieee))
   1902   1.60.18.1      phil 		ic->ic_bsschan = IEEE80211_CHAN_ANYC;
   1903   1.60.18.1      phil 	memcpy(ic->ic_chan_active, chanlist, IEEE80211_CHAN_BYTES);
   1904   1.60.18.1      phil 	ieee80211_scan_flush(vap);
   1905   1.60.18.1      phil 	IEEE80211_FREE(list, M_TEMP);
   1906   1.60.18.1      phil 	return ENETRESET;
   1907   1.60.18.1      phil }
   1908   1.60.18.1      phil 
   1909   1.60.18.1      phil static int
   1910   1.60.18.1      phil ieee80211_ioctl_setstastats(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1911   1.60.18.1      phil {
   1912   1.60.18.1      phil 	struct ieee80211_node *ni;
   1913   1.60.18.1      phil 	uint8_t macaddr[IEEE80211_ADDR_LEN];
   1914   1.60.18.1      phil 	int error;
   1915   1.60.18.1      phil 
   1916   1.60.18.1      phil 	/*
   1917   1.60.18.1      phil 	 * NB: we could copyin ieee80211req_sta_stats so apps
   1918   1.60.18.1      phil 	 *     could make selective changes but that's overkill;
   1919   1.60.18.1      phil 	 *     just clear all stats for now.
   1920   1.60.18.1      phil 	 */
   1921   1.60.18.1      phil 	if (ireq->i_len < IEEE80211_ADDR_LEN)
   1922   1.60.18.1      phil 		return EINVAL;
   1923   1.60.18.1      phil 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
   1924   1.60.18.1      phil 	if (error != 0)
   1925   1.60.18.1      phil 		return error;
   1926   1.60.18.1      phil 	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
   1927   1.60.18.1      phil 	if (ni == NULL)
   1928   1.60.18.1      phil 		return ENOENT;
   1929   1.60.18.1      phil 	/* XXX require ni_vap == vap? */
   1930   1.60.18.1      phil 	memset(&ni->ni_stats, 0, sizeof(ni->ni_stats));
   1931   1.60.18.1      phil 	ieee80211_free_node(ni);
   1932   1.60.18.1      phil 	return 0;
   1933        1.19    dyoung }
   1934        1.19    dyoung 
   1935        1.19    dyoung static int
   1936   1.60.18.1      phil ieee80211_ioctl_setstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1937        1.19    dyoung {
   1938        1.19    dyoung 	struct ieee80211_node *ni;
   1939        1.19    dyoung 	struct ieee80211req_sta_txpow txpow;
   1940        1.19    dyoung 	int error;
   1941        1.19    dyoung 
   1942        1.19    dyoung 	if (ireq->i_len != sizeof(txpow))
   1943        1.19    dyoung 		return EINVAL;
   1944        1.19    dyoung 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
   1945        1.19    dyoung 	if (error != 0)
   1946        1.19    dyoung 		return error;
   1947   1.60.18.1      phil 	ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, txpow.it_macaddr);
   1948        1.19    dyoung 	if (ni == NULL)
   1949   1.60.18.1      phil 		return ENOENT;
   1950        1.19    dyoung 	ni->ni_txpower = txpow.it_txpow;
   1951        1.19    dyoung 	ieee80211_free_node(ni);
   1952        1.19    dyoung 	return error;
   1953        1.19    dyoung }
   1954        1.19    dyoung 
   1955        1.19    dyoung static int
   1956   1.60.18.1      phil ieee80211_ioctl_setwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq)
   1957        1.19    dyoung {
   1958   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   1959        1.19    dyoung 	struct ieee80211_wme_state *wme = &ic->ic_wme;
   1960        1.19    dyoung 	struct wmeParams *wmep, *chanp;
   1961   1.60.18.1      phil 	int isbss, ac, aggrmode;
   1962        1.19    dyoung 
   1963        1.19    dyoung 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
   1964   1.60.18.1      phil 		return EOPNOTSUPP;
   1965        1.19    dyoung 
   1966        1.19    dyoung 	isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
   1967        1.19    dyoung 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
   1968   1.60.18.1      phil 	aggrmode = (wme->wme_flags & WME_F_AGGRMODE);
   1969        1.19    dyoung 	if (ac >= WME_NUM_AC)
   1970        1.19    dyoung 		ac = WME_AC_BE;
   1971        1.19    dyoung 	if (isbss) {
   1972        1.19    dyoung 		chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
   1973        1.19    dyoung 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
   1974        1.19    dyoung 	} else {
   1975        1.19    dyoung 		chanp = &wme->wme_chanParams.cap_wmeParams[ac];
   1976        1.19    dyoung 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
   1977        1.19    dyoung 	}
   1978        1.19    dyoung 	switch (ireq->i_type) {
   1979        1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   1980   1.60.18.1      phil 		wmep->wmep_logcwmin = ireq->i_val;
   1981   1.60.18.1      phil 		if (!isbss || !aggrmode)
   1982   1.60.18.1      phil 			chanp->wmep_logcwmin = ireq->i_val;
   1983        1.19    dyoung 		break;
   1984        1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   1985   1.60.18.1      phil 		wmep->wmep_logcwmax = ireq->i_val;
   1986   1.60.18.1      phil 		if (!isbss || !aggrmode)
   1987   1.60.18.1      phil 			chanp->wmep_logcwmax = ireq->i_val;
   1988        1.19    dyoung 		break;
   1989        1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   1990   1.60.18.1      phil 		wmep->wmep_aifsn = ireq->i_val;
   1991   1.60.18.1      phil 		if (!isbss || !aggrmode)
   1992   1.60.18.1      phil 			chanp->wmep_aifsn = ireq->i_val;
   1993        1.19    dyoung 		break;
   1994        1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   1995   1.60.18.1      phil 		wmep->wmep_txopLimit = ireq->i_val;
   1996   1.60.18.1      phil 		if (!isbss || !aggrmode)
   1997   1.60.18.1      phil 			chanp->wmep_txopLimit = ireq->i_val;
   1998        1.19    dyoung 		break;
   1999        1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   2000        1.19    dyoung 		wmep->wmep_acm = ireq->i_val;
   2001   1.60.18.1      phil 		if (!aggrmode)
   2002        1.19    dyoung 			chanp->wmep_acm = ireq->i_val;
   2003        1.19    dyoung 		break;
   2004        1.19    dyoung 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
   2005        1.19    dyoung 		wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
   2006        1.19    dyoung 			(ireq->i_val) == 0;
   2007        1.19    dyoung 		break;
   2008        1.19    dyoung 	}
   2009   1.60.18.1      phil 	ieee80211_wme_updateparams(vap);
   2010        1.19    dyoung 	return 0;
   2011        1.19    dyoung }
   2012        1.19    dyoung 
   2013        1.19    dyoung static int
   2014   1.60.18.1      phil find11gchannel(struct ieee80211com *ic, int start, int freq)
   2015        1.19    dyoung {
   2016   1.60.18.1      phil 	const struct ieee80211_channel *c;
   2017   1.60.18.1      phil 	int i;
   2018   1.60.18.1      phil 
   2019   1.60.18.1      phil 	for (i = start+1; i < ic->ic_nchans; i++) {
   2020   1.60.18.1      phil 		c = &ic->ic_channels[i];
   2021   1.60.18.1      phil 		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
   2022   1.60.18.1      phil 			return 1;
   2023   1.60.18.1      phil 	}
   2024   1.60.18.1      phil 	/* NB: should not be needed but in case things are mis-sorted */
   2025   1.60.18.1      phil 	for (i = 0; i < start; i++) {
   2026   1.60.18.1      phil 		c = &ic->ic_channels[i];
   2027   1.60.18.1      phil 		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
   2028   1.60.18.1      phil 			return 1;
   2029        1.19    dyoung 	}
   2030        1.19    dyoung 	return 0;
   2031        1.19    dyoung }
   2032        1.19    dyoung 
   2033   1.60.18.1      phil static struct ieee80211_channel *
   2034   1.60.18.1      phil findchannel(struct ieee80211com *ic, int ieee, int mode)
   2035   1.60.18.1      phil {
   2036   1.60.18.1      phil 	static const u_int chanflags[IEEE80211_MODE_MAX] = {
   2037   1.60.18.1      phil 	    [IEEE80211_MODE_AUTO]	= 0,
   2038   1.60.18.1      phil 	    [IEEE80211_MODE_11A]	= IEEE80211_CHAN_A,
   2039   1.60.18.1      phil 	    [IEEE80211_MODE_11B]	= IEEE80211_CHAN_B,
   2040   1.60.18.1      phil 	    [IEEE80211_MODE_11G]	= IEEE80211_CHAN_G,
   2041   1.60.18.1      phil 	    [IEEE80211_MODE_FH]		= IEEE80211_CHAN_FHSS,
   2042   1.60.18.1      phil 	    [IEEE80211_MODE_TURBO_A]	= IEEE80211_CHAN_108A,
   2043   1.60.18.1      phil 	    [IEEE80211_MODE_TURBO_G]	= IEEE80211_CHAN_108G,
   2044   1.60.18.1      phil 	    [IEEE80211_MODE_STURBO_A]	= IEEE80211_CHAN_STURBO,
   2045   1.60.18.1      phil 	    [IEEE80211_MODE_HALF]	= IEEE80211_CHAN_HALF,
   2046   1.60.18.1      phil 	    [IEEE80211_MODE_QUARTER]	= IEEE80211_CHAN_QUARTER,
   2047   1.60.18.1      phil 	    /* NB: handled specially below */
   2048   1.60.18.1      phil 	    [IEEE80211_MODE_11NA]	= IEEE80211_CHAN_A,
   2049   1.60.18.1      phil 	    [IEEE80211_MODE_11NG]	= IEEE80211_CHAN_G,
   2050   1.60.18.1      phil 	    [IEEE80211_MODE_VHT_5GHZ]	= IEEE80211_CHAN_A,
   2051   1.60.18.1      phil 	    [IEEE80211_MODE_VHT_2GHZ]	= IEEE80211_CHAN_G,
   2052   1.60.18.1      phil 	};
   2053   1.60.18.1      phil 	u_int modeflags;
   2054   1.60.18.1      phil 	int i;
   2055   1.60.18.1      phil 
   2056   1.60.18.1      phil 	modeflags = chanflags[mode];
   2057   1.60.18.1      phil 	for (i = 0; i < ic->ic_nchans; i++) {
   2058   1.60.18.1      phil 		struct ieee80211_channel *c = &ic->ic_channels[i];
   2059   1.60.18.1      phil 
   2060   1.60.18.1      phil 		if (c->ic_ieee != ieee)
   2061   1.60.18.1      phil 			continue;
   2062   1.60.18.1      phil 		if (mode == IEEE80211_MODE_AUTO) {
   2063   1.60.18.1      phil 			/* ignore turbo channels for autoselect */
   2064   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_TURBO(c))
   2065   1.60.18.1      phil 				continue;
   2066   1.60.18.1      phil 			/*
   2067   1.60.18.1      phil 			 * XXX special-case 11b/g channels so we
   2068   1.60.18.1      phil 			 *     always select the g channel if both
   2069   1.60.18.1      phil 			 *     are present.
   2070   1.60.18.1      phil 			 * XXX prefer HT to non-HT?
   2071   1.60.18.1      phil 			 */
   2072   1.60.18.1      phil 			if (!IEEE80211_IS_CHAN_B(c) ||
   2073   1.60.18.1      phil 			    !find11gchannel(ic, i, c->ic_freq))
   2074   1.60.18.1      phil 				return c;
   2075   1.60.18.1      phil 		} else {
   2076   1.60.18.1      phil 			/* must check VHT specifically */
   2077   1.60.18.1      phil 			if ((mode == IEEE80211_MODE_VHT_5GHZ ||
   2078   1.60.18.1      phil 			    mode == IEEE80211_MODE_VHT_2GHZ) &&
   2079   1.60.18.1      phil 			    !IEEE80211_IS_CHAN_VHT(c))
   2080   1.60.18.1      phil 				continue;
   2081   1.60.18.1      phil 
   2082   1.60.18.1      phil 			/*
   2083   1.60.18.1      phil 			 * Must check HT specially - only match on HT,
   2084   1.60.18.1      phil 			 * not HT+VHT channels
   2085   1.60.18.1      phil 			 */
   2086   1.60.18.1      phil 			if ((mode == IEEE80211_MODE_11NA ||
   2087   1.60.18.1      phil 			    mode == IEEE80211_MODE_11NG) &&
   2088   1.60.18.1      phil 			    !IEEE80211_IS_CHAN_HT(c))
   2089   1.60.18.1      phil 				continue;
   2090   1.60.18.1      phil 
   2091   1.60.18.1      phil 			if ((mode == IEEE80211_MODE_11NA ||
   2092   1.60.18.1      phil 			    mode == IEEE80211_MODE_11NG) &&
   2093   1.60.18.1      phil 			    IEEE80211_IS_CHAN_VHT(c))
   2094   1.60.18.1      phil 				continue;
   2095   1.60.18.1      phil 
   2096   1.60.18.1      phil 			/* Check that the modeflags above match */
   2097   1.60.18.1      phil 			if ((c->ic_flags & modeflags) == modeflags)
   2098   1.60.18.1      phil 				return c;
   2099   1.60.18.1      phil 		}
   2100   1.60.18.1      phil 	}
   2101   1.60.18.1      phil 	return NULL;
   2102   1.60.18.1      phil }
   2103   1.60.18.1      phil 
   2104   1.60.18.1      phil /*
   2105   1.60.18.1      phil  * Check the specified against any desired mode (aka netband).
   2106   1.60.18.1      phil  * This is only used (presently) when operating in hostap mode
   2107   1.60.18.1      phil  * to enforce consistency.
   2108   1.60.18.1      phil  */
   2109        1.19    dyoung static int
   2110   1.60.18.1      phil check_mode_consistency(const struct ieee80211_channel *c, int mode)
   2111        1.19    dyoung {
   2112   1.60.18.1      phil 	KASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
   2113   1.60.18.1      phil 
   2114   1.60.18.1      phil 	switch (mode) {
   2115   1.60.18.1      phil 	case IEEE80211_MODE_11B:
   2116   1.60.18.1      phil 		return (IEEE80211_IS_CHAN_B(c));
   2117   1.60.18.1      phil 	case IEEE80211_MODE_11G:
   2118   1.60.18.1      phil 		return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
   2119   1.60.18.1      phil 	case IEEE80211_MODE_11A:
   2120   1.60.18.1      phil 		return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
   2121   1.60.18.1      phil 	case IEEE80211_MODE_STURBO_A:
   2122   1.60.18.1      phil 		return (IEEE80211_IS_CHAN_STURBO(c));
   2123   1.60.18.1      phil 	case IEEE80211_MODE_11NA:
   2124   1.60.18.1      phil 		return (IEEE80211_IS_CHAN_HTA(c));
   2125   1.60.18.1      phil 	case IEEE80211_MODE_11NG:
   2126   1.60.18.1      phil 		return (IEEE80211_IS_CHAN_HTG(c));
   2127   1.60.18.1      phil 	}
   2128   1.60.18.1      phil 	return 1;
   2129   1.60.18.1      phil 
   2130   1.60.18.1      phil }
   2131   1.60.18.1      phil 
   2132   1.60.18.1      phil /*
   2133   1.60.18.1      phil  * Common code to set the current channel.  If the device
   2134   1.60.18.1      phil  * is up and running this may result in an immediate channel
   2135   1.60.18.1      phil  * change or a kick of the state machine.
   2136   1.60.18.1      phil  */
   2137   1.60.18.1      phil static int
   2138   1.60.18.1      phil setcurchan(struct ieee80211vap *vap, struct ieee80211_channel *c)
   2139   1.60.18.1      phil {
   2140   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2141        1.23    dyoung 	int error;
   2142   1.60.18.1      phil 
   2143   1.60.18.1      phil 	if (c != IEEE80211_CHAN_ANYC) {
   2144   1.60.18.1      phil 		if (IEEE80211_IS_CHAN_RADAR(c))
   2145   1.60.18.1      phil 			return EBUSY;	/* XXX better code? */
   2146   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
   2147   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_NOHOSTAP(c))
   2148   1.60.18.1      phil 				return EINVAL;
   2149   1.60.18.1      phil 			if (!check_mode_consistency(c, vap->iv_des_mode))
   2150   1.60.18.1      phil 				return EINVAL;
   2151   1.60.18.1      phil 		} else if (vap->iv_opmode == IEEE80211_M_IBSS) {
   2152   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_NOADHOC(c))
   2153   1.60.18.1      phil 				return EINVAL;
   2154   1.60.18.1      phil 		}
   2155   1.60.18.1      phil 		if ((vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) &&
   2156   1.60.18.1      phil 		    vap->iv_bss->ni_chan == c)
   2157   1.60.18.1      phil 			return 0;	/* NB: nothing to do */
   2158   1.60.18.1      phil 	}
   2159   1.60.18.1      phil 	vap->iv_des_chan = c;
   2160        1.19    dyoung 
   2161        1.19    dyoung 	error = 0;
   2162   1.60.18.1      phil 	if (vap->iv_opmode == IEEE80211_M_MONITOR &&
   2163   1.60.18.1      phil 	    vap->iv_des_chan != IEEE80211_CHAN_ANYC) {
   2164   1.60.18.1      phil 		/*
   2165   1.60.18.1      phil 		 * Monitor mode can switch directly.
   2166   1.60.18.1      phil 		 */
   2167   1.60.18.1      phil 		if (IFNET_IS_UP_RUNNING(vap->iv_ifp)) {
   2168   1.60.18.1      phil 			/* XXX need state machine for other vap's to follow */
   2169   1.60.18.1      phil 			ieee80211_setcurchan(ic, vap->iv_des_chan);
   2170   1.60.18.1      phil 			vap->iv_bss->ni_chan = ic->ic_curchan;
   2171   1.60.18.1      phil 		} else {
   2172   1.60.18.1      phil 			ic->ic_curchan = vap->iv_des_chan;
   2173   1.60.18.1      phil 			ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
   2174   1.60.18.1      phil 		}
   2175   1.60.18.1      phil 	} else {
   2176   1.60.18.1      phil 		/*
   2177   1.60.18.1      phil 		 * Need to go through the state machine in case we
   2178   1.60.18.1      phil 		 * need to reassociate or the like.  The state machine
   2179   1.60.18.1      phil 		 * will pickup the desired channel and avoid scanning.
   2180   1.60.18.1      phil 		 */
   2181   1.60.18.1      phil 		if (IS_UP_AUTO(vap))
   2182   1.60.18.1      phil 			ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
   2183   1.60.18.1      phil 		else if (vap->iv_des_chan != IEEE80211_CHAN_ANYC) {
   2184   1.60.18.1      phil 			/*
   2185   1.60.18.1      phil 			 * When not up+running and a real channel has
   2186   1.60.18.1      phil 			 * been specified fix the current channel so
   2187   1.60.18.1      phil 			 * there is immediate feedback; e.g. via ifconfig.
   2188   1.60.18.1      phil 			 */
   2189   1.60.18.1      phil 			ic->ic_curchan = vap->iv_des_chan;
   2190   1.60.18.1      phil 			ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
   2191   1.60.18.1      phil 		}
   2192   1.60.18.1      phil 	}
   2193   1.60.18.1      phil 	return error;
   2194   1.60.18.1      phil }
   2195   1.60.18.1      phil 
   2196   1.60.18.1      phil /*
   2197   1.60.18.1      phil  * Old api for setting the current channel; this is
   2198   1.60.18.1      phil  * deprecated because channel numbers are ambiguous.
   2199   1.60.18.1      phil  */
   2200   1.60.18.1      phil static int
   2201   1.60.18.1      phil ieee80211_ioctl_setchannel(struct ieee80211vap *vap,
   2202   1.60.18.1      phil 	const struct ieee80211req *ireq)
   2203   1.60.18.1      phil {
   2204   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2205   1.60.18.1      phil 	struct ieee80211_channel *c;
   2206   1.60.18.1      phil 
   2207   1.60.18.1      phil 	/* XXX 0xffff overflows 16-bit signed */
   2208   1.60.18.1      phil 	if (ireq->i_val == 0 ||
   2209   1.60.18.1      phil 	    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
   2210   1.60.18.1      phil 		c = IEEE80211_CHAN_ANYC;
   2211   1.60.18.1      phil 	} else {
   2212   1.60.18.1      phil 		struct ieee80211_channel *c2;
   2213   1.60.18.1      phil 
   2214   1.60.18.1      phil 		c = findchannel(ic, ireq->i_val, vap->iv_des_mode);
   2215   1.60.18.1      phil 		if (c == NULL) {
   2216   1.60.18.1      phil 			c = findchannel(ic, ireq->i_val,
   2217   1.60.18.1      phil 				IEEE80211_MODE_AUTO);
   2218   1.60.18.1      phil 			if (c == NULL)
   2219   1.60.18.1      phil 				return EINVAL;
   2220   1.60.18.1      phil 		}
   2221   1.60.18.1      phil 
   2222   1.60.18.1      phil 		/*
   2223   1.60.18.1      phil 		 * Fine tune channel selection based on desired mode:
   2224   1.60.18.1      phil 		 *   if 11b is requested, find the 11b version of any
   2225   1.60.18.1      phil 		 *      11g channel returned,
   2226   1.60.18.1      phil 		 *   if static turbo, find the turbo version of any
   2227   1.60.18.1      phil 		 *	11a channel return,
   2228   1.60.18.1      phil 		 *   if 11na is requested, find the ht version of any
   2229   1.60.18.1      phil 		 *      11a channel returned,
   2230   1.60.18.1      phil 		 *   if 11ng is requested, find the ht version of any
   2231   1.60.18.1      phil 		 *      11g channel returned,
   2232   1.60.18.1      phil 		 *   if 11ac is requested, find the 11ac version
   2233   1.60.18.1      phil 		 *      of any 11a/11na channel returned,
   2234   1.60.18.1      phil 		 *   (TBD) 11acg (2GHz VHT)
   2235   1.60.18.1      phil 		 *   otherwise we should be ok with what we've got.
   2236   1.60.18.1      phil 		 */
   2237   1.60.18.1      phil 		switch (vap->iv_des_mode) {
   2238   1.60.18.1      phil 		case IEEE80211_MODE_11B:
   2239   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_ANYG(c)) {
   2240   1.60.18.1      phil 				c2 = findchannel(ic, ireq->i_val,
   2241   1.60.18.1      phil 					IEEE80211_MODE_11B);
   2242   1.60.18.1      phil 				/* NB: should not happen, =>'s 11g w/o 11b */
   2243   1.60.18.1      phil 				if (c2 != NULL)
   2244   1.60.18.1      phil 					c = c2;
   2245   1.60.18.1      phil 			}
   2246         1.1    dyoung 			break;
   2247   1.60.18.1      phil 		case IEEE80211_MODE_TURBO_A:
   2248   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_A(c)) {
   2249   1.60.18.1      phil 				c2 = findchannel(ic, ireq->i_val,
   2250   1.60.18.1      phil 					IEEE80211_MODE_TURBO_A);
   2251   1.60.18.1      phil 				if (c2 != NULL)
   2252   1.60.18.1      phil 					c = c2;
   2253   1.60.18.1      phil 			}
   2254         1.1    dyoung 			break;
   2255   1.60.18.1      phil 		case IEEE80211_MODE_11NA:
   2256   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_A(c)) {
   2257   1.60.18.1      phil 				c2 = findchannel(ic, ireq->i_val,
   2258   1.60.18.1      phil 					IEEE80211_MODE_11NA);
   2259   1.60.18.1      phil 				if (c2 != NULL)
   2260   1.60.18.1      phil 					c = c2;
   2261   1.60.18.1      phil 			}
   2262         1.1    dyoung 			break;
   2263   1.60.18.1      phil 		case IEEE80211_MODE_11NG:
   2264   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_ANYG(c)) {
   2265   1.60.18.1      phil 				c2 = findchannel(ic, ireq->i_val,
   2266   1.60.18.1      phil 					IEEE80211_MODE_11NG);
   2267   1.60.18.1      phil 				if (c2 != NULL)
   2268   1.60.18.1      phil 					c = c2;
   2269   1.60.18.1      phil 			}
   2270         1.1    dyoung 			break;
   2271   1.60.18.1      phil 		case IEEE80211_MODE_VHT_2GHZ:
   2272   1.60.18.1      phil 			printf("%s: TBD\n", __func__);
   2273   1.60.18.1      phil 			break;
   2274   1.60.18.1      phil 		case IEEE80211_MODE_VHT_5GHZ:
   2275   1.60.18.1      phil 			if (IEEE80211_IS_CHAN_A(c)) {
   2276   1.60.18.1      phil 				c2 = findchannel(ic, ireq->i_val,
   2277   1.60.18.1      phil 					IEEE80211_MODE_VHT_5GHZ);
   2278   1.60.18.1      phil 				if (c2 != NULL)
   2279   1.60.18.1      phil 					c = c2;
   2280   1.60.18.1      phil 			}
   2281   1.60.18.1      phil 			break;
   2282   1.60.18.1      phil 		default:		/* NB: no static turboG */
   2283         1.1    dyoung 			break;
   2284        1.19    dyoung 		}
   2285   1.60.18.1      phil 	}
   2286   1.60.18.1      phil 	return setcurchan(vap, c);
   2287   1.60.18.1      phil }
   2288   1.60.18.1      phil 
   2289   1.60.18.1      phil /*
   2290   1.60.18.1      phil  * New/current api for setting the current channel; a complete
   2291   1.60.18.1      phil  * channel description is provide so there is no ambiguity in
   2292   1.60.18.1      phil  * identifying the channel.
   2293   1.60.18.1      phil  */
   2294   1.60.18.1      phil static int
   2295   1.60.18.1      phil ieee80211_ioctl_setcurchan(struct ieee80211vap *vap,
   2296   1.60.18.1      phil 	const struct ieee80211req *ireq)
   2297   1.60.18.1      phil {
   2298   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2299   1.60.18.1      phil 	struct ieee80211_channel chan, *c;
   2300   1.60.18.1      phil 	int error;
   2301   1.60.18.1      phil 
   2302   1.60.18.1      phil 	if (ireq->i_len != sizeof(chan))
   2303   1.60.18.1      phil 		return EINVAL;
   2304   1.60.18.1      phil 	error = copyin(ireq->i_data, &chan, sizeof(chan));
   2305   1.60.18.1      phil 	if (error != 0)
   2306   1.60.18.1      phil 		return error;
   2307   1.60.18.1      phil 
   2308   1.60.18.1      phil 	/* XXX 0xffff overflows 16-bit signed */
   2309   1.60.18.1      phil 	if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
   2310   1.60.18.1      phil 		c = IEEE80211_CHAN_ANYC;
   2311   1.60.18.1      phil 	} else {
   2312   1.60.18.1      phil 		c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
   2313   1.60.18.1      phil 		if (c == NULL)
   2314        1.19    dyoung 			return EINVAL;
   2315   1.60.18.1      phil 	}
   2316   1.60.18.1      phil 	return setcurchan(vap, c);
   2317   1.60.18.1      phil }
   2318   1.60.18.1      phil 
   2319   1.60.18.1      phil static int
   2320   1.60.18.1      phil ieee80211_ioctl_setregdomain(struct ieee80211vap *vap,
   2321   1.60.18.1      phil 	const struct ieee80211req *ireq)
   2322   1.60.18.1      phil {
   2323   1.60.18.1      phil 	struct ieee80211_regdomain_req *reg;
   2324   1.60.18.1      phil 	int nchans, error;
   2325   1.60.18.1      phil 
   2326   1.60.18.1      phil 	nchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_regdomain_req)) /
   2327   1.60.18.1      phil 	    sizeof(struct ieee80211_channel));
   2328   1.60.18.1      phil 	if (!(1 <= nchans && nchans <= IEEE80211_CHAN_MAX)) {
   2329   1.60.18.1      phil 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
   2330   1.60.18.1      phil 		    "%s: bad # chans, i_len %d nchans %d\n", __func__,
   2331   1.60.18.1      phil 		    ireq->i_len, nchans);
   2332   1.60.18.1      phil 		return EINVAL;
   2333   1.60.18.1      phil 	}
   2334   1.60.18.1      phil 	reg = (struct ieee80211_regdomain_req *)
   2335   1.60.18.1      phil 	    IEEE80211_MALLOC(IEEE80211_REGDOMAIN_SIZE(nchans), M_TEMP,
   2336   1.60.18.1      phil 	      IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
   2337   1.60.18.1      phil 	if (reg == NULL) {
   2338   1.60.18.1      phil 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
   2339   1.60.18.1      phil 		    "%s: no memory, nchans %d\n", __func__, nchans);
   2340   1.60.18.1      phil 		return ENOMEM;
   2341   1.60.18.1      phil 	}
   2342   1.60.18.1      phil 	error = copyin(ireq->i_data, reg, IEEE80211_REGDOMAIN_SIZE(nchans));
   2343   1.60.18.1      phil 	if (error == 0) {
   2344   1.60.18.1      phil 		/* NB: validate inline channel count against storage size */
   2345   1.60.18.1      phil 		if (reg->chaninfo.ic_nchans != nchans) {
   2346   1.60.18.1      phil 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
   2347   1.60.18.1      phil 			    "%s: chan cnt mismatch, %d != %d\n", __func__,
   2348   1.60.18.1      phil 				reg->chaninfo.ic_nchans, nchans);
   2349   1.60.18.1      phil 			error = EINVAL;
   2350   1.60.18.1      phil 		} else
   2351   1.60.18.1      phil 			error = ieee80211_setregdomain(vap, reg);
   2352   1.60.18.1      phil 	}
   2353   1.60.18.1      phil 	IEEE80211_FREE(reg, M_TEMP);
   2354   1.60.18.1      phil 
   2355   1.60.18.1      phil 	return (error == 0 ? ENETRESET : error);
   2356   1.60.18.1      phil }
   2357   1.60.18.1      phil 
   2358   1.60.18.1      phil static int
   2359   1.60.18.1      phil ieee80211_ioctl_setroam(struct ieee80211vap *vap,
   2360   1.60.18.1      phil 	const struct ieee80211req *ireq)
   2361   1.60.18.1      phil {
   2362   1.60.18.1      phil 	if (ireq->i_len != sizeof(vap->iv_roamparms))
   2363   1.60.18.1      phil 		return EINVAL;
   2364   1.60.18.1      phil 	/* XXX validate params */
   2365   1.60.18.1      phil 	/* XXX? ENETRESET to push to device? */
   2366   1.60.18.1      phil 	return copyin(ireq->i_data, vap->iv_roamparms,
   2367   1.60.18.1      phil 	    sizeof(vap->iv_roamparms));
   2368   1.60.18.1      phil }
   2369   1.60.18.1      phil 
   2370   1.60.18.1      phil static int
   2371   1.60.18.1      phil checkrate(const struct ieee80211_rateset *rs, int rate)
   2372   1.60.18.1      phil {
   2373   1.60.18.1      phil 	int i;
   2374   1.60.18.1      phil 
   2375   1.60.18.1      phil 	if (rate == IEEE80211_FIXED_RATE_NONE)
   2376   1.60.18.1      phil 		return 1;
   2377   1.60.18.1      phil 	for (i = 0; i < rs->rs_nrates; i++)
   2378   1.60.18.1      phil 		if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
   2379   1.60.18.1      phil 			return 1;
   2380   1.60.18.1      phil 	return 0;
   2381   1.60.18.1      phil }
   2382   1.60.18.1      phil 
   2383   1.60.18.1      phil static int
   2384   1.60.18.1      phil checkmcs(const struct ieee80211_htrateset *rs, int mcs)
   2385   1.60.18.1      phil {
   2386   1.60.18.1      phil 	int rate_val = IEEE80211_RV(mcs);
   2387   1.60.18.1      phil 	int i;
   2388   1.60.18.1      phil 
   2389   1.60.18.1      phil 	if (mcs == IEEE80211_FIXED_RATE_NONE)
   2390   1.60.18.1      phil 		return 1;
   2391   1.60.18.1      phil 	if ((mcs & IEEE80211_RATE_MCS) == 0)	/* MCS always have 0x80 set */
   2392   1.60.18.1      phil 		return 0;
   2393   1.60.18.1      phil 	for (i = 0; i < rs->rs_nrates; i++)
   2394   1.60.18.1      phil 		if (IEEE80211_RV(rs->rs_rates[i]) == rate_val)
   2395   1.60.18.1      phil 			return 1;
   2396   1.60.18.1      phil 	return 0;
   2397   1.60.18.1      phil }
   2398   1.60.18.1      phil 
   2399   1.60.18.1      phil static int
   2400   1.60.18.1      phil ieee80211_ioctl_settxparams(struct ieee80211vap *vap,
   2401   1.60.18.1      phil 	const struct ieee80211req *ireq)
   2402   1.60.18.1      phil {
   2403   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2404   1.60.18.1      phil 	struct ieee80211_txparams_req parms;	/* XXX stack use? */
   2405   1.60.18.1      phil 	struct ieee80211_txparam *src, *dst;
   2406   1.60.18.1      phil 	const struct ieee80211_htrateset *rs_ht;
   2407   1.60.18.1      phil 	const struct ieee80211_rateset *rs;
   2408   1.60.18.1      phil 	int error, mode, changed, is11n, nmodes;
   2409   1.60.18.1      phil 
   2410   1.60.18.1      phil 	/* NB: accept short requests for backwards compat */
   2411   1.60.18.1      phil 	if (ireq->i_len > sizeof(parms))
   2412   1.60.18.1      phil 		return EINVAL;
   2413   1.60.18.1      phil 	error = copyin(ireq->i_data, &parms, ireq->i_len);
   2414   1.60.18.1      phil 	if (error != 0)
   2415   1.60.18.1      phil 		return error;
   2416   1.60.18.1      phil 	nmodes = ireq->i_len / sizeof(struct ieee80211_txparam);
   2417   1.60.18.1      phil 	changed = 0;
   2418   1.60.18.1      phil 	/* validate parameters and check if anything changed */
   2419   1.60.18.1      phil 	for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) {
   2420   1.60.18.1      phil 		if (isclr(ic->ic_modecaps, mode))
   2421   1.60.18.1      phil 			continue;
   2422   1.60.18.1      phil 		src = &parms.params[mode];
   2423   1.60.18.1      phil 		dst = &vap->iv_txparms[mode];
   2424   1.60.18.1      phil 		rs = &ic->ic_sup_rates[mode];	/* NB: 11n maps to legacy */
   2425   1.60.18.1      phil 		rs_ht = &ic->ic_sup_htrates;
   2426   1.60.18.1      phil 		is11n = (mode == IEEE80211_MODE_11NA ||
   2427   1.60.18.1      phil 			 mode == IEEE80211_MODE_11NG);
   2428   1.60.18.1      phil 		if (src->ucastrate != dst->ucastrate) {
   2429   1.60.18.1      phil 			if (!checkrate(rs, src->ucastrate) &&
   2430   1.60.18.1      phil 			    (!is11n || !checkmcs(rs_ht, src->ucastrate)))
   2431   1.60.18.1      phil 				return EINVAL;
   2432   1.60.18.1      phil 			changed++;
   2433   1.60.18.1      phil 		}
   2434   1.60.18.1      phil 		if (src->mcastrate != dst->mcastrate) {
   2435   1.60.18.1      phil 			if (!checkrate(rs, src->mcastrate) &&
   2436   1.60.18.1      phil 			    (!is11n || !checkmcs(rs_ht, src->mcastrate)))
   2437   1.60.18.1      phil 				return EINVAL;
   2438   1.60.18.1      phil 			changed++;
   2439   1.60.18.1      phil 		}
   2440   1.60.18.1      phil 		if (src->mgmtrate != dst->mgmtrate) {
   2441   1.60.18.1      phil 			if (!checkrate(rs, src->mgmtrate) &&
   2442   1.60.18.1      phil 			    (!is11n || !checkmcs(rs_ht, src->mgmtrate)))
   2443   1.60.18.1      phil 				return EINVAL;
   2444   1.60.18.1      phil 			changed++;
   2445   1.60.18.1      phil 		}
   2446   1.60.18.1      phil 		if (src->maxretry != dst->maxretry)	/* NB: no bounds */
   2447   1.60.18.1      phil 			changed++;
   2448   1.60.18.1      phil 	}
   2449   1.60.18.1      phil 	if (changed) {
   2450   1.60.18.1      phil 		/*
   2451   1.60.18.1      phil 		 * Copy new parameters in place and notify the
   2452   1.60.18.1      phil 		 * driver so it can push state to the device.
   2453   1.60.18.1      phil 		 */
   2454   1.60.18.1      phil 		for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) {
   2455   1.60.18.1      phil 			if (isset(ic->ic_modecaps, mode))
   2456   1.60.18.1      phil 				vap->iv_txparms[mode] = parms.params[mode];
   2457   1.60.18.1      phil 		}
   2458   1.60.18.1      phil 		/* XXX could be more intelligent,
   2459   1.60.18.1      phil 		   e.g. don't reset if setting not being used */
   2460   1.60.18.1      phil 		return ENETRESET;
   2461   1.60.18.1      phil 	}
   2462   1.60.18.1      phil 	return 0;
   2463   1.60.18.1      phil }
   2464   1.60.18.1      phil 
   2465   1.60.18.1      phil /*
   2466   1.60.18.1      phil  * Application Information Element support.
   2467   1.60.18.1      phil  */
   2468   1.60.18.1      phil static int
   2469   1.60.18.1      phil setappie(struct ieee80211_appie **aie, const struct ieee80211req *ireq)
   2470   1.60.18.1      phil {
   2471   1.60.18.1      phil 	struct ieee80211_appie *app = *aie;
   2472   1.60.18.1      phil 	struct ieee80211_appie *napp;
   2473   1.60.18.1      phil 	int error;
   2474   1.60.18.1      phil 
   2475   1.60.18.1      phil 	if (ireq->i_len == 0) {		/* delete any existing ie */
   2476   1.60.18.1      phil 		if (app != NULL) {
   2477   1.60.18.1      phil 			*aie = NULL;	/* XXX racey */
   2478   1.60.18.1      phil 			IEEE80211_FREE(app, M_80211_NODE_IE);
   2479   1.60.18.1      phil 		}
   2480   1.60.18.1      phil 		return 0;
   2481   1.60.18.1      phil 	}
   2482   1.60.18.1      phil 	if (!(2 <= ireq->i_len && ireq->i_len <= IEEE80211_MAX_APPIE))
   2483   1.60.18.1      phil 		return EINVAL;
   2484   1.60.18.1      phil 	/*
   2485   1.60.18.1      phil 	 * Allocate a new appie structure and copy in the user data.
   2486   1.60.18.1      phil 	 * When done swap in the new structure.  Note that we do not
   2487   1.60.18.1      phil 	 * guard against users holding a ref to the old structure;
   2488   1.60.18.1      phil 	 * this must be handled outside this code.
   2489   1.60.18.1      phil 	 *
   2490   1.60.18.1      phil 	 * XXX bad bad bad
   2491   1.60.18.1      phil 	 */
   2492   1.60.18.1      phil 	napp = (struct ieee80211_appie *) IEEE80211_MALLOC(
   2493   1.60.18.1      phil 	    sizeof(struct ieee80211_appie) + ireq->i_len, M_80211_NODE_IE,
   2494   1.60.18.1      phil 	    IEEE80211_M_NOWAIT);
   2495   1.60.18.1      phil 	if (napp == NULL)
   2496   1.60.18.1      phil 		return ENOMEM;
   2497   1.60.18.1      phil 	/* XXX holding ic lock */
   2498   1.60.18.1      phil 	error = copyin(ireq->i_data, napp->ie_data, ireq->i_len);
   2499   1.60.18.1      phil 	if (error) {
   2500   1.60.18.1      phil 		IEEE80211_FREE(napp, M_80211_NODE_IE);
   2501   1.60.18.1      phil 		return error;
   2502   1.60.18.1      phil 	}
   2503   1.60.18.1      phil 	napp->ie_len = ireq->i_len;
   2504   1.60.18.1      phil 	*aie = napp;
   2505   1.60.18.1      phil 	if (app != NULL)
   2506   1.60.18.1      phil 		IEEE80211_FREE(app, M_80211_NODE_IE);
   2507   1.60.18.1      phil 	return 0;
   2508   1.60.18.1      phil }
   2509   1.60.18.1      phil 
   2510   1.60.18.1      phil static void
   2511   1.60.18.1      phil setwparsnie(struct ieee80211vap *vap, uint8_t *ie, int space)
   2512   1.60.18.1      phil {
   2513   1.60.18.1      phil 	/* validate data is present as best we can */
   2514   1.60.18.1      phil 	if (space == 0 || 2+ie[1] > space)
   2515   1.60.18.1      phil 		return;
   2516   1.60.18.1      phil 	if (ie[0] == IEEE80211_ELEMID_VENDOR)
   2517   1.60.18.1      phil 		vap->iv_wpa_ie = ie;
   2518   1.60.18.1      phil 	else if (ie[0] == IEEE80211_ELEMID_RSN)
   2519   1.60.18.1      phil 		vap->iv_rsn_ie = ie;
   2520   1.60.18.1      phil }
   2521   1.60.18.1      phil 
   2522   1.60.18.1      phil static int
   2523   1.60.18.1      phil ieee80211_ioctl_setappie_locked(struct ieee80211vap *vap,
   2524   1.60.18.1      phil 	const struct ieee80211req *ireq, int fc0)
   2525   1.60.18.1      phil {
   2526   1.60.18.1      phil 	int error;
   2527   1.60.18.1      phil 
   2528   1.60.18.1      phil 	IEEE80211_LOCK_ASSERT(vap->iv_ic);
   2529   1.60.18.1      phil 
   2530   1.60.18.1      phil 	switch (fc0 & IEEE80211_FC0_SUBTYPE_MASK) {
   2531   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_BEACON:
   2532   1.60.18.1      phil 		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
   2533   1.60.18.1      phil 		    vap->iv_opmode != IEEE80211_M_IBSS) {
   2534   1.60.18.1      phil 			error = EINVAL;
   2535   1.60.18.1      phil 			break;
   2536   1.60.18.1      phil 		}
   2537   1.60.18.1      phil 		error = setappie(&vap->iv_appie_beacon, ireq);
   2538   1.60.18.1      phil 		if (error == 0)
   2539   1.60.18.1      phil 			ieee80211_beacon_notify(vap, IEEE80211_BEACON_APPIE);
   2540   1.60.18.1      phil 		break;
   2541   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
   2542   1.60.18.1      phil 		error = setappie(&vap->iv_appie_proberesp, ireq);
   2543   1.60.18.1      phil 		break;
   2544   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
   2545   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
   2546   1.60.18.1      phil 			error = setappie(&vap->iv_appie_assocresp, ireq);
   2547   1.60.18.1      phil 		else
   2548   1.60.18.1      phil 			error = EINVAL;
   2549   1.60.18.1      phil 		break;
   2550   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
   2551   1.60.18.1      phil 		error = setappie(&vap->iv_appie_probereq, ireq);
   2552   1.60.18.1      phil 		break;
   2553   1.60.18.1      phil 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
   2554   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA)
   2555   1.60.18.1      phil 			error = setappie(&vap->iv_appie_assocreq, ireq);
   2556   1.60.18.1      phil 		else
   2557   1.60.18.1      phil 			error = EINVAL;
   2558   1.60.18.1      phil 		break;
   2559   1.60.18.1      phil 	case (IEEE80211_APPIE_WPA & IEEE80211_FC0_SUBTYPE_MASK):
   2560   1.60.18.1      phil 		error = setappie(&vap->iv_appie_wpa, ireq);
   2561   1.60.18.1      phil 		if (error == 0) {
   2562   1.60.18.1      phil 			/*
   2563   1.60.18.1      phil 			 * Must split single blob of data into separate
   2564   1.60.18.1      phil 			 * WPA and RSN ie's because they go in different
   2565   1.60.18.1      phil 			 * locations in the mgt frames.
   2566   1.60.18.1      phil 			 * XXX use IEEE80211_IOC_WPA2 so user code does split
   2567   1.60.18.1      phil 			 */
   2568   1.60.18.1      phil 			vap->iv_wpa_ie = NULL;
   2569   1.60.18.1      phil 			vap->iv_rsn_ie = NULL;
   2570   1.60.18.1      phil 			if (vap->iv_appie_wpa != NULL) {
   2571   1.60.18.1      phil 				struct ieee80211_appie *appie =
   2572   1.60.18.1      phil 				    vap->iv_appie_wpa;
   2573   1.60.18.1      phil 				uint8_t *data = appie->ie_data;
   2574   1.60.18.1      phil 
   2575   1.60.18.1      phil 				/* XXX ie length validate is painful, cheat */
   2576   1.60.18.1      phil 				setwparsnie(vap, data, appie->ie_len);
   2577   1.60.18.1      phil 				setwparsnie(vap, data + 2 + data[1],
   2578   1.60.18.1      phil 				    appie->ie_len - (2 + data[1]));
   2579   1.60.18.1      phil 			}
   2580   1.60.18.1      phil 			if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
   2581   1.60.18.1      phil 			    vap->iv_opmode == IEEE80211_M_IBSS) {
   2582   1.60.18.1      phil 				/*
   2583   1.60.18.1      phil 				 * Must rebuild beacon frame as the update
   2584   1.60.18.1      phil 				 * mechanism doesn't handle WPA/RSN ie's.
   2585   1.60.18.1      phil 				 * Could extend it but it doesn't normally
   2586   1.60.18.1      phil 				 * change; this is just to deal with hostapd
   2587   1.60.18.1      phil 				 * plumbing the ie after the interface is up.
   2588   1.60.18.1      phil 				 */
   2589   1.60.18.1      phil 				error = ENETRESET;
   2590   1.60.18.1      phil 			}
   2591   1.60.18.1      phil 		}
   2592   1.60.18.1      phil 		break;
   2593   1.60.18.1      phil 	default:
   2594   1.60.18.1      phil 		error = EINVAL;
   2595   1.60.18.1      phil 		break;
   2596   1.60.18.1      phil 	}
   2597   1.60.18.1      phil 	return error;
   2598   1.60.18.1      phil }
   2599   1.60.18.1      phil 
   2600   1.60.18.1      phil static int
   2601   1.60.18.1      phil ieee80211_ioctl_setappie(struct ieee80211vap *vap,
   2602   1.60.18.1      phil 	const struct ieee80211req *ireq)
   2603   1.60.18.1      phil {
   2604   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2605   1.60.18.1      phil 	int error;
   2606   1.60.18.1      phil 	uint8_t fc0;
   2607   1.60.18.1      phil 
   2608   1.60.18.1      phil 	fc0 = ireq->i_val & 0xff;
   2609   1.60.18.1      phil 	if ((fc0 & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
   2610   1.60.18.1      phil 		return EINVAL;
   2611   1.60.18.1      phil 	/* NB: could check iv_opmode and reject but hardly worth the effort */
   2612   1.60.18.1      phil 	IEEE80211_LOCK(ic);
   2613   1.60.18.1      phil 	error = ieee80211_ioctl_setappie_locked(vap, ireq, fc0);
   2614   1.60.18.1      phil 	IEEE80211_UNLOCK(ic);
   2615   1.60.18.1      phil 	return error;
   2616   1.60.18.1      phil }
   2617   1.60.18.1      phil 
   2618   1.60.18.1      phil static int
   2619   1.60.18.1      phil ieee80211_ioctl_chanswitch(struct ieee80211vap *vap, struct ieee80211req *ireq)
   2620   1.60.18.1      phil {
   2621   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2622   1.60.18.1      phil 	struct ieee80211_chanswitch_req csr;
   2623   1.60.18.1      phil 	struct ieee80211_channel *c;
   2624   1.60.18.1      phil 	int error;
   2625   1.60.18.1      phil 
   2626   1.60.18.1      phil 	if (ireq->i_len != sizeof(csr))
   2627   1.60.18.1      phil 		return EINVAL;
   2628   1.60.18.1      phil 	error = copyin(ireq->i_data, &csr, sizeof(csr));
   2629   1.60.18.1      phil 	if (error != 0)
   2630   1.60.18.1      phil 		return error;
   2631   1.60.18.1      phil 	/* XXX adhoc mode not supported */
   2632   1.60.18.1      phil 	if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
   2633   1.60.18.1      phil 	    (vap->iv_flags & IEEE80211_F_DOTH) == 0)
   2634   1.60.18.1      phil 		return EOPNOTSUPP;
   2635   1.60.18.1      phil 	c = ieee80211_find_channel(ic,
   2636   1.60.18.1      phil 	    csr.csa_chan.ic_freq, csr.csa_chan.ic_flags);
   2637   1.60.18.1      phil 	if (c == NULL)
   2638   1.60.18.1      phil 		return ENOENT;
   2639   1.60.18.1      phil 	IEEE80211_LOCK(ic);
   2640   1.60.18.1      phil 	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0)
   2641   1.60.18.1      phil 		ieee80211_csa_startswitch(ic, c, csr.csa_mode, csr.csa_count);
   2642   1.60.18.1      phil 	else if (csr.csa_count == 0)
   2643   1.60.18.1      phil 		ieee80211_csa_cancelswitch(ic);
   2644   1.60.18.1      phil 	else
   2645   1.60.18.1      phil 		error = EBUSY;
   2646   1.60.18.1      phil 	IEEE80211_UNLOCK(ic);
   2647   1.60.18.1      phil 	return error;
   2648   1.60.18.1      phil }
   2649   1.60.18.1      phil 
   2650   1.60.18.1      phil static int
   2651   1.60.18.1      phil ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr)
   2652   1.60.18.1      phil {
   2653   1.60.18.1      phil #define	IEEE80211_IOC_SCAN_FLAGS \
   2654   1.60.18.1      phil 	(IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ACTIVE | \
   2655   1.60.18.1      phil 	 IEEE80211_IOC_SCAN_PICK1ST | IEEE80211_IOC_SCAN_BGSCAN | \
   2656   1.60.18.1      phil 	 IEEE80211_IOC_SCAN_ONCE | IEEE80211_IOC_SCAN_NOBCAST | \
   2657   1.60.18.1      phil 	 IEEE80211_IOC_SCAN_NOJOIN | IEEE80211_IOC_SCAN_FLUSH | \
   2658   1.60.18.1      phil 	 IEEE80211_IOC_SCAN_CHECK)
   2659   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2660   1.60.18.1      phil 	int error, i;
   2661   1.60.18.1      phil 
   2662   1.60.18.1      phil 	/* convert duration */
   2663   1.60.18.1      phil 	if (sr->sr_duration == IEEE80211_IOC_SCAN_FOREVER)
   2664   1.60.18.1      phil 		sr->sr_duration = IEEE80211_SCAN_FOREVER;
   2665   1.60.18.1      phil 	else {
   2666   1.60.18.1      phil 		if (sr->sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN ||
   2667   1.60.18.1      phil 		    sr->sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX)
   2668   1.60.18.1      phil 			return EINVAL;
   2669   1.60.18.1      phil 		sr->sr_duration = msecs_to_ticks(sr->sr_duration);
   2670   1.60.18.1      phil 		if (sr->sr_duration < 1)
   2671   1.60.18.1      phil 			sr->sr_duration = 1;
   2672   1.60.18.1      phil 	}
   2673   1.60.18.1      phil 	/* convert min/max channel dwell */
   2674   1.60.18.1      phil 	if (sr->sr_mindwell != 0) {
   2675   1.60.18.1      phil 		sr->sr_mindwell = msecs_to_ticks(sr->sr_mindwell);
   2676   1.60.18.1      phil 		if (sr->sr_mindwell < 1)
   2677   1.60.18.1      phil 			sr->sr_mindwell = 1;
   2678   1.60.18.1      phil 	}
   2679   1.60.18.1      phil 	if (sr->sr_maxdwell != 0) {
   2680   1.60.18.1      phil 		sr->sr_maxdwell = msecs_to_ticks(sr->sr_maxdwell);
   2681   1.60.18.1      phil 		if (sr->sr_maxdwell < 1)
   2682   1.60.18.1      phil 			sr->sr_maxdwell = 1;
   2683   1.60.18.1      phil 	}
   2684   1.60.18.1      phil 	/* NB: silently reduce ssid count to what is supported */
   2685   1.60.18.1      phil 	if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID)
   2686   1.60.18.1      phil 		sr->sr_nssid = IEEE80211_SCAN_MAX_SSID;
   2687   1.60.18.1      phil 	for (i = 0; i < sr->sr_nssid; i++)
   2688   1.60.18.1      phil 		if (sr->sr_ssid[i].len > IEEE80211_NWID_LEN)
   2689   1.60.18.1      phil 			return EINVAL;
   2690   1.60.18.1      phil 	/* cleanse flags just in case, could reject if invalid flags */
   2691   1.60.18.1      phil 	sr->sr_flags &= IEEE80211_IOC_SCAN_FLAGS;
   2692   1.60.18.1      phil 	/*
   2693   1.60.18.1      phil 	 * Add an implicit NOPICK if the vap is not marked UP.  This
   2694   1.60.18.1      phil 	 * allows applications to scan without joining a bss (or picking
   2695   1.60.18.1      phil 	 * a channel and setting up a bss) and without forcing manual
   2696   1.60.18.1      phil 	 * roaming mode--you just need to mark the parent device UP.
   2697   1.60.18.1      phil 	 */
   2698   1.60.18.1      phil 	if ((vap->iv_ifp->if_flags & IFF_UP) == 0)
   2699   1.60.18.1      phil 		sr->sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
   2700   1.60.18.1      phil 
   2701   1.60.18.1      phil 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
   2702   1.60.18.1      phil 	    "%s: flags 0x%x%s duration 0x%x mindwell %u maxdwell %u nssid %d\n",
   2703   1.60.18.1      phil 	    __func__, sr->sr_flags,
   2704   1.60.18.1      phil 	    (vap->iv_ifp->if_flags & IFF_UP) == 0 ? " (!IFF_UP)" : "",
   2705   1.60.18.1      phil 	    sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, sr->sr_nssid);
   2706   1.60.18.1      phil 	/*
   2707   1.60.18.1      phil 	 * If we are in INIT state then the driver has never had a chance
   2708   1.60.18.1      phil 	 * to setup hardware state to do a scan; we must use the state
   2709   1.60.18.1      phil 	 * machine to get us up to the SCAN state but once we reach SCAN
   2710   1.60.18.1      phil 	 * state we then want to use the supplied params.  Stash the
   2711   1.60.18.1      phil 	 * parameters in the vap and mark IEEE80211_FEXT_SCANREQ; the
   2712   1.60.18.1      phil 	 * state machines will recognize this and use the stashed params
   2713   1.60.18.1      phil 	 * to issue the scan request.
   2714   1.60.18.1      phil 	 *
   2715   1.60.18.1      phil 	 * Otherwise just invoke the scan machinery directly.
   2716   1.60.18.1      phil 	 */
   2717   1.60.18.1      phil 	IEEE80211_LOCK(ic);
   2718   1.60.18.1      phil 	if (ic->ic_nrunning == 0) {
   2719   1.60.18.1      phil 		IEEE80211_UNLOCK(ic);
   2720   1.60.18.1      phil 		return ENXIO;
   2721   1.60.18.1      phil 	}
   2722   1.60.18.1      phil 
   2723   1.60.18.1      phil 	if (vap->iv_state == IEEE80211_S_INIT) {
   2724   1.60.18.1      phil 		/* NB: clobbers previous settings */
   2725   1.60.18.1      phil 		vap->iv_scanreq_flags = sr->sr_flags;
   2726   1.60.18.1      phil 		vap->iv_scanreq_duration = sr->sr_duration;
   2727   1.60.18.1      phil 		vap->iv_scanreq_nssid = sr->sr_nssid;
   2728   1.60.18.1      phil 		for (i = 0; i < sr->sr_nssid; i++) {
   2729   1.60.18.1      phil 			vap->iv_scanreq_ssid[i].len = sr->sr_ssid[i].len;
   2730   1.60.18.1      phil 			memcpy(vap->iv_scanreq_ssid[i].ssid,
   2731   1.60.18.1      phil 			    sr->sr_ssid[i].ssid, sr->sr_ssid[i].len);
   2732   1.60.18.1      phil 		}
   2733   1.60.18.1      phil 		vap->iv_flags_ext |= IEEE80211_FEXT_SCANREQ;
   2734   1.60.18.1      phil 		IEEE80211_UNLOCK(ic);
   2735   1.60.18.1      phil 		ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
   2736   1.60.18.1      phil 	} else {
   2737   1.60.18.1      phil 		vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
   2738   1.60.18.1      phil 		IEEE80211_UNLOCK(ic);
   2739   1.60.18.1      phil 		if (sr->sr_flags & IEEE80211_IOC_SCAN_CHECK) {
   2740   1.60.18.1      phil 			error = ieee80211_check_scan(vap, sr->sr_flags,
   2741   1.60.18.1      phil 			    sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
   2742   1.60.18.1      phil 			    sr->sr_nssid,
   2743   1.60.18.1      phil 			    /* NB: cheat, we assume structures are compatible */
   2744   1.60.18.1      phil 			    (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]);
   2745   1.60.18.1      phil 		} else {
   2746   1.60.18.1      phil 			error = ieee80211_start_scan(vap, sr->sr_flags,
   2747   1.60.18.1      phil 			    sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
   2748   1.60.18.1      phil 			    sr->sr_nssid,
   2749   1.60.18.1      phil 			    /* NB: cheat, we assume structures are compatible */
   2750   1.60.18.1      phil 			    (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]);
   2751   1.60.18.1      phil 		}
   2752   1.60.18.1      phil 		if (error == 0)
   2753   1.60.18.1      phil 			return EINPROGRESS;
   2754   1.60.18.1      phil 	}
   2755   1.60.18.1      phil 	return 0;
   2756   1.60.18.1      phil #undef IEEE80211_IOC_SCAN_FLAGS
   2757   1.60.18.1      phil }
   2758   1.60.18.1      phil 
   2759   1.60.18.1      phil static int
   2760   1.60.18.1      phil ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
   2761   1.60.18.1      phil {
   2762   1.60.18.1      phil 	struct ieee80211_scan_req *sr;
   2763   1.60.18.1      phil 	int error;
   2764   1.60.18.1      phil 
   2765   1.60.18.1      phil 	if (ireq->i_len != sizeof(*sr))
   2766   1.60.18.1      phil 		return EINVAL;
   2767   1.60.18.1      phil 	sr = IEEE80211_MALLOC(sizeof(*sr), M_TEMP,
   2768   1.60.18.1      phil 	     IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
   2769   1.60.18.1      phil 	if (sr == NULL)
   2770   1.60.18.1      phil 		return ENOMEM;
   2771   1.60.18.1      phil 	error = copyin(ireq->i_data, sr, sizeof(*sr));
   2772   1.60.18.1      phil 	if (error != 0)
   2773   1.60.18.1      phil 		goto bad;
   2774   1.60.18.1      phil 	error = ieee80211_scanreq(vap, sr);
   2775   1.60.18.1      phil bad:
   2776   1.60.18.1      phil 	IEEE80211_FREE(sr, M_TEMP);
   2777   1.60.18.1      phil 	return error;
   2778   1.60.18.1      phil }
   2779   1.60.18.1      phil 
   2780   1.60.18.1      phil static int
   2781   1.60.18.1      phil ieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
   2782   1.60.18.1      phil {
   2783   1.60.18.1      phil 	struct ieee80211_node *ni;
   2784   1.60.18.1      phil 	struct ieee80211req_sta_vlan vlan;
   2785   1.60.18.1      phil 	int error;
   2786   1.60.18.1      phil 
   2787   1.60.18.1      phil 	if (ireq->i_len != sizeof(vlan))
   2788   1.60.18.1      phil 		return EINVAL;
   2789   1.60.18.1      phil 	error = copyin(ireq->i_data, &vlan, sizeof(vlan));
   2790   1.60.18.1      phil 	if (error != 0)
   2791   1.60.18.1      phil 		return error;
   2792   1.60.18.1      phil 	if (!IEEE80211_ADDR_EQ(vlan.sv_macaddr, zerobssid)) {
   2793   1.60.18.1      phil 		ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
   2794   1.60.18.1      phil 		    vlan.sv_macaddr);
   2795   1.60.18.1      phil 		if (ni == NULL)
   2796   1.60.18.1      phil 			return ENOENT;
   2797   1.60.18.1      phil 	} else
   2798   1.60.18.1      phil 		ni = ieee80211_ref_node(vap->iv_bss);
   2799   1.60.18.1      phil 	ni->ni_vlan = vlan.sv_vlan;
   2800   1.60.18.1      phil 	ieee80211_free_node(ni);
   2801   1.60.18.1      phil 	return error;
   2802   1.60.18.1      phil }
   2803   1.60.18.1      phil 
   2804   1.60.18.1      phil static int
   2805   1.60.18.1      phil isvap11g(const struct ieee80211vap *vap)
   2806   1.60.18.1      phil {
   2807   1.60.18.1      phil 	const struct ieee80211_node *bss = vap->iv_bss;
   2808   1.60.18.1      phil 	return bss->ni_chan != IEEE80211_CHAN_ANYC &&
   2809   1.60.18.1      phil 	    IEEE80211_IS_CHAN_ANYG(bss->ni_chan);
   2810   1.60.18.1      phil }
   2811   1.60.18.1      phil 
   2812   1.60.18.1      phil static int
   2813   1.60.18.1      phil isvapht(const struct ieee80211vap *vap)
   2814   1.60.18.1      phil {
   2815   1.60.18.1      phil 	const struct ieee80211_node *bss = vap->iv_bss;
   2816   1.60.18.1      phil 	return bss->ni_chan != IEEE80211_CHAN_ANYC &&
   2817   1.60.18.1      phil 	    IEEE80211_IS_CHAN_HT(bss->ni_chan);
   2818   1.60.18.1      phil }
   2819   1.60.18.1      phil 
   2820   1.60.18.1      phil /*
   2821   1.60.18.1      phil  * Dummy ioctl set handler so the linker set is defined.
   2822   1.60.18.1      phil  */
   2823   1.60.18.2      phil static __unused int
   2824   1.60.18.1      phil dummy_ioctl_set(struct ieee80211vap *vap, struct ieee80211req *ireq)
   2825   1.60.18.1      phil {
   2826   1.60.18.1      phil 	return ENOSYS;
   2827   1.60.18.1      phil }
   2828   1.60.18.1      phil IEEE80211_IOCTL_SET(dummy, dummy_ioctl_set);
   2829   1.60.18.1      phil 
   2830   1.60.18.1      phil static int
   2831   1.60.18.1      phil ieee80211_ioctl_setdefault(struct ieee80211vap *vap, struct ieee80211req *ireq)
   2832   1.60.18.1      phil {
   2833   1.60.18.2      phil #ifdef notyet
   2834   1.60.18.1      phil 	ieee80211_ioctl_setfunc * const *set;
   2835   1.60.18.1      phil 	int error;
   2836   1.60.18.1      phil 
   2837   1.60.18.1      phil 	SET_FOREACH(set, ieee80211_ioctl_setset) {
   2838   1.60.18.1      phil 		error = (*set)(vap, ireq);
   2839   1.60.18.1      phil 		if (error != ENOSYS)
   2840   1.60.18.1      phil 			return error;
   2841   1.60.18.1      phil 	}
   2842   1.60.18.3      phil #else
   2843   1.60.18.3      phil 	printf ("ieee80211_ioctl_setdefault called\n");
   2844   1.60.18.2      phil #endif
   2845   1.60.18.1      phil 	return EINVAL;
   2846   1.60.18.1      phil }
   2847   1.60.18.1      phil 
   2848   1.60.18.1      phil static int
   2849   1.60.18.1      phil ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211req *ireq)
   2850   1.60.18.1      phil {
   2851   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   2852   1.60.18.1      phil 	int error;
   2853   1.60.18.1      phil 	const struct ieee80211_authenticator *auth;
   2854   1.60.18.1      phil 	uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
   2855   1.60.18.1      phil 	char tmpssid[IEEE80211_NWID_LEN];
   2856   1.60.18.1      phil 	uint8_t tmpbssid[IEEE80211_ADDR_LEN];
   2857   1.60.18.1      phil 	struct ieee80211_key *k;
   2858   1.60.18.1      phil 	u_int kid;
   2859   1.60.18.1      phil 	uint32_t flags;
   2860   1.60.18.1      phil 
   2861   1.60.18.1      phil 	error = 0;
   2862   1.60.18.1      phil 	switch (ireq->i_type) {
   2863   1.60.18.1      phil 	case IEEE80211_IOC_SSID:
   2864   1.60.18.1      phil 		if (ireq->i_val != 0 ||
   2865   1.60.18.1      phil 		    ireq->i_len > IEEE80211_NWID_LEN)
   2866   1.60.18.1      phil 			return EINVAL;
   2867   1.60.18.1      phil 		error = copyin(ireq->i_data, tmpssid, ireq->i_len);
   2868   1.60.18.1      phil 		if (error)
   2869   1.60.18.1      phil 			break;
   2870   1.60.18.1      phil 		memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
   2871   1.60.18.1      phil 		vap->iv_des_ssid[0].len = ireq->i_len;
   2872   1.60.18.1      phil 		memcpy(vap->iv_des_ssid[0].ssid, tmpssid, ireq->i_len);
   2873   1.60.18.1      phil 		vap->iv_des_nssid = (ireq->i_len > 0);
   2874   1.60.18.1      phil 		error = ENETRESET;
   2875   1.60.18.1      phil 		break;
   2876   1.60.18.1      phil 	case IEEE80211_IOC_WEP:
   2877   1.60.18.1      phil 		switch (ireq->i_val) {
   2878   1.60.18.1      phil 		case IEEE80211_WEP_OFF:
   2879   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_PRIVACY;
   2880   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
   2881   1.60.18.1      phil 			break;
   2882   1.60.18.1      phil 		case IEEE80211_WEP_ON:
   2883   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_PRIVACY;
   2884   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_DROPUNENC;
   2885   1.60.18.1      phil 			break;
   2886   1.60.18.1      phil 		case IEEE80211_WEP_MIXED:
   2887   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_PRIVACY;
   2888   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
   2889   1.60.18.1      phil 			break;
   2890   1.60.18.1      phil 		}
   2891   1.60.18.1      phil 		error = ENETRESET;
   2892   1.60.18.1      phil 		break;
   2893   1.60.18.1      phil 	case IEEE80211_IOC_WEPKEY:
   2894   1.60.18.1      phil 		kid = (u_int) ireq->i_val;
   2895   1.60.18.1      phil 		if (kid >= IEEE80211_WEP_NKID)
   2896   1.60.18.1      phil 			return EINVAL;
   2897   1.60.18.1      phil 		k = &vap->iv_nw_keys[kid];
   2898   1.60.18.1      phil 		if (ireq->i_len == 0) {
   2899   1.60.18.1      phil 			/* zero-len =>'s delete any existing key */
   2900   1.60.18.1      phil 			(void) ieee80211_crypto_delkey(vap, k);
   2901   1.60.18.1      phil 			break;
   2902   1.60.18.1      phil 		}
   2903   1.60.18.1      phil 		if (ireq->i_len > sizeof(tmpkey))
   2904   1.60.18.1      phil 			return EINVAL;
   2905   1.60.18.1      phil 		memset(tmpkey, 0, sizeof(tmpkey));
   2906   1.60.18.1      phil 		error = copyin(ireq->i_data, tmpkey, ireq->i_len);
   2907   1.60.18.1      phil 		if (error)
   2908   1.60.18.1      phil 			break;
   2909   1.60.18.1      phil 		ieee80211_key_update_begin(vap);
   2910   1.60.18.1      phil 		k->wk_keyix = kid;	/* NB: force fixed key id */
   2911   1.60.18.1      phil 		if (ieee80211_crypto_newkey(vap, IEEE80211_CIPHER_WEP,
   2912   1.60.18.1      phil 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
   2913   1.60.18.1      phil 			k->wk_keylen = ireq->i_len;
   2914        1.19    dyoung 			memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
   2915   1.60.18.1      phil 			IEEE80211_ADDR_COPY(k->wk_macaddr, vap->iv_myaddr);
   2916   1.60.18.1      phil 			if  (!ieee80211_crypto_setkey(vap, k))
   2917        1.19    dyoung 				error = EINVAL;
   2918        1.19    dyoung 		} else
   2919        1.19    dyoung 			error = EINVAL;
   2920   1.60.18.1      phil 		ieee80211_key_update_end(vap);
   2921        1.19    dyoung 		break;
   2922        1.19    dyoung 	case IEEE80211_IOC_WEPTXKEY:
   2923        1.19    dyoung 		kid = (u_int) ireq->i_val;
   2924        1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID &&
   2925   1.60.18.1      phil 		    (uint16_t) kid != IEEE80211_KEYIX_NONE)
   2926        1.19    dyoung 			return EINVAL;
   2927   1.60.18.1      phil 		/*
   2928   1.60.18.1      phil 		 * Firmware devices may need to be told about an explicit
   2929   1.60.18.1      phil 		 * key index here, versus just inferring it from the
   2930   1.60.18.1      phil 		 * key set / change.  Since we may also need to pause
   2931   1.60.18.1      phil 		 * things like transmit before the key is updated,
   2932   1.60.18.1      phil 		 * give the driver a chance to flush things by tying
   2933   1.60.18.1      phil 		 * into key update begin/end.
   2934   1.60.18.1      phil 		 */
   2935   1.60.18.1      phil 		ieee80211_key_update_begin(vap);
   2936   1.60.18.1      phil 		ieee80211_crypto_set_deftxkey(vap, kid);
   2937   1.60.18.1      phil 		ieee80211_key_update_end(vap);
   2938        1.19    dyoung 		break;
   2939        1.19    dyoung 	case IEEE80211_IOC_AUTHMODE:
   2940        1.19    dyoung 		switch (ireq->i_val) {
   2941        1.19    dyoung 		case IEEE80211_AUTH_WPA:
   2942        1.19    dyoung 		case IEEE80211_AUTH_8021X:	/* 802.1x */
   2943        1.19    dyoung 		case IEEE80211_AUTH_OPEN:	/* open */
   2944        1.19    dyoung 		case IEEE80211_AUTH_SHARED:	/* shared-key */
   2945        1.19    dyoung 		case IEEE80211_AUTH_AUTO:	/* auto */
   2946        1.19    dyoung 			auth = ieee80211_authenticator_get(ireq->i_val);
   2947        1.19    dyoung 			if (auth == NULL)
   2948        1.19    dyoung 				return EINVAL;
   2949         1.1    dyoung 			break;
   2950        1.19    dyoung 		default:
   2951        1.19    dyoung 			return EINVAL;
   2952        1.19    dyoung 		}
   2953        1.19    dyoung 		switch (ireq->i_val) {
   2954        1.19    dyoung 		case IEEE80211_AUTH_WPA:	/* WPA w/ 802.1x */
   2955   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_PRIVACY;
   2956        1.19    dyoung 			ireq->i_val = IEEE80211_AUTH_8021X;
   2957         1.1    dyoung 			break;
   2958        1.19    dyoung 		case IEEE80211_AUTH_OPEN:	/* open */
   2959   1.60.18.1      phil 			vap->iv_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
   2960        1.10    dyoung 			break;
   2961        1.19    dyoung 		case IEEE80211_AUTH_SHARED:	/* shared-key */
   2962        1.19    dyoung 		case IEEE80211_AUTH_8021X:	/* 802.1x */
   2963   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_WPA;
   2964        1.19    dyoung 			/* both require a key so mark the PRIVACY capability */
   2965   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_PRIVACY;
   2966        1.10    dyoung 			break;
   2967        1.19    dyoung 		case IEEE80211_AUTH_AUTO:	/* auto */
   2968   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_WPA;
   2969        1.19    dyoung 			/* XXX PRIVACY handling? */
   2970        1.19    dyoung 			/* XXX what's the right way to do this? */
   2971        1.10    dyoung 			break;
   2972         1.1    dyoung 		}
   2973        1.19    dyoung 		/* NB: authenticator attach/detach happens on state change */
   2974   1.60.18.1      phil 		vap->iv_bss->ni_authmode = ireq->i_val;
   2975        1.19    dyoung 		/* XXX mixed/mode/usage? */
   2976   1.60.18.1      phil 		vap->iv_auth = auth;
   2977        1.19    dyoung 		error = ENETRESET;
   2978         1.1    dyoung 		break;
   2979        1.19    dyoung 	case IEEE80211_IOC_CHANNEL:
   2980   1.60.18.1      phil 		error = ieee80211_ioctl_setchannel(vap, ireq);
   2981        1.19    dyoung 		break;
   2982        1.19    dyoung 	case IEEE80211_IOC_POWERSAVE:
   2983        1.19    dyoung 		switch (ireq->i_val) {
   2984        1.19    dyoung 		case IEEE80211_POWERSAVE_OFF:
   2985   1.60.18.1      phil 			if (vap->iv_flags & IEEE80211_F_PMGTON) {
   2986   1.60.18.1      phil 				ieee80211_syncflag(vap, -IEEE80211_F_PMGTON);
   2987   1.60.18.1      phil 				error = ERESTART;
   2988        1.18     perry 			}
   2989         1.1    dyoung 			break;
   2990        1.19    dyoung 		case IEEE80211_POWERSAVE_ON:
   2991   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_PMGT) == 0)
   2992   1.60.18.1      phil 				error = EOPNOTSUPP;
   2993   1.60.18.1      phil 			else if ((vap->iv_flags & IEEE80211_F_PMGTON) == 0) {
   2994   1.60.18.1      phil 				ieee80211_syncflag(vap, IEEE80211_F_PMGTON);
   2995   1.60.18.1      phil 				error = ERESTART;
   2996         1.1    dyoung 			}
   2997         1.1    dyoung 			break;
   2998        1.19    dyoung 		default:
   2999        1.19    dyoung 			error = EINVAL;
   3000         1.1    dyoung 			break;
   3001        1.19    dyoung 		}
   3002        1.19    dyoung 		break;
   3003        1.19    dyoung 	case IEEE80211_IOC_POWERSAVESLEEP:
   3004        1.19    dyoung 		if (ireq->i_val < 0)
   3005        1.19    dyoung 			return EINVAL;
   3006        1.19    dyoung 		ic->ic_lintval = ireq->i_val;
   3007   1.60.18.1      phil 		error = ERESTART;
   3008        1.19    dyoung 		break;
   3009        1.19    dyoung 	case IEEE80211_IOC_RTSTHRESHOLD:
   3010        1.26     skrll 		if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
   3011        1.26     skrll 		      ireq->i_val <= IEEE80211_RTS_MAX))
   3012        1.19    dyoung 			return EINVAL;
   3013   1.60.18.1      phil 		vap->iv_rtsthreshold = ireq->i_val;
   3014   1.60.18.1      phil 		error = ERESTART;
   3015        1.19    dyoung 		break;
   3016        1.19    dyoung 	case IEEE80211_IOC_PROTMODE:
   3017        1.19    dyoung 		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
   3018        1.19    dyoung 			return EINVAL;
   3019   1.60.18.1      phil 		ic->ic_protmode = (enum ieee80211_protmode)ireq->i_val;
   3020        1.19    dyoung 		/* NB: if not operating in 11g this can wait */
   3021   1.60.18.1      phil 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3022   1.60.18.1      phil 		    IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
   3023   1.60.18.1      phil 			error = ERESTART;
   3024        1.19    dyoung 		break;
   3025        1.19    dyoung 	case IEEE80211_IOC_TXPOWER:
   3026        1.19    dyoung 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
   3027   1.60.18.1      phil 			return EOPNOTSUPP;
   3028   1.60.18.1      phil 		if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
   3029   1.60.18.1      phil 		      ireq->i_val <= IEEE80211_TXPOWER_MAX))
   3030        1.19    dyoung 			return EINVAL;
   3031        1.19    dyoung 		ic->ic_txpowlimit = ireq->i_val;
   3032   1.60.18.1      phil 		error = ERESTART;
   3033        1.19    dyoung 		break;
   3034        1.19    dyoung 	case IEEE80211_IOC_ROAMING:
   3035        1.19    dyoung 		if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
   3036        1.19    dyoung 		    ireq->i_val <= IEEE80211_ROAMING_MANUAL))
   3037        1.19    dyoung 			return EINVAL;
   3038   1.60.18.1      phil 		vap->iv_roaming = (enum ieee80211_roamingmode)ireq->i_val;
   3039        1.19    dyoung 		/* XXXX reset? */
   3040        1.19    dyoung 		break;
   3041        1.19    dyoung 	case IEEE80211_IOC_PRIVACY:
   3042        1.19    dyoung 		if (ireq->i_val) {
   3043        1.19    dyoung 			/* XXX check for key state? */
   3044   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_PRIVACY;
   3045        1.19    dyoung 		} else
   3046   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_PRIVACY;
   3047   1.60.18.1      phil 		/* XXX ERESTART? */
   3048        1.19    dyoung 		break;
   3049        1.19    dyoung 	case IEEE80211_IOC_DROPUNENCRYPTED:
   3050        1.19    dyoung 		if (ireq->i_val)
   3051   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_DROPUNENC;
   3052        1.19    dyoung 		else
   3053   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
   3054   1.60.18.1      phil 		/* XXX ERESTART? */
   3055        1.19    dyoung 		break;
   3056        1.19    dyoung 	case IEEE80211_IOC_WPAKEY:
   3057   1.60.18.1      phil 		error = ieee80211_ioctl_setkey(vap, ireq);
   3058        1.19    dyoung 		break;
   3059        1.19    dyoung 	case IEEE80211_IOC_DELKEY:
   3060   1.60.18.1      phil 		error = ieee80211_ioctl_delkey(vap, ireq);
   3061        1.19    dyoung 		break;
   3062        1.19    dyoung 	case IEEE80211_IOC_MLME:
   3063   1.60.18.1      phil 		error = ieee80211_ioctl_setmlme(vap, ireq);
   3064        1.19    dyoung 		break;
   3065        1.19    dyoung 	case IEEE80211_IOC_COUNTERMEASURES:
   3066        1.19    dyoung 		if (ireq->i_val) {
   3067   1.60.18.1      phil 			if ((vap->iv_flags & IEEE80211_F_WPA) == 0)
   3068   1.60.18.1      phil 				return EOPNOTSUPP;
   3069   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_COUNTERM;
   3070        1.19    dyoung 		} else
   3071   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_COUNTERM;
   3072   1.60.18.1      phil 		/* XXX ERESTART? */
   3073        1.19    dyoung 		break;
   3074        1.19    dyoung 	case IEEE80211_IOC_WPA:
   3075        1.19    dyoung 		if (ireq->i_val > 3)
   3076        1.19    dyoung 			return EINVAL;
   3077        1.19    dyoung 		/* XXX verify ciphers available */
   3078   1.60.18.1      phil 		flags = vap->iv_flags & ~IEEE80211_F_WPA;
   3079        1.19    dyoung 		switch (ireq->i_val) {
   3080   1.60.18.1      phil 		case 0:
   3081   1.60.18.1      phil 			/* wpa_supplicant calls this to clear the WPA config */
   3082   1.60.18.1      phil 			break;
   3083        1.19    dyoung 		case 1:
   3084   1.60.18.1      phil 			if (!(vap->iv_caps & IEEE80211_C_WPA1))
   3085   1.60.18.1      phil 				return EOPNOTSUPP;
   3086   1.60.18.1      phil 			flags |= IEEE80211_F_WPA1;
   3087         1.1    dyoung 			break;
   3088        1.19    dyoung 		case 2:
   3089   1.60.18.1      phil 			if (!(vap->iv_caps & IEEE80211_C_WPA2))
   3090   1.60.18.1      phil 				return EOPNOTSUPP;
   3091   1.60.18.1      phil 			flags |= IEEE80211_F_WPA2;
   3092         1.1    dyoung 			break;
   3093        1.19    dyoung 		case 3:
   3094   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_WPA) != IEEE80211_C_WPA)
   3095   1.60.18.1      phil 				return EOPNOTSUPP;
   3096   1.60.18.1      phil 			flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
   3097         1.1    dyoung 			break;
   3098   1.60.18.1      phil 		default:	/*  Can't set any -> error */
   3099   1.60.18.1      phil 			return EOPNOTSUPP;
   3100        1.19    dyoung 		}
   3101   1.60.18.1      phil 		vap->iv_flags = flags;
   3102   1.60.18.1      phil 		error = ERESTART;	/* NB: can change beacon frame */
   3103        1.19    dyoung 		break;
   3104        1.19    dyoung 	case IEEE80211_IOC_WME:
   3105        1.19    dyoung 		if (ireq->i_val) {
   3106   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_WME) == 0)
   3107   1.60.18.1      phil 				return EOPNOTSUPP;
   3108   1.60.18.1      phil 			ieee80211_syncflag(vap, IEEE80211_F_WME);
   3109        1.19    dyoung 		} else
   3110   1.60.18.1      phil 			ieee80211_syncflag(vap, -IEEE80211_F_WME);
   3111   1.60.18.1      phil 		error = ERESTART;	/* NB: can change beacon frame */
   3112        1.19    dyoung 		break;
   3113        1.19    dyoung 	case IEEE80211_IOC_HIDESSID:
   3114        1.19    dyoung 		if (ireq->i_val)
   3115   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_HIDESSID;
   3116        1.19    dyoung 		else
   3117   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_HIDESSID;
   3118   1.60.18.1      phil 		error = ERESTART;		/* XXX ENETRESET? */
   3119        1.19    dyoung 		break;
   3120        1.19    dyoung 	case IEEE80211_IOC_APBRIDGE:
   3121        1.19    dyoung 		if (ireq->i_val == 0)
   3122   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_NOBRIDGE;
   3123        1.19    dyoung 		else
   3124   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_NOBRIDGE;
   3125        1.19    dyoung 		break;
   3126   1.60.18.1      phil 	case IEEE80211_IOC_BSSID:
   3127   1.60.18.1      phil 		if (ireq->i_len != sizeof(tmpbssid))
   3128        1.19    dyoung 			return EINVAL;
   3129   1.60.18.1      phil 		error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
   3130   1.60.18.1      phil 		if (error)
   3131   1.60.18.1      phil 			break;
   3132   1.60.18.1      phil 		IEEE80211_ADDR_COPY(vap->iv_des_bssid, tmpbssid);
   3133   1.60.18.1      phil 		if (IEEE80211_ADDR_EQ(vap->iv_des_bssid, zerobssid))
   3134   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_DESBSSID;
   3135   1.60.18.1      phil 		else
   3136   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_DESBSSID;
   3137   1.60.18.1      phil 		error = ENETRESET;
   3138        1.19    dyoung 		break;
   3139   1.60.18.1      phil 	case IEEE80211_IOC_CHANLIST:
   3140   1.60.18.1      phil 		error = ieee80211_ioctl_setchanlist(vap, ireq);
   3141        1.19    dyoung 		break;
   3142   1.60.18.1      phil #ifdef OLD_IEEE80211_IOC_SCAN_REQ
   3143   1.60.18.1      phil 	case OLD_IEEE80211_IOC_SCAN_REQ:
   3144   1.60.18.1      phil 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
   3145   1.60.18.1      phil 			"%s: active scan request\n", __func__);
   3146   1.60.18.5      phil 		printf ("old scan req\n");
   3147        1.19    dyoung 		/*
   3148   1.60.18.1      phil 		 * If we are in INIT state then the driver has never
   3149   1.60.18.1      phil 		 * had a chance to setup hardware state to do a scan;
   3150   1.60.18.1      phil 		 * use the state machine to get us up the SCAN state.
   3151   1.60.18.1      phil 		 * Otherwise just invoke the scan machinery to start
   3152   1.60.18.1      phil 		 * a one-time scan.
   3153        1.19    dyoung 		 */
   3154   1.60.18.1      phil 		if (vap->iv_state == IEEE80211_S_INIT)
   3155   1.60.18.5      phil {  printf ("calling new_state\n");
   3156   1.60.18.1      phil 			ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
   3157   1.60.18.5      phil }
   3158   1.60.18.1      phil 		else
   3159   1.60.18.5      phil {  printf("calling _start_scan()\n");
   3160   1.60.18.1      phil 			(void) ieee80211_start_scan(vap,
   3161   1.60.18.1      phil 				IEEE80211_SCAN_ACTIVE |
   3162   1.60.18.1      phil 				IEEE80211_SCAN_NOPICK |
   3163   1.60.18.1      phil 				IEEE80211_SCAN_ONCE,
   3164   1.60.18.1      phil 				IEEE80211_SCAN_FOREVER, 0, 0,
   3165   1.60.18.1      phil 				/* XXX use ioctl params */
   3166   1.60.18.1      phil 				vap->iv_des_nssid, vap->iv_des_ssid);
   3167   1.60.18.5      phil }
   3168        1.19    dyoung 		break;
   3169   1.60.18.1      phil #endif /* OLD_IEEE80211_IOC_SCAN_REQ */
   3170   1.60.18.1      phil 	case IEEE80211_IOC_SCAN_REQ:
   3171   1.60.18.1      phil 		error = ieee80211_ioctl_scanreq(vap, ireq);
   3172   1.60.18.1      phil 		break;
   3173   1.60.18.1      phil 	case IEEE80211_IOC_SCAN_CANCEL:
   3174   1.60.18.1      phil 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
   3175   1.60.18.1      phil 		    "%s: cancel scan\n", __func__);
   3176   1.60.18.4      phil #if __NetBSD__
   3177   1.60.18.4      phil 		/* Bug in FreeBSD? */
   3178   1.60.18.4      phil 		IEEE80211_LOCK(ic);
   3179   1.60.18.4      phil #endif
   3180   1.60.18.1      phil 		ieee80211_cancel_scan(vap);
   3181   1.60.18.4      phil #if __NetBSD__
   3182   1.60.18.4      phil 		IEEE80211_UNLOCK(ic);
   3183   1.60.18.4      phil #endif
   3184   1.60.18.1      phil 		break;
   3185   1.60.18.1      phil 	case IEEE80211_IOC_HTCONF:
   3186   1.60.18.1      phil 		if (ireq->i_val & 1)
   3187   1.60.18.1      phil 			ieee80211_syncflag_ht(vap, IEEE80211_FHT_HT);
   3188   1.60.18.1      phil 		else
   3189   1.60.18.1      phil 			ieee80211_syncflag_ht(vap, -IEEE80211_FHT_HT);
   3190   1.60.18.1      phil 		if (ireq->i_val & 2)
   3191   1.60.18.1      phil 			ieee80211_syncflag_ht(vap, IEEE80211_FHT_USEHT40);
   3192   1.60.18.1      phil 		else
   3193   1.60.18.1      phil 			ieee80211_syncflag_ht(vap, -IEEE80211_FHT_USEHT40);
   3194   1.60.18.1      phil 		error = ENETRESET;
   3195   1.60.18.1      phil 		break;
   3196   1.60.18.1      phil 	case IEEE80211_IOC_ADDMAC:
   3197   1.60.18.1      phil 	case IEEE80211_IOC_DELMAC:
   3198   1.60.18.1      phil 		error = ieee80211_ioctl_macmac(vap, ireq);
   3199   1.60.18.1      phil 		break;
   3200   1.60.18.1      phil 	case IEEE80211_IOC_MACCMD:
   3201   1.60.18.1      phil 		error = ieee80211_ioctl_setmaccmd(vap, ireq);
   3202   1.60.18.1      phil 		break;
   3203   1.60.18.1      phil 	case IEEE80211_IOC_STA_STATS:
   3204   1.60.18.1      phil 		error = ieee80211_ioctl_setstastats(vap, ireq);
   3205   1.60.18.1      phil 		break;
   3206   1.60.18.1      phil 	case IEEE80211_IOC_STA_TXPOW:
   3207   1.60.18.1      phil 		error = ieee80211_ioctl_setstatxpow(vap, ireq);
   3208   1.60.18.1      phil 		break;
   3209   1.60.18.1      phil 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   3210   1.60.18.1      phil 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   3211   1.60.18.1      phil 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   3212   1.60.18.1      phil 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   3213   1.60.18.1      phil 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   3214   1.60.18.1      phil 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only) */
   3215   1.60.18.1      phil 		error = ieee80211_ioctl_setwmeparam(vap, ireq);
   3216   1.60.18.1      phil 		break;
   3217   1.60.18.1      phil 	case IEEE80211_IOC_DTIM_PERIOD:
   3218   1.60.18.1      phil 		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
   3219   1.60.18.1      phil 		    vap->iv_opmode != IEEE80211_M_MBSS &&
   3220   1.60.18.1      phil 		    vap->iv_opmode != IEEE80211_M_IBSS)
   3221   1.60.18.1      phil 			return EINVAL;
   3222   1.60.18.1      phil 		if (IEEE80211_DTIM_MIN <= ireq->i_val &&
   3223   1.60.18.1      phil 		    ireq->i_val <= IEEE80211_DTIM_MAX) {
   3224   1.60.18.1      phil 			vap->iv_dtim_period = ireq->i_val;
   3225   1.60.18.1      phil 			error = ENETRESET;		/* requires restart */
   3226   1.60.18.1      phil 		} else
   3227   1.60.18.1      phil 			error = EINVAL;
   3228   1.60.18.1      phil 		break;
   3229   1.60.18.1      phil 	case IEEE80211_IOC_BEACON_INTERVAL:
   3230   1.60.18.1      phil 		if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
   3231   1.60.18.1      phil 		    vap->iv_opmode != IEEE80211_M_MBSS &&
   3232   1.60.18.1      phil 		    vap->iv_opmode != IEEE80211_M_IBSS)
   3233   1.60.18.1      phil 			return EINVAL;
   3234   1.60.18.1      phil 		if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
   3235   1.60.18.1      phil 		    ireq->i_val <= IEEE80211_BINTVAL_MAX) {
   3236   1.60.18.1      phil 			ic->ic_bintval = ireq->i_val;
   3237   1.60.18.1      phil 			error = ENETRESET;		/* requires restart */
   3238   1.60.18.1      phil 		} else
   3239   1.60.18.1      phil 			error = EINVAL;
   3240   1.60.18.1      phil 		break;
   3241   1.60.18.1      phil 	case IEEE80211_IOC_PUREG:
   3242   1.60.18.1      phil 		if (ireq->i_val)
   3243   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_PUREG;
   3244   1.60.18.1      phil 		else
   3245   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_PUREG;
   3246   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11g channel */
   3247   1.60.18.1      phil 		if (isvap11g(vap))
   3248   1.60.18.1      phil 			error = ENETRESET;
   3249   1.60.18.1      phil 		break;
   3250   1.60.18.1      phil 	case IEEE80211_IOC_QUIET:
   3251   1.60.18.1      phil 		vap->iv_quiet= ireq->i_val;
   3252   1.60.18.1      phil 		break;
   3253   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_COUNT:
   3254   1.60.18.1      phil 		vap->iv_quiet_count=ireq->i_val;
   3255   1.60.18.1      phil 		break;
   3256   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_PERIOD:
   3257   1.60.18.1      phil 		vap->iv_quiet_period=ireq->i_val;
   3258   1.60.18.1      phil 		break;
   3259   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_OFFSET:
   3260   1.60.18.1      phil 		vap->iv_quiet_offset=ireq->i_val;
   3261   1.60.18.1      phil 		break;
   3262   1.60.18.1      phil 	case IEEE80211_IOC_QUIET_DUR:
   3263   1.60.18.1      phil 		if(ireq->i_val < vap->iv_bss->ni_intval)
   3264   1.60.18.1      phil 			vap->iv_quiet_duration = ireq->i_val;
   3265   1.60.18.1      phil 		else
   3266   1.60.18.1      phil 			error = EINVAL;
   3267   1.60.18.1      phil 		break;
   3268   1.60.18.1      phil 	case IEEE80211_IOC_BGSCAN:
   3269   1.60.18.1      phil 		if (ireq->i_val) {
   3270   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_BGSCAN) == 0)
   3271   1.60.18.1      phil 				return EOPNOTSUPP;
   3272   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_BGSCAN;
   3273   1.60.18.1      phil 		} else
   3274   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_BGSCAN;
   3275   1.60.18.1      phil 		break;
   3276   1.60.18.1      phil 	case IEEE80211_IOC_BGSCAN_IDLE:
   3277   1.60.18.1      phil 		if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
   3278   1.60.18.1      phil 			vap->iv_bgscanidle = ireq->i_val*hz/1000;
   3279   1.60.18.1      phil 		else
   3280   1.60.18.1      phil 			error = EINVAL;
   3281   1.60.18.1      phil 		break;
   3282   1.60.18.1      phil 	case IEEE80211_IOC_BGSCAN_INTERVAL:
   3283   1.60.18.1      phil 		if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
   3284   1.60.18.1      phil 			vap->iv_bgscanintvl = ireq->i_val*hz;
   3285   1.60.18.1      phil 		else
   3286   1.60.18.1      phil 			error = EINVAL;
   3287   1.60.18.1      phil 		break;
   3288   1.60.18.1      phil 	case IEEE80211_IOC_SCANVALID:
   3289   1.60.18.1      phil 		if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
   3290   1.60.18.1      phil 			vap->iv_scanvalid = ireq->i_val*hz;
   3291   1.60.18.1      phil 		else
   3292   1.60.18.1      phil 			error = EINVAL;
   3293   1.60.18.1      phil 		break;
   3294   1.60.18.1      phil 	case IEEE80211_IOC_FRAGTHRESHOLD:
   3295   1.60.18.1      phil 		if ((vap->iv_caps & IEEE80211_C_TXFRAG) == 0 &&
   3296   1.60.18.1      phil 		    ireq->i_val != IEEE80211_FRAG_MAX)
   3297   1.60.18.1      phil 			return EOPNOTSUPP;
   3298   1.60.18.1      phil 		if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
   3299   1.60.18.1      phil 		      ireq->i_val <= IEEE80211_FRAG_MAX))
   3300   1.60.18.1      phil 			return EINVAL;
   3301   1.60.18.1      phil 		vap->iv_fragthreshold = ireq->i_val;
   3302   1.60.18.1      phil 		error = ERESTART;
   3303   1.60.18.1      phil 		break;
   3304   1.60.18.1      phil 	case IEEE80211_IOC_BURST:
   3305   1.60.18.1      phil 		if (ireq->i_val) {
   3306   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_BURST) == 0)
   3307   1.60.18.1      phil 				return EOPNOTSUPP;
   3308   1.60.18.1      phil 			ieee80211_syncflag(vap, IEEE80211_F_BURST);
   3309   1.60.18.1      phil 		} else
   3310   1.60.18.1      phil 			ieee80211_syncflag(vap, -IEEE80211_F_BURST);
   3311   1.60.18.1      phil 		error = ERESTART;
   3312   1.60.18.1      phil 		break;
   3313   1.60.18.1      phil 	case IEEE80211_IOC_BMISSTHRESHOLD:
   3314   1.60.18.1      phil 		if (!(IEEE80211_HWBMISS_MIN <= ireq->i_val &&
   3315   1.60.18.1      phil 		      ireq->i_val <= IEEE80211_HWBMISS_MAX))
   3316   1.60.18.1      phil 			return EINVAL;
   3317   1.60.18.1      phil 		vap->iv_bmissthreshold = ireq->i_val;
   3318   1.60.18.1      phil 		error = ERESTART;
   3319   1.60.18.1      phil 		break;
   3320   1.60.18.1      phil 	case IEEE80211_IOC_CURCHAN:
   3321   1.60.18.1      phil 		error = ieee80211_ioctl_setcurchan(vap, ireq);
   3322   1.60.18.1      phil 		break;
   3323   1.60.18.1      phil 	case IEEE80211_IOC_SHORTGI:
   3324   1.60.18.1      phil 		if (ireq->i_val) {
   3325   1.60.18.1      phil #define	IEEE80211_HTCAP_SHORTGI \
   3326   1.60.18.1      phil 	(IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
   3327   1.60.18.1      phil 			if (((ireq->i_val ^ vap->iv_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
   3328   1.60.18.1      phil 				return EINVAL;
   3329   1.60.18.1      phil 			if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
   3330   1.60.18.1      phil 				vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI20;
   3331   1.60.18.1      phil 			if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
   3332   1.60.18.1      phil 				vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI40;
   3333   1.60.18.1      phil #undef IEEE80211_HTCAP_SHORTGI
   3334   1.60.18.1      phil 		} else
   3335   1.60.18.1      phil 			vap->iv_flags_ht &=
   3336   1.60.18.1      phil 			    ~(IEEE80211_FHT_SHORTGI20 | IEEE80211_FHT_SHORTGI40);
   3337   1.60.18.1      phil 		error = ERESTART;
   3338   1.60.18.1      phil 		break;
   3339   1.60.18.1      phil 	case IEEE80211_IOC_AMPDU:
   3340   1.60.18.1      phil 		if (ireq->i_val && (vap->iv_htcaps & IEEE80211_HTC_AMPDU) == 0)
   3341   1.60.18.1      phil 			return EINVAL;
   3342   1.60.18.1      phil 		if (ireq->i_val & 1)
   3343   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_TX;
   3344   1.60.18.1      phil 		else
   3345   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_TX;
   3346   1.60.18.1      phil 		if (ireq->i_val & 2)
   3347   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_RX;
   3348   1.60.18.1      phil 		else
   3349   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX;
   3350   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11n channel */
   3351   1.60.18.1      phil 		if (isvapht(vap))
   3352   1.60.18.1      phil 			error = ERESTART;
   3353   1.60.18.1      phil 		break;
   3354   1.60.18.1      phil 	case IEEE80211_IOC_AMPDU_LIMIT:
   3355   1.60.18.1      phil 		/* XXX TODO: figure out ampdu_limit versus ampdu_rxmax */
   3356   1.60.18.1      phil 		if (!(IEEE80211_HTCAP_MAXRXAMPDU_8K <= ireq->i_val &&
   3357   1.60.18.1      phil 		      ireq->i_val <= IEEE80211_HTCAP_MAXRXAMPDU_64K))
   3358   1.60.18.1      phil 			return EINVAL;
   3359   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
   3360   1.60.18.1      phil 			vap->iv_ampdu_rxmax = ireq->i_val;
   3361   1.60.18.1      phil 		else
   3362   1.60.18.1      phil 			vap->iv_ampdu_limit = ireq->i_val;
   3363   1.60.18.1      phil 		error = ERESTART;
   3364   1.60.18.1      phil 		break;
   3365   1.60.18.1      phil 	case IEEE80211_IOC_AMPDU_DENSITY:
   3366   1.60.18.1      phil 		if (!(IEEE80211_HTCAP_MPDUDENSITY_NA <= ireq->i_val &&
   3367   1.60.18.1      phil 		      ireq->i_val <= IEEE80211_HTCAP_MPDUDENSITY_16))
   3368        1.19    dyoung 			return EINVAL;
   3369   1.60.18.1      phil 		vap->iv_ampdu_density = ireq->i_val;
   3370   1.60.18.1      phil 		error = ERESTART;
   3371   1.60.18.1      phil 		break;
   3372   1.60.18.1      phil 	case IEEE80211_IOC_AMSDU:
   3373   1.60.18.1      phil 		if (ireq->i_val && (vap->iv_htcaps & IEEE80211_HTC_AMSDU) == 0)
   3374        1.19    dyoung 			return EINVAL;
   3375   1.60.18.1      phil 		if (ireq->i_val & 1)
   3376   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_TX;
   3377   1.60.18.1      phil 		else
   3378   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_AMSDU_TX;
   3379   1.60.18.1      phil 		if (ireq->i_val & 2)
   3380   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_RX;
   3381        1.19    dyoung 		else
   3382   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_AMSDU_RX;
   3383   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11n channel */
   3384   1.60.18.1      phil 		if (isvapht(vap))
   3385   1.60.18.1      phil 			error = ERESTART;
   3386   1.60.18.1      phil 		break;
   3387   1.60.18.1      phil 	case IEEE80211_IOC_AMSDU_LIMIT:
   3388   1.60.18.1      phil 		/* XXX validate */
   3389   1.60.18.1      phil 		vap->iv_amsdu_limit = ireq->i_val;	/* XXX truncation? */
   3390   1.60.18.1      phil 		break;
   3391   1.60.18.1      phil 	case IEEE80211_IOC_PUREN:
   3392   1.60.18.1      phil 		if (ireq->i_val) {
   3393   1.60.18.1      phil 			if ((vap->iv_flags_ht & IEEE80211_FHT_HT) == 0)
   3394   1.60.18.1      phil 				return EINVAL;
   3395   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_PUREN;
   3396   1.60.18.1      phil 		} else
   3397   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_PUREN;
   3398   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11n channel */
   3399   1.60.18.1      phil 		if (isvapht(vap))
   3400   1.60.18.1      phil 			error = ERESTART;
   3401   1.60.18.1      phil 		break;
   3402   1.60.18.1      phil 	case IEEE80211_IOC_DOTH:
   3403   1.60.18.1      phil 		if (ireq->i_val) {
   3404   1.60.18.1      phil #if 0
   3405   1.60.18.1      phil 			/* XXX no capability */
   3406   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_DOTH) == 0)
   3407   1.60.18.1      phil 				return EOPNOTSUPP;
   3408   1.60.18.1      phil #endif
   3409   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_DOTH;
   3410   1.60.18.1      phil 		} else
   3411   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_DOTH;
   3412        1.19    dyoung 		error = ENETRESET;
   3413        1.19    dyoung 		break;
   3414   1.60.18.1      phil 	case IEEE80211_IOC_REGDOMAIN:
   3415   1.60.18.1      phil 		error = ieee80211_ioctl_setregdomain(vap, ireq);
   3416        1.19    dyoung 		break;
   3417   1.60.18.1      phil 	case IEEE80211_IOC_ROAM:
   3418   1.60.18.1      phil 		error = ieee80211_ioctl_setroam(vap, ireq);
   3419        1.19    dyoung 		break;
   3420   1.60.18.1      phil 	case IEEE80211_IOC_TXPARAMS:
   3421   1.60.18.1      phil 		error = ieee80211_ioctl_settxparams(vap, ireq);
   3422        1.19    dyoung 		break;
   3423   1.60.18.1      phil 	case IEEE80211_IOC_HTCOMPAT:
   3424   1.60.18.1      phil 		if (ireq->i_val) {
   3425   1.60.18.1      phil 			if ((vap->iv_flags_ht & IEEE80211_FHT_HT) == 0)
   3426   1.60.18.1      phil 				return EOPNOTSUPP;
   3427   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_HTCOMPAT;
   3428   1.60.18.1      phil 		} else
   3429   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_HTCOMPAT;
   3430   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11n channel */
   3431   1.60.18.1      phil 		if (isvapht(vap))
   3432   1.60.18.1      phil 			error = ERESTART;
   3433        1.19    dyoung 		break;
   3434   1.60.18.1      phil 	case IEEE80211_IOC_DWDS:
   3435   1.60.18.1      phil 		if (ireq->i_val) {
   3436   1.60.18.1      phil 			/* NB: DWDS only makes sense for WDS-capable devices */
   3437   1.60.18.1      phil 			if ((ic->ic_caps & IEEE80211_C_WDS) == 0)
   3438   1.60.18.1      phil 				return EOPNOTSUPP;
   3439   1.60.18.1      phil 			/* NB: DWDS is used only with ap+sta vaps */
   3440   1.60.18.1      phil 			if (vap->iv_opmode != IEEE80211_M_HOSTAP &&
   3441   1.60.18.1      phil 			    vap->iv_opmode != IEEE80211_M_STA)
   3442   1.60.18.1      phil 				return EINVAL;
   3443   1.60.18.1      phil 			vap->iv_flags |= IEEE80211_F_DWDS;
   3444   1.60.18.1      phil 			if (vap->iv_opmode == IEEE80211_M_STA)
   3445   1.60.18.1      phil 				vap->iv_flags_ext |= IEEE80211_FEXT_4ADDR;
   3446   1.60.18.1      phil 		} else {
   3447   1.60.18.1      phil 			vap->iv_flags &= ~IEEE80211_F_DWDS;
   3448   1.60.18.1      phil 			if (vap->iv_opmode == IEEE80211_M_STA)
   3449   1.60.18.1      phil 				vap->iv_flags_ext &= ~IEEE80211_FEXT_4ADDR;
   3450   1.60.18.1      phil 		}
   3451        1.19    dyoung 		break;
   3452   1.60.18.1      phil 	case IEEE80211_IOC_INACTIVITY:
   3453   1.60.18.1      phil 		if (ireq->i_val)
   3454   1.60.18.1      phil 			vap->iv_flags_ext |= IEEE80211_FEXT_INACT;
   3455   1.60.18.1      phil 		else
   3456   1.60.18.1      phil 			vap->iv_flags_ext &= ~IEEE80211_FEXT_INACT;
   3457        1.19    dyoung 		break;
   3458   1.60.18.1      phil 	case IEEE80211_IOC_APPIE:
   3459   1.60.18.1      phil 		error = ieee80211_ioctl_setappie(vap, ireq);
   3460   1.60.18.1      phil 		break;
   3461   1.60.18.1      phil 	case IEEE80211_IOC_WPS:
   3462   1.60.18.1      phil 		if (ireq->i_val) {
   3463   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_WPA) == 0)
   3464   1.60.18.1      phil 				return EOPNOTSUPP;
   3465   1.60.18.1      phil 			vap->iv_flags_ext |= IEEE80211_FEXT_WPS;
   3466        1.19    dyoung 		} else
   3467   1.60.18.1      phil 			vap->iv_flags_ext &= ~IEEE80211_FEXT_WPS;
   3468        1.19    dyoung 		break;
   3469   1.60.18.1      phil 	case IEEE80211_IOC_TSN:
   3470   1.60.18.1      phil 		if (ireq->i_val) {
   3471   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_WPA) == 0)
   3472   1.60.18.1      phil 				return EOPNOTSUPP;
   3473   1.60.18.1      phil 			vap->iv_flags_ext |= IEEE80211_FEXT_TSN;
   3474        1.19    dyoung 		} else
   3475   1.60.18.1      phil 			vap->iv_flags_ext &= ~IEEE80211_FEXT_TSN;
   3476        1.19    dyoung 		break;
   3477   1.60.18.1      phil 	case IEEE80211_IOC_CHANSWITCH:
   3478   1.60.18.1      phil 		error = ieee80211_ioctl_chanswitch(vap, ireq);
   3479   1.60.18.1      phil 		break;
   3480   1.60.18.1      phil 	case IEEE80211_IOC_DFS:
   3481   1.60.18.1      phil 		if (ireq->i_val) {
   3482   1.60.18.1      phil 			if ((vap->iv_caps & IEEE80211_C_DFS) == 0)
   3483   1.60.18.1      phil 				return EOPNOTSUPP;
   3484   1.60.18.1      phil 			/* NB: DFS requires 11h support */
   3485   1.60.18.1      phil 			if ((vap->iv_flags & IEEE80211_F_DOTH) == 0)
   3486   1.60.18.1      phil 				return EINVAL;
   3487   1.60.18.1      phil 			vap->iv_flags_ext |= IEEE80211_FEXT_DFS;
   3488   1.60.18.1      phil 		} else
   3489   1.60.18.1      phil 			vap->iv_flags_ext &= ~IEEE80211_FEXT_DFS;
   3490   1.60.18.1      phil 		break;
   3491   1.60.18.1      phil 	case IEEE80211_IOC_DOTD:
   3492        1.21    dyoung 		if (ireq->i_val)
   3493   1.60.18.1      phil 			vap->iv_flags_ext |= IEEE80211_FEXT_DOTD;
   3494        1.21    dyoung 		else
   3495   1.60.18.1      phil 			vap->iv_flags_ext &= ~IEEE80211_FEXT_DOTD;
   3496   1.60.18.1      phil 		if (vap->iv_opmode == IEEE80211_M_STA)
   3497        1.21    dyoung 			error = ENETRESET;
   3498        1.21    dyoung 		break;
   3499   1.60.18.1      phil 	case IEEE80211_IOC_HTPROTMODE:
   3500   1.60.18.1      phil 		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
   3501        1.26     skrll 			return EINVAL;
   3502   1.60.18.1      phil 		ic->ic_htprotmode = ireq->i_val ?
   3503   1.60.18.1      phil 		    IEEE80211_PROT_RTSCTS : IEEE80211_PROT_NONE;
   3504   1.60.18.1      phil 		/* NB: if not operating in 11n this can wait */
   3505   1.60.18.1      phil 		if (isvapht(vap))
   3506   1.60.18.1      phil 			error = ERESTART;
   3507   1.60.18.1      phil 		break;
   3508   1.60.18.1      phil 	case IEEE80211_IOC_STA_VLAN:
   3509   1.60.18.1      phil 		error = ieee80211_ioctl_setstavlan(vap, ireq);
   3510   1.60.18.1      phil 		break;
   3511   1.60.18.1      phil 	case IEEE80211_IOC_SMPS:
   3512   1.60.18.1      phil 		if ((ireq->i_val &~ IEEE80211_HTCAP_SMPS) != 0 ||
   3513   1.60.18.1      phil 		    ireq->i_val == 0x0008)	/* value of 2 is reserved */
   3514   1.60.18.1      phil 			return EINVAL;
   3515   1.60.18.1      phil 		if (ireq->i_val != IEEE80211_HTCAP_SMPS_OFF &&
   3516   1.60.18.1      phil 		    (vap->iv_htcaps & IEEE80211_HTC_SMPS) == 0)
   3517   1.60.18.1      phil 			return EOPNOTSUPP;
   3518   1.60.18.1      phil 		vap->iv_htcaps = (vap->iv_htcaps &~ IEEE80211_HTCAP_SMPS) |
   3519   1.60.18.1      phil 			ireq->i_val;
   3520   1.60.18.1      phil 		/* NB: if not operating in 11n this can wait */
   3521   1.60.18.1      phil 		if (isvapht(vap))
   3522   1.60.18.1      phil 			error = ERESTART;
   3523   1.60.18.1      phil 		break;
   3524   1.60.18.1      phil 	case IEEE80211_IOC_RIFS:
   3525   1.60.18.1      phil 		if (ireq->i_val != 0) {
   3526   1.60.18.1      phil 			if ((vap->iv_htcaps & IEEE80211_HTC_RIFS) == 0)
   3527   1.60.18.1      phil 				return EOPNOTSUPP;
   3528   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_RIFS;
   3529   1.60.18.1      phil 		} else
   3530   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_RIFS;
   3531   1.60.18.1      phil 		/* NB: if not operating in 11n this can wait */
   3532   1.60.18.1      phil 		if (isvapht(vap))
   3533   1.60.18.1      phil 			error = ERESTART;
   3534   1.60.18.1      phil 		break;
   3535   1.60.18.1      phil 	case IEEE80211_IOC_STBC:
   3536   1.60.18.1      phil 		/* Check if we can do STBC TX/RX before changing the setting */
   3537   1.60.18.1      phil 		if ((ireq->i_val & 1) &&
   3538   1.60.18.1      phil 		    ((vap->iv_htcaps & IEEE80211_HTCAP_TXSTBC) == 0))
   3539   1.60.18.1      phil 			return EOPNOTSUPP;
   3540   1.60.18.1      phil 		if ((ireq->i_val & 2) &&
   3541   1.60.18.1      phil 		    ((vap->iv_htcaps & IEEE80211_HTCAP_RXSTBC) == 0))
   3542   1.60.18.1      phil 			return EOPNOTSUPP;
   3543   1.60.18.1      phil 
   3544   1.60.18.1      phil 		/* TX */
   3545   1.60.18.1      phil 		if (ireq->i_val & 1)
   3546   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_STBC_TX;
   3547   1.60.18.1      phil 		else
   3548   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_STBC_TX;
   3549   1.60.18.1      phil 
   3550   1.60.18.1      phil 		/* RX */
   3551   1.60.18.1      phil 		if (ireq->i_val & 2)
   3552   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_STBC_RX;
   3553   1.60.18.1      phil 		else
   3554   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_STBC_RX;
   3555   1.60.18.1      phil 
   3556   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11n channel */
   3557   1.60.18.1      phil 		if (isvapht(vap))
   3558   1.60.18.1      phil 			error = ERESTART;
   3559   1.60.18.1      phil 		break;
   3560   1.60.18.1      phil 	case IEEE80211_IOC_LDPC:
   3561   1.60.18.1      phil 		/* Check if we can do LDPC TX/RX before changing the setting */
   3562   1.60.18.1      phil 		if ((ireq->i_val & 1) &&
   3563   1.60.18.1      phil 		    (vap->iv_htcaps & IEEE80211_HTC_TXLDPC) == 0)
   3564   1.60.18.1      phil 			return EOPNOTSUPP;
   3565   1.60.18.1      phil 		if ((ireq->i_val & 2) &&
   3566   1.60.18.1      phil 		    (vap->iv_htcaps & IEEE80211_HTCAP_LDPC) == 0)
   3567   1.60.18.1      phil 			return EOPNOTSUPP;
   3568   1.60.18.1      phil 
   3569   1.60.18.1      phil 		/* TX */
   3570   1.60.18.1      phil 		if (ireq->i_val & 1)
   3571   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_LDPC_TX;
   3572   1.60.18.1      phil 		else
   3573   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_LDPC_TX;
   3574   1.60.18.1      phil 
   3575   1.60.18.1      phil 		/* RX */
   3576   1.60.18.1      phil 		if (ireq->i_val & 2)
   3577   1.60.18.1      phil 			vap->iv_flags_ht |= IEEE80211_FHT_LDPC_RX;
   3578   1.60.18.1      phil 		else
   3579   1.60.18.1      phil 			vap->iv_flags_ht &= ~IEEE80211_FHT_LDPC_RX;
   3580   1.60.18.1      phil 
   3581   1.60.18.1      phil 		/* NB: reset only if we're operating on an 11n channel */
   3582   1.60.18.1      phil 		if (isvapht(vap))
   3583   1.60.18.1      phil 			error = ERESTART;
   3584   1.60.18.1      phil 		break;
   3585   1.60.18.1      phil 
   3586   1.60.18.1      phil 	/* VHT */
   3587   1.60.18.1      phil 	case IEEE80211_IOC_VHTCONF:
   3588   1.60.18.1      phil 		if (ireq->i_val & 1)
   3589   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, IEEE80211_FVHT_VHT);
   3590   1.60.18.1      phil 		else
   3591   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_VHT);
   3592   1.60.18.1      phil 
   3593   1.60.18.1      phil 		if (ireq->i_val & 2)
   3594   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, IEEE80211_FVHT_USEVHT40);
   3595   1.60.18.1      phil 		else
   3596   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_USEVHT40);
   3597   1.60.18.1      phil 
   3598   1.60.18.1      phil 		if (ireq->i_val & 4)
   3599   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, IEEE80211_FVHT_USEVHT80);
   3600   1.60.18.1      phil 		else
   3601   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_USEVHT80);
   3602   1.60.18.1      phil 
   3603   1.60.18.1      phil 		if (ireq->i_val & 8)
   3604   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, IEEE80211_FVHT_USEVHT80P80);
   3605   1.60.18.1      phil 		else
   3606   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_USEVHT80P80);
   3607   1.60.18.1      phil 
   3608   1.60.18.1      phil 		if (ireq->i_val & 16)
   3609   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, IEEE80211_FVHT_USEVHT160);
   3610   1.60.18.1      phil 		else
   3611   1.60.18.1      phil 			ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_USEVHT160);
   3612   1.60.18.1      phil 
   3613   1.60.18.1      phil 		error = ENETRESET;
   3614        1.26     skrll 		break;
   3615   1.60.18.1      phil 
   3616        1.19    dyoung 	default:
   3617   1.60.18.1      phil 		error = ieee80211_ioctl_setdefault(vap, ireq);
   3618        1.19    dyoung 		break;
   3619        1.19    dyoung 	}
   3620   1.60.18.1      phil 	/*
   3621   1.60.18.1      phil 	 * The convention is that ENETRESET means an operation
   3622   1.60.18.1      phil 	 * requires a complete re-initialization of the device (e.g.
   3623   1.60.18.1      phil 	 * changing something that affects the association state).
   3624   1.60.18.1      phil 	 * ERESTART means the request may be handled with only a
   3625   1.60.18.1      phil 	 * reload of the hardware state.  We hand ERESTART requests
   3626   1.60.18.1      phil 	 * to the iv_reset callback so the driver can decide.  If
   3627   1.60.18.1      phil 	 * a device does not fillin iv_reset then it defaults to one
   3628   1.60.18.1      phil 	 * that returns ENETRESET.  Otherwise a driver may return
   3629   1.60.18.1      phil 	 * ENETRESET (in which case a full reset will be done) or
   3630   1.60.18.1      phil 	 * 0 to mean there's no need to do anything (e.g. when the
   3631   1.60.18.1      phil 	 * change has no effect on the driver/device).
   3632   1.60.18.1      phil 	 */
   3633   1.60.18.1      phil 	if (error == ERESTART)
   3634   1.60.18.1      phil 		error = IFNET_IS_UP_RUNNING(vap->iv_ifp) ?
   3635   1.60.18.1      phil 		    vap->iv_reset(vap, ireq->i_type) : 0;
   3636   1.60.18.1      phil 	if (error == ENETRESET) {
   3637   1.60.18.1      phil 		/* XXX need to re-think AUTO handling */
   3638   1.60.18.1      phil 		if (IS_UP_AUTO(vap))
   3639   1.60.18.3      phil #if __FreeBSD__
   3640   1.60.18.1      phil 			ieee80211_init(vap);
   3641  1.60.18.10       nat 		error = 0;
   3642   1.60.18.3      phil #elif __NetBSD__
   3643   1.60.18.3      phil 			/* arg is a vap in 802.11 code */
   3644   1.60.18.3      phil 			ieee80211_init((struct ifnet *)vap);
   3645   1.60.18.3      phil #endif
   3646   1.60.18.1      phil 	}
   3647        1.19    dyoung 	return error;
   3648        1.19    dyoung }
   3649        1.19    dyoung 
   3650        1.19    dyoung int
   3651   1.60.18.1      phil ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
   3652        1.19    dyoung {
   3653   1.60.18.1      phil 	struct ieee80211vap *vap = ifp->if_softc;
   3654   1.60.18.1      phil 	struct ieee80211com *ic = vap->iv_ic;
   3655   1.60.18.1      phil 	int error = 0, wait = 0;
   3656        1.19    dyoung 	struct ifreq *ifr;
   3657        1.19    dyoung 	struct ifaddr *ifa;			/* XXX */
   3658   1.60.18.4      phil #if __NetBSD__
   3659   1.60.18.4      phil 	struct ieee80211_nwid nwid;
   3660   1.60.18.4      phil 	//	struct ieee80211_nwkey *nwkey;
   3661   1.60.18.7      phil 	struct ieee80211_power *power;
   3662   1.60.18.7      phil 	struct ieee80211chanreq *chanreq;
   3663   1.60.18.6      phil 	struct ieee80211_bssid *bssid;
   3664   1.60.18.7      phil 	struct ieee80211_channel *chan;
   3665   1.60.18.7      phil 	struct ieee80211req ireq;
   3666   1.60.18.4      phil 
   3667   1.60.18.4      phil 	ifr = (struct ifreq *)data;
   3668   1.60.18.4      phil #endif
   3669   1.60.18.4      phil 
   3670        1.19    dyoung 	switch (cmd) {
   3671   1.60.18.1      phil 	case SIOCSIFFLAGS:
   3672   1.60.18.1      phil 		IEEE80211_LOCK(ic);
   3673   1.60.18.1      phil 		if ((ifp->if_flags ^ vap->iv_ifflags) & IFF_PROMISC) {
   3674   1.60.18.4      phil 			printf ("    promisc mode\n");
   3675   1.60.18.1      phil 			/*
   3676   1.60.18.1      phil 			 * Enable promiscuous mode when:
   3677   1.60.18.1      phil 			 * 1. Interface is not a member of bridge, or
   3678   1.60.18.1      phil 			 * 2. Requested by user, or
   3679   1.60.18.1      phil 			 * 3. In monitor (or adhoc-demo) mode.
   3680   1.60.18.1      phil 			 */
   3681   1.60.18.1      phil 			if (ifp->if_bridge == NULL ||
   3682   1.60.18.1      phil 			    (ifp->if_flags & IFF_PPROMISC) != 0 ||
   3683   1.60.18.1      phil 			    vap->iv_opmode == IEEE80211_M_MONITOR ||
   3684   1.60.18.1      phil 			    (vap->iv_opmode == IEEE80211_M_AHDEMO &&
   3685   1.60.18.1      phil 			    (vap->iv_caps & IEEE80211_C_TDMA) == 0)) {
   3686   1.60.18.1      phil 				ieee80211_promisc(vap,
   3687   1.60.18.1      phil 				    ifp->if_flags & IFF_PROMISC);
   3688   1.60.18.1      phil 				vap->iv_ifflags ^= IFF_PROMISC;
   3689   1.60.18.1      phil 			}
   3690   1.60.18.1      phil 		}
   3691   1.60.18.1      phil 		if ((ifp->if_flags ^ vap->iv_ifflags) & IFF_ALLMULTI) {
   3692   1.60.18.4      phil 			printf ("    allmulti\n");
   3693   1.60.18.1      phil 			ieee80211_allmulti(vap, ifp->if_flags & IFF_ALLMULTI);
   3694   1.60.18.1      phil 			vap->iv_ifflags ^= IFF_ALLMULTI;
   3695   1.60.18.1      phil 		}
   3696   1.60.18.1      phil 		if (ifp->if_flags & IFF_UP) {
   3697   1.60.18.4      phil 			printf ("    up flag\n");
   3698   1.60.18.1      phil 			/*
   3699   1.60.18.1      phil 			 * Bring ourself up unless we're already operational.
   3700   1.60.18.1      phil 			 * If we're the first vap and the parent is not up
   3701   1.60.18.1      phil 			 * then it will automatically be brought up as a
   3702   1.60.18.1      phil 			 * side-effect of bringing ourself up.
   3703   1.60.18.1      phil 			 */
   3704   1.60.18.1      phil 			if (vap->iv_state == IEEE80211_S_INIT) {
   3705   1.60.18.1      phil 				if (ic->ic_nrunning == 0)
   3706   1.60.18.1      phil 					wait = 1;
   3707   1.60.18.4      phil 				printf ("Should call start_locked ...\n");
   3708   1.60.18.4      phil 				wait = 0;
   3709   1.60.18.4      phil 				// ieee80211_start_locked(vap);
   3710   1.60.18.1      phil 			}
   3711   1.60.18.2      phil #if __FreeBSD__
   3712   1.60.18.1      phil 		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
   3713   1.60.18.2      phil #elif __NetBSD__
   3714   1.60.18.2      phil 		} else if (ifp->if_flags & IFF_RUNNING) {
   3715   1.60.18.2      phil #endif
   3716   1.60.18.1      phil 			/*
   3717   1.60.18.1      phil 			 * Stop ourself.  If we are the last vap to be
   3718   1.60.18.1      phil 			 * marked down the parent will also be taken down.
   3719   1.60.18.1      phil 			 */
   3720   1.60.18.1      phil 			if (ic->ic_nrunning == 1)
   3721   1.60.18.1      phil 				wait = 1;
   3722   1.60.18.1      phil 			ieee80211_stop_locked(vap);
   3723   1.60.18.1      phil 		}
   3724   1.60.18.1      phil 		IEEE80211_UNLOCK(ic);
   3725   1.60.18.1      phil 		/* Wait for parent ioctl handler if it was queued */
   3726   1.60.18.1      phil 		if (wait) {
   3727   1.60.18.1      phil 			ieee80211_waitfor_parent(ic);
   3728   1.60.18.1      phil 
   3729   1.60.18.1      phil 			/*
   3730   1.60.18.1      phil 			 * Check if the MAC address was changed
   3731   1.60.18.1      phil 			 * via SIOCSIFLLADDR ioctl.
   3732   1.60.18.1      phil 			 */
   3733   1.60.18.1      phil 			if_addr_rlock(ifp);
   3734   1.60.18.1      phil 			if ((ifp->if_flags & IFF_UP) == 0 &&
   3735   1.60.18.7      phil 			    !IEEE80211_ADDR_EQ(vap->iv_myaddr, IF_LLADDR(ifp))) {
   3736   1.60.18.1      phil 				IEEE80211_ADDR_COPY(vap->iv_myaddr,
   3737   1.60.18.1      phil 				    IF_LLADDR(ifp));
   3738   1.60.18.7      phil 				printf ("vap->iv_myaddr changed in ioctl to %s\n",
   3739   1.60.18.7      phil 					ether_sprintf(vap->iv_myaddr));
   3740   1.60.18.7      phil 			}
   3741   1.60.18.7      phil 
   3742   1.60.18.1      phil 			if_addr_runlock(ifp);
   3743   1.60.18.1      phil 		}
   3744   1.60.18.1      phil 		break;
   3745   1.60.18.1      phil 	case SIOCADDMULTI:
   3746   1.60.18.1      phil 	case SIOCDELMULTI:
   3747   1.60.18.1      phil 		ieee80211_runtask(ic, &ic->ic_mcast_task);
   3748   1.60.18.1      phil 		break;
   3749   1.60.18.7      phil #ifdef OSIOCSIFMEDIA
   3750   1.60.18.7      phil 	case OSIOCSIFMEDIA:
   3751   1.60.18.7      phil #endif
   3752        1.19    dyoung 	case SIOCSIFMEDIA:
   3753        1.19    dyoung 	case SIOCGIFMEDIA:
   3754   1.60.18.1      phil 		ifr = (struct ifreq *)data;
   3755   1.60.18.1      phil 		error = ifmedia_ioctl(ifp, ifr, &vap->iv_media, cmd);
   3756        1.19    dyoung 		break;
   3757        1.19    dyoung 	case SIOCG80211:
   3758   1.60.18.1      phil 		error = ieee80211_ioctl_get80211(vap, cmd,
   3759        1.19    dyoung 				(struct ieee80211req *) data);
   3760        1.19    dyoung 		break;
   3761        1.19    dyoung 	case SIOCS80211:
   3762   1.60.18.1      phil 		error = priv_check(curthread, PRIV_NET80211_MANAGE);
   3763        1.19    dyoung 		if (error == 0)
   3764   1.60.18.1      phil 			error = ieee80211_ioctl_set80211(vap, cmd,
   3765        1.19    dyoung 					(struct ieee80211req *) data);
   3766         1.1    dyoung 		break;
   3767   1.60.18.8  christos #ifdef __NetBSD__
   3768   1.60.18.8  christos 	case OSIOCG80211STATS:
   3769   1.60.18.8  christos 	case OSIOCG80211ZSTATS:
   3770   1.60.18.8  christos 		(void)module_autoload("compat_20", MODULE_CLASS_EXEC);
   3771   1.60.18.8  christos 		MODULE_HOOK_CALL(ieee80211_ioctl_20_hook, (vap, cmd, data),
   3772   1.60.18.8  christos 		    enosys(), error);
   3773   1.60.18.8  christos 		break;
   3774   1.60.18.8  christos #endif
   3775   1.60.18.7      phil #ifdef SIOCG80211ZSTATS
   3776   1.60.18.7      phil 	case SIOCG80211ZSTATS:
   3777   1.60.18.7      phil #endif
   3778        1.19    dyoung 	case SIOCG80211STATS:
   3779        1.19    dyoung 		ifr = (struct ifreq *)data;
   3780   1.60.18.2      phil #if __FreeBSD__
   3781   1.60.18.1      phil 		copyout(&vap->iv_stats, ifr_data_get_ptr(ifr),
   3782   1.60.18.1      phil 		    sizeof (vap->iv_stats));
   3783   1.60.18.2      phil #elif__NetBSD__
   3784   1.60.18.8  christos 		s = splnet();
   3785   1.60.18.8  christos 		error = copyout(&vap->iv_stats, ifr->ifr_buf,
   3786   1.60.18.7      phil 			sizeof (vap->iv_stats) <= ifr->ifr_buflen
   3787   1.60.18.7      phil 			? sizeof (vap->iv_stats) : ifr->ifr_buflen);
   3788   1.60.18.8  christos 		if (error == 0 && cmd == SIOCG80211ZSTATS)
   3789   1.60.18.8  christos 			(void)memset(&vap->iv_stats, 0, sizeof(vap->iv_stats));
   3790   1.60.18.8  christos 		splx(s);
   3791   1.60.18.2      phil #endif
   3792        1.19    dyoung 		break;
   3793        1.19    dyoung 	case SIOCSIFMTU:
   3794        1.19    dyoung 		ifr = (struct ifreq *)data;
   3795        1.19    dyoung 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
   3796        1.19    dyoung 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
   3797        1.19    dyoung 			error = EINVAL;
   3798   1.60.18.8  christos 		else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
   3799   1.60.18.8  christos 			error = 0;
   3800        1.19    dyoung 		break;
   3801   1.60.18.1      phil 	case SIOCSIFADDR:
   3802   1.60.18.1      phil 		/*
   3803   1.60.18.1      phil 		 * XXX Handle this directly so we can suppress if_init calls.
   3804   1.60.18.1      phil 		 * XXX This should be done in ether_ioctl but for the moment
   3805   1.60.18.1      phil 		 * XXX there are too many other parts of the system that
   3806   1.60.18.1      phil 		 * XXX set IFF_UP and so suppress if_init being called when
   3807   1.60.18.1      phil 		 * XXX it should be.
   3808   1.60.18.1      phil 		 */
   3809   1.60.18.1      phil 		ifa = (struct ifaddr *) data;
   3810   1.60.18.1      phil 		switch (ifa->ifa_addr->sa_family) {
   3811   1.60.18.1      phil #ifdef INET
   3812   1.60.18.1      phil 		case AF_INET:
   3813   1.60.18.1      phil 			if ((ifp->if_flags & IFF_UP) == 0) {
   3814   1.60.18.1      phil 				ifp->if_flags |= IFF_UP;
   3815   1.60.18.6      phil #if __FreeBSD__
   3816   1.60.18.1      phil 				ifp->if_init(ifp->if_softc);
   3817   1.60.18.6      phil #elif __NetBSD__
   3818   1.60.18.6      phil 				ifp->if_init(ifp);
   3819   1.60.18.6      phil #endif
   3820         1.2    dyoung 			}
   3821   1.60.18.1      phil 			arp_ifinit(ifp, ifa);
   3822         1.2    dyoung 			break;
   3823   1.60.18.1      phil #endif
   3824         1.2    dyoung 		default:
   3825   1.60.18.1      phil 			if ((ifp->if_flags & IFF_UP) == 0) {
   3826   1.60.18.1      phil 				ifp->if_flags |= IFF_UP;
   3827   1.60.18.6      phil #if __FreeBSD__
   3828   1.60.18.1      phil 				ifp->if_init(ifp->if_softc);
   3829   1.60.18.6      phil #elif __NetBSD__
   3830   1.60.18.6      phil 				ifp->if_init(ifp);
   3831   1.60.18.6      phil #endif
   3832         1.2    dyoung 			}
   3833         1.2    dyoung 			break;
   3834         1.2    dyoung 		}
   3835         1.2    dyoung 		break;
   3836   1.60.18.4      phil #if __NetBSD__
   3837   1.60.18.4      phil 	case SIOCS80211NWID:
   3838   1.60.18.4      phil 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
   3839   1.60.18.4      phil 			break;
   3840   1.60.18.4      phil 		if (nwid.i_len > IEEE80211_NWID_LEN) {
   3841   1.60.18.4      phil 			error = EINVAL;
   3842   1.60.18.4      phil 			break;
   3843   1.60.18.4      phil 		}
   3844   1.60.18.4      phil 		memset(vap->iv_des_ssid, 0, IEEE80211_NWID_LEN);
   3845   1.60.18.4      phil 		vap->iv_des_ssid[0].len = nwid.i_len;
   3846   1.60.18.4      phil 		memcpy(vap->iv_des_ssid[0].ssid, nwid.i_nwid, nwid.i_len);
   3847   1.60.18.4      phil 		error = ENETRESET;
   3848   1.60.18.4      phil 		break;
   3849   1.60.18.4      phil 	case SIOCG80211NWID:
   3850   1.60.18.4      phil 		memset(&nwid, 0, sizeof(nwid));
   3851   1.60.18.4      phil 		switch (vap->iv_state) {
   3852   1.60.18.4      phil 		case IEEE80211_S_INIT:
   3853   1.60.18.4      phil 		case IEEE80211_S_SCAN:
   3854   1.60.18.4      phil 			nwid.i_len  = vap->iv_des_ssid[0].len;
   3855   1.60.18.4      phil 			memcpy(nwid.i_nwid, vap->iv_des_ssid[0].ssid,
   3856   1.60.18.4      phil 			    nwid.i_len);
   3857   1.60.18.4      phil 			break;
   3858   1.60.18.4      phil 		default:
   3859   1.60.18.4      phil 			nwid.i_len = vap->iv_bss->ni_esslen;
   3860   1.60.18.4      phil 			memcpy(nwid.i_nwid, vap->iv_bss->ni_essid, nwid.i_len);
   3861   1.60.18.4      phil 			break;
   3862   1.60.18.4      phil 		}
   3863   1.60.18.4      phil 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
   3864   1.60.18.4      phil 		break;
   3865   1.60.18.4      phil 	case SIOCS80211NWKEY:
   3866   1.60.18.4      phil 	case SIOCG80211NWKEY:
   3867   1.60.18.6      phil 		printf ("NetBSD NWKEY ioctl\n"); // NNN
   3868   1.60.18.4      phil 		error = ENOTTY;
   3869   1.60.18.4      phil 	        break;
   3870   1.60.18.4      phil 	case SIOCS80211POWER:
   3871   1.60.18.7      phil 		power = (struct ieee80211_power *)data;
   3872   1.60.18.7      phil 		ic->ic_lintval = power->i_maxsleep;
   3873   1.60.18.7      phil 		if (power->i_enabled != 0) {
   3874   1.60.18.7      phil 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
   3875   1.60.18.7      phil 				error = EINVAL;
   3876   1.60.18.7      phil 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
   3877   1.60.18.7      phil 				ic->ic_flags |= IEEE80211_F_PMGTON;
   3878   1.60.18.7      phil 				error = ENETRESET;
   3879   1.60.18.7      phil 			}
   3880   1.60.18.7      phil 		} else {
   3881   1.60.18.7      phil 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
   3882   1.60.18.7      phil 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
   3883   1.60.18.7      phil 				error = ENETRESET;
   3884   1.60.18.7      phil 			}
   3885   1.60.18.7      phil 		}
   3886   1.60.18.7      phil 		break;
   3887   1.60.18.7      phil 	case SIOCG80211POWER:
   3888   1.60.18.7      phil 		power = (struct ieee80211_power *)data;
   3889   1.60.18.7      phil 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
   3890   1.60.18.7      phil 		power->i_maxsleep = ic->ic_lintval;
   3891   1.60.18.4      phil 		break;
   3892   1.60.18.6      phil 	case SIOCS80211BSSID:
   3893   1.60.18.6      phil 		bssid = (struct ieee80211_bssid *)data;
   3894   1.60.18.6      phil 		IEEE80211_ADDR_COPY(vap->iv_des_bssid, bssid->i_bssid);
   3895   1.60.18.6      phil 		if (IEEE80211_ADDR_EQ(vap->iv_des_bssid, zerobssid))
   3896   1.60.18.6      phil 			vap->iv_flags &= ~IEEE80211_F_DESBSSID;
   3897   1.60.18.6      phil 		else
   3898   1.60.18.6      phil 			vap->iv_flags |= IEEE80211_F_DESBSSID;
   3899   1.60.18.6      phil 		error = ENETRESET;
   3900   1.60.18.6      phil 		break;
   3901   1.60.18.6      phil 	case SIOCG80211BSSID:
   3902   1.60.18.6      phil 		bssid = (struct ieee80211_bssid *)data;
   3903   1.60.18.6      phil 		switch (vap->iv_state) {
   3904   1.60.18.6      phil 		case IEEE80211_S_RUN:
   3905   1.60.18.6      phil 		case IEEE80211_S_SLEEP:
   3906   1.60.18.6      phil 			IEEE80211_ADDR_COPY(bssid->i_bssid,
   3907   1.60.18.6      phil 			    vap->iv_opmode == IEEE80211_M_WDS ?
   3908   1.60.18.6      phil 			    vap->iv_bss->ni_macaddr : vap->iv_bss->ni_bssid);
   3909   1.60.18.6      phil 			break;
   3910   1.60.18.6      phil 		case IEEE80211_S_INIT:
   3911   1.60.18.6      phil 		case IEEE80211_S_SCAN:
   3912   1.60.18.6      phil 			if (vap->iv_opmode == IEEE80211_M_HOSTAP)
   3913   1.60.18.6      phil 				IEEE80211_ADDR_COPY(bssid->i_bssid,
   3914   1.60.18.6      phil 				    vap->iv_myaddr);
   3915   1.60.18.6      phil 			else if (vap->iv_flags & IEEE80211_F_DESBSSID)
   3916   1.60.18.6      phil 				IEEE80211_ADDR_COPY(bssid->i_bssid,
   3917   1.60.18.6      phil 				    vap->iv_des_bssid);
   3918   1.60.18.6      phil 			else
   3919   1.60.18.6      phil 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
   3920   1.60.18.6      phil 
   3921   1.60.18.6      phil 			break;
   3922   1.60.18.6      phil 		default:
   3923   1.60.18.6      phil 			memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
   3924   1.60.18.6      phil 		}
   3925   1.60.18.6      phil 		break;
   3926   1.60.18.7      phil 	case SIOCS80211CHANNEL:
   3927   1.60.18.7      phil 		/* Use deprecated ieee80211_ioctl_setchannel code. NNN? */
   3928   1.60.18.7      phil 		chanreq = (struct ieee80211chanreq *)data;
   3929   1.60.18.7      phil 		ireq.i_val = chanreq->i_channel;
   3930   1.60.18.7      phil 		error = ieee80211_ioctl_setchannel(vap, &ireq);
   3931   1.60.18.7      phil 		break;
   3932   1.60.18.7      phil 	case SIOCG80211CHANNEL:
   3933   1.60.18.7      phil 		chanreq = (struct ieee80211chanreq *)data;
   3934   1.60.18.7      phil 		switch (vap->iv_state) {
   3935   1.60.18.7      phil 		case IEEE80211_S_INIT:
   3936   1.60.18.7      phil 		case IEEE80211_S_SCAN:
   3937   1.60.18.7      phil 			if (vap->iv_opmode == IEEE80211_M_STA)
   3938   1.60.18.7      phil 				chan = vap->iv_des_chan;
   3939   1.60.18.7      phil 			else
   3940   1.60.18.7      phil 				chan = ic->ic_bsschan;  // NNN ibss chan?
   3941   1.60.18.7      phil 			break;
   3942   1.60.18.7      phil 		default:
   3943   1.60.18.7      phil 			chan = ic->ic_curchan;
   3944   1.60.18.7      phil 			break;
   3945   1.60.18.7      phil 		}
   3946   1.60.18.7      phil 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
   3947   1.60.18.7      phil 		break;
   3948   1.60.18.4      phil #endif
   3949         1.2    dyoung 	default:
   3950   1.60.18.1      phil 		/*
   3951   1.60.18.1      phil 		 * Pass unknown ioctls first to the driver, and if it
   3952   1.60.18.1      phil 		 * returns ENOTTY, then to the generic Ethernet handler.
   3953   1.60.18.1      phil 		 */
   3954   1.60.18.1      phil 		if (ic->ic_ioctl != NULL &&
   3955   1.60.18.1      phil 		    (error = ic->ic_ioctl(ic, cmd, data)) != ENOTTY)
   3956   1.60.18.1      phil 			break;
   3957         1.2    dyoung 		error = ether_ioctl(ifp, cmd, data);
   3958   1.60.18.7      phil 		if (error == ENOTTY) {
   3959   1.60.18.7      phil 			printf ("ieee80211_ioctl: cmd is 0x%lx. ('%c', %ld)\n",
   3960   1.60.18.7      phil 				cmd, (char) ((cmd>>8) & 0xff), cmd & 0xff );
   3961   1.60.18.4      phil 			printf ("Unknown 802.11 IOCTL.\n"); /* NNN */
   3962   1.60.18.7      phil 		}
   3963         1.2    dyoung 		break;
   3964         1.2    dyoung 	}
   3965   1.60.18.1      phil 	return (error);
   3966         1.2    dyoung }
   3967