Home | History | Annotate | Line # | Download | only in net80211
ieee80211_ioctl.c revision 1.48.4.1
      1      1.48    dyoung /*	$NetBSD: ieee80211_ioctl.c,v 1.48.4.1 2008/02/22 16:50:25 skrll Exp $	*/
      2       1.1    dyoung /*-
      3       1.1    dyoung  * Copyright (c) 2001 Atsushi Onoe
      4  1.48.4.1     skrll  * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
      5       1.1    dyoung  * All rights reserved.
      6       1.1    dyoung  *
      7       1.1    dyoung  * Redistribution and use in source and binary forms, with or without
      8       1.1    dyoung  * modification, are permitted provided that the following conditions
      9       1.1    dyoung  * are met:
     10       1.1    dyoung  * 1. Redistributions of source code must retain the above copyright
     11       1.1    dyoung  *    notice, this list of conditions and the following disclaimer.
     12       1.1    dyoung  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1    dyoung  *    notice, this list of conditions and the following disclaimer in the
     14       1.1    dyoung  *    documentation and/or other materials provided with the distribution.
     15       1.1    dyoung  *
     16       1.1    dyoung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17       1.1    dyoung  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18       1.1    dyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19       1.1    dyoung  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20       1.1    dyoung  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21       1.1    dyoung  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22       1.1    dyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23       1.1    dyoung  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24       1.1    dyoung  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25       1.1    dyoung  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26       1.1    dyoung  */
     27       1.1    dyoung 
     28       1.1    dyoung #include <sys/cdefs.h>
     29       1.3    dyoung #ifdef __FreeBSD__
     30  1.48.4.1     skrll __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.58 2007/11/02 05:22:24 sam Exp $");
     31      1.19    dyoung #endif
     32      1.19    dyoung #ifdef __NetBSD__
     33      1.48    dyoung __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.48.4.1 2008/02/22 16:50:25 skrll Exp $");
     34       1.3    dyoung #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.10    dyoung #include "opt_inet.h"
     41      1.46  christos #include "opt_compat_netbsd.h"
     42      1.10    dyoung 
     43       1.1    dyoung #include <sys/endian.h>
     44       1.1    dyoung #include <sys/param.h>
     45       1.1    dyoung #include <sys/kernel.h>
     46       1.1    dyoung #include <sys/socket.h>
     47       1.1    dyoung #include <sys/sockio.h>
     48       1.1    dyoung #include <sys/systm.h>
     49       1.4    dyoung #include <sys/proc.h>
     50      1.32      elad #include <sys/kauth.h>
     51      1.19    dyoung 
     52       1.1    dyoung #include <net/if.h>
     53  1.48.4.1     skrll #include <net/if_dl.h>
     54       1.1    dyoung #include <net/if_media.h>
     55       1.4    dyoung #include <net/if_ether.h>
     56       1.1    dyoung 
     57      1.10    dyoung #ifdef INET
     58      1.10    dyoung #include <netinet/in.h>
     59      1.10    dyoung #include <netinet/if_inarp.h>
     60      1.10    dyoung #endif
     61      1.10    dyoung 
     62       1.1    dyoung #include <net80211/ieee80211_var.h>
     63       1.1    dyoung #include <net80211/ieee80211_ioctl.h>
     64       1.1    dyoung 
     65       1.4    dyoung #include <dev/ic/wi_ieee.h>
     66      1.19    dyoung 
     67      1.46  christos #if defined(COMPAT_09) || defined(COMPAT_10) || defined(COMPAT_11) || \
     68      1.46  christos     defined(COMPAT_12) || defined(COMPAT_13) || defined(COMPAT_14) || \
     69      1.46  christos     defined(COMPAT_15) || defined(COMPAT_16) || defined(COMPAT_20) || \
     70      1.46  christos     defined(COMPAT_30) || defined(COMPAT_40)
     71      1.46  christos #include <compat/sys/sockio.h>
     72      1.46  christos #endif
     73      1.46  christos 
     74      1.26     skrll #ifdef __FreeBSD__
     75      1.26     skrll #define	IS_UP(_ic) \
     76      1.26     skrll 	(((_ic)->ic_ifp->if_flags & IFF_UP) &&			\
     77      1.26     skrll 	    ((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING))
     78      1.26     skrll #endif
     79      1.26     skrll #ifdef __NetBSD__
     80      1.19    dyoung #define	IS_UP(_ic) \
     81      1.26     skrll 	(((_ic)->ic_ifp->if_flags & IFF_UP) &&			\
     82      1.26     skrll 	    ((_ic)->ic_ifp->if_flags & IFF_RUNNING))
     83      1.26     skrll #endif
     84      1.19    dyoung #define	IS_UP_AUTO(_ic) \
     85      1.19    dyoung 	(IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
     86  1.48.4.1     skrll #define	RESCAN	1
     87       1.1    dyoung 
     88       1.1    dyoung /*
     89       1.1    dyoung  * XXX
     90       1.1    dyoung  * Wireless LAN specific configuration interface, which is compatible
     91       1.1    dyoung  * with wicontrol(8).
     92       1.1    dyoung  */
     93       1.1    dyoung 
     94      1.19    dyoung struct wi_read_ap_args {
     95      1.19    dyoung 	int	i;		/* result count */
     96      1.19    dyoung 	struct wi_apinfo *ap;	/* current entry in result buffer */
     97      1.45  christos 	void *	max;		/* result buffer bound */
     98      1.19    dyoung };
     99      1.19    dyoung 
    100      1.19    dyoung static void
    101      1.19    dyoung wi_read_ap_result(void *arg, struct ieee80211_node *ni)
    102      1.19    dyoung {
    103      1.19    dyoung 	struct ieee80211com *ic = ni->ni_ic;
    104      1.19    dyoung 	struct wi_read_ap_args *sa = arg;
    105      1.19    dyoung 	struct wi_apinfo *ap = sa->ap;
    106      1.19    dyoung 	struct ieee80211_rateset *rs;
    107      1.19    dyoung 	int j;
    108      1.19    dyoung 
    109      1.45  christos 	if ((void *)(ap + 1) > sa->max)
    110      1.19    dyoung 		return;
    111      1.19    dyoung 	memset(ap, 0, sizeof(struct wi_apinfo));
    112      1.19    dyoung 	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
    113      1.19    dyoung 		IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
    114  1.48.4.1     skrll 		ap->namelen = ic->ic_des_ssid[0].len;
    115  1.48.4.1     skrll 		if (ic->ic_des_ssid[0].len)
    116  1.48.4.1     skrll 			memcpy(ap->name, ic->ic_des_ssid[0].ssid,
    117  1.48.4.1     skrll 			    ic->ic_des_ssid[0].len);
    118      1.19    dyoung 	} else {
    119      1.19    dyoung 		IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
    120      1.19    dyoung 		ap->namelen = ni->ni_esslen;
    121      1.19    dyoung 		if (ni->ni_esslen)
    122      1.19    dyoung 			memcpy(ap->name, ni->ni_essid,
    123      1.19    dyoung 			    ni->ni_esslen);
    124      1.19    dyoung 	}
    125      1.19    dyoung 	ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
    126      1.19    dyoung 	ap->signal = ic->ic_node_getrssi(ni);
    127      1.19    dyoung 	ap->capinfo = ni->ni_capinfo;
    128      1.19    dyoung 	ap->interval = ni->ni_intval;
    129      1.19    dyoung 	rs = &ni->ni_rates;
    130      1.19    dyoung 	for (j = 0; j < rs->rs_nrates; j++) {
    131      1.19    dyoung 		if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
    132      1.19    dyoung 			ap->rate = (rs->rs_rates[j] &
    133      1.19    dyoung 			    IEEE80211_RATE_VAL) * 5; /* XXX */
    134      1.19    dyoung 		}
    135      1.19    dyoung 	}
    136      1.19    dyoung 	sa->i++;
    137      1.19    dyoung 	sa->ap++;
    138      1.19    dyoung }
    139      1.19    dyoung 
    140      1.19    dyoung struct wi_read_prism2_args {
    141      1.19    dyoung 	int	i;		/* result count */
    142      1.19    dyoung 	struct wi_scan_res *res;/* current entry in result buffer */
    143      1.45  christos 	void *	max;		/* result buffer bound */
    144      1.19    dyoung };
    145      1.19    dyoung 
    146      1.19    dyoung #if 0
    147      1.19    dyoung static void
    148      1.19    dyoung wi_read_prism2_result(void *arg, struct ieee80211_node *ni)
    149      1.19    dyoung {
    150      1.19    dyoung 	struct ieee80211com *ic = ni->ni_ic;
    151      1.19    dyoung 	struct wi_read_prism2_args *sa = arg;
    152      1.19    dyoung 	struct wi_scan_res *res = sa->res;
    153      1.19    dyoung 
    154      1.45  christos 	if ((void *)(res + 1) > sa->max)
    155      1.19    dyoung 		return;
    156      1.19    dyoung 	res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
    157      1.19    dyoung 	res->wi_noise = 0;
    158      1.19    dyoung 	res->wi_signal = ic->ic_node_getrssi(ni);
    159      1.19    dyoung 	IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
    160      1.19    dyoung 	res->wi_interval = ni->ni_intval;
    161      1.19    dyoung 	res->wi_capinfo = ni->ni_capinfo;
    162      1.19    dyoung 	res->wi_ssid_len = ni->ni_esslen;
    163      1.19    dyoung 	memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
    164      1.19    dyoung 	/* NB: assumes wi_srates holds <= ni->ni_rates */
    165      1.19    dyoung 	memcpy(res->wi_srates, ni->ni_rates.rs_rates,
    166      1.19    dyoung 		sizeof(res->wi_srates));
    167      1.19    dyoung 	if (ni->ni_rates.rs_nrates < 10)
    168      1.19    dyoung 		res->wi_srates[ni->ni_rates.rs_nrates] = 0;
    169      1.19    dyoung 	res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
    170      1.19    dyoung 	res->wi_rsvd = 0;
    171      1.19    dyoung 
    172      1.19    dyoung 	sa->i++;
    173      1.19    dyoung 	sa->res++;
    174      1.19    dyoung }
    175      1.19    dyoung 
    176      1.19    dyoung struct wi_read_sigcache_args {
    177      1.19    dyoung 	int	i;		/* result count */
    178      1.19    dyoung 	struct wi_sigcache *wsc;/* current entry in result buffer */
    179      1.45  christos 	void *	max;		/* result buffer bound */
    180      1.19    dyoung };
    181      1.19    dyoung 
    182      1.19    dyoung static void
    183      1.19    dyoung wi_read_sigcache(void *arg, struct ieee80211_node *ni)
    184      1.19    dyoung {
    185      1.19    dyoung 	struct ieee80211com *ic = ni->ni_ic;
    186      1.19    dyoung 	struct wi_read_sigcache_args *sa = arg;
    187      1.19    dyoung 	struct wi_sigcache *wsc = sa->wsc;
    188      1.19    dyoung 
    189      1.45  christos 	if ((void *)(wsc + 1) > sa->max)
    190      1.19    dyoung 		return;
    191      1.19    dyoung 	memset(wsc, 0, sizeof(struct wi_sigcache));
    192      1.19    dyoung 	IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr);
    193      1.19    dyoung 	wsc->signal = ic->ic_node_getrssi(ni);
    194      1.19    dyoung 
    195      1.19    dyoung 	sa->wsc++;
    196      1.19    dyoung 	sa->i++;
    197      1.19    dyoung }
    198      1.19    dyoung #endif
    199      1.19    dyoung 
    200       1.1    dyoung int
    201      1.45  christos ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, void *data)
    202       1.1    dyoung {
    203      1.19    dyoung 	struct ifnet *ifp = ic->ic_ifp;
    204       1.1    dyoung 	int i, j, error;
    205       1.1    dyoung 	struct ifreq *ifr = (struct ifreq *)data;
    206      1.34  christos 	struct wi_req *wreq;
    207       1.1    dyoung 	struct wi_ltv_keys *keys;
    208       1.1    dyoung 
    209      1.34  christos 	wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK);
    210      1.34  christos 	error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
    211       1.1    dyoung 	if (error)
    212      1.34  christos 		goto out;
    213      1.34  christos 	wreq->wi_len = 0;
    214      1.34  christos 	switch (wreq->wi_type) {
    215       1.1    dyoung 	case WI_RID_SERIALNO:
    216       1.8      onoe 	case WI_RID_STA_IDENTITY:
    217       1.1    dyoung 		/* nothing appropriate */
    218       1.1    dyoung 		break;
    219       1.1    dyoung 	case WI_RID_NODENAME:
    220      1.34  christos 		strlcpy((char *)&wreq->wi_val[1], hostname,
    221      1.34  christos 		    sizeof(wreq->wi_val) - sizeof(wreq->wi_val[0]));
    222      1.34  christos 		wreq->wi_val[0] = htole16(strlen(hostname));
    223      1.34  christos 		wreq->wi_len = (1 + strlen(hostname) + 1) / 2;
    224       1.1    dyoung 		break;
    225       1.1    dyoung 	case WI_RID_CURRENT_SSID:
    226       1.1    dyoung 		if (ic->ic_state != IEEE80211_S_RUN) {
    227      1.34  christos 			wreq->wi_val[0] = 0;
    228      1.34  christos 			wreq->wi_len = 1;
    229       1.1    dyoung 			break;
    230       1.1    dyoung 		}
    231      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_bss->ni_esslen);
    232      1.34  christos 		memcpy(&wreq->wi_val[1], ic->ic_bss->ni_essid,
    233       1.1    dyoung 		    ic->ic_bss->ni_esslen);
    234      1.34  christos 		wreq->wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
    235       1.1    dyoung 		break;
    236       1.1    dyoung 	case WI_RID_OWN_SSID:
    237       1.1    dyoung 	case WI_RID_DESIRED_SSID:
    238  1.48.4.1     skrll 		wreq->wi_val[0] = htole16(ic->ic_des_ssid[0].len);
    239  1.48.4.1     skrll 		memcpy(&wreq->wi_val[1], ic->ic_des_ssid[0].ssid, ic->ic_des_ssid[0].len);
    240  1.48.4.1     skrll 		wreq->wi_len = (1 + ic->ic_des_ssid[0].len + 1) / 2;
    241       1.1    dyoung 		break;
    242       1.1    dyoung 	case WI_RID_CURRENT_BSSID:
    243       1.1    dyoung 		if (ic->ic_state == IEEE80211_S_RUN)
    244      1.34  christos 			IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_bss->ni_bssid);
    245       1.1    dyoung 		else
    246      1.34  christos 			memset(wreq->wi_val, 0, IEEE80211_ADDR_LEN);
    247      1.34  christos 		wreq->wi_len = IEEE80211_ADDR_LEN / 2;
    248       1.1    dyoung 		break;
    249       1.1    dyoung 	case WI_RID_CHANNEL_LIST:
    250      1.34  christos 		memset(wreq->wi_val, 0, sizeof(wreq->wi_val));
    251       1.1    dyoung 		/*
    252       1.1    dyoung 		 * Since channel 0 is not available for DS, channel 1
    253       1.1    dyoung 		 * is assigned to LSB on WaveLAN.
    254       1.1    dyoung 		 */
    255       1.1    dyoung 		if (ic->ic_phytype == IEEE80211_T_DS)
    256       1.1    dyoung 			i = 1;
    257       1.1    dyoung 		else
    258       1.1    dyoung 			i = 0;
    259       1.1    dyoung 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
    260       1.1    dyoung 			if (isset(ic->ic_chan_active, i)) {
    261      1.34  christos 				setbit((u_int8_t *)wreq->wi_val, j);
    262      1.34  christos 				wreq->wi_len = j / 16 + 1;
    263       1.1    dyoung 			}
    264       1.1    dyoung 		break;
    265       1.1    dyoung 	case WI_RID_OWN_CHNL:
    266      1.34  christos 		wreq->wi_val[0] = htole16(
    267  1.48.4.1     skrll 			ieee80211_chan2ieee(ic, ic->ic_bsschan));
    268      1.34  christos 		wreq->wi_len = 1;
    269       1.1    dyoung 		break;
    270       1.1    dyoung 	case WI_RID_CURRENT_CHAN:
    271      1.34  christos 		wreq->wi_val[0] = htole16(
    272      1.26     skrll 			ieee80211_chan2ieee(ic, ic->ic_curchan));
    273      1.34  christos 		wreq->wi_len = 1;
    274       1.1    dyoung 		break;
    275       1.1    dyoung 	case WI_RID_COMMS_QUALITY:
    276      1.34  christos 		wreq->wi_val[0] = 0;				/* quality */
    277      1.34  christos 		wreq->wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss));
    278      1.34  christos 		wreq->wi_val[2] = 0;				/* noise */
    279      1.34  christos 		wreq->wi_len = 3;
    280       1.1    dyoung 		break;
    281       1.1    dyoung 	case WI_RID_PROMISC:
    282      1.34  christos 		wreq->wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
    283      1.34  christos 		wreq->wi_len = 1;
    284       1.1    dyoung 		break;
    285       1.1    dyoung 	case WI_RID_PORTTYPE:
    286      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_opmode);
    287      1.34  christos 		wreq->wi_len = 1;
    288       1.1    dyoung 		break;
    289       1.1    dyoung 	case WI_RID_MAC_NODE:
    290      1.34  christos 		IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_myaddr);
    291      1.34  christos 		wreq->wi_len = IEEE80211_ADDR_LEN / 2;
    292       1.1    dyoung 		break;
    293       1.1    dyoung 	case WI_RID_TX_RATE:
    294      1.26     skrll 		if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
    295      1.34  christos 			wreq->wi_val[0] = 0;	/* auto */
    296       1.1    dyoung 		else
    297      1.34  christos 			wreq->wi_val[0] = htole16(
    298       1.1    dyoung 			    (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
    299       1.1    dyoung 			    IEEE80211_RATE_VAL) / 2);
    300      1.34  christos 		wreq->wi_len = 1;
    301       1.1    dyoung 		break;
    302       1.1    dyoung 	case WI_RID_CUR_TX_RATE:
    303      1.34  christos 		wreq->wi_val[0] = htole16(
    304       1.1    dyoung 		    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
    305       1.1    dyoung 		    IEEE80211_RATE_VAL) / 2);
    306      1.34  christos 		wreq->wi_len = 1;
    307       1.1    dyoung 		break;
    308       1.6    dyoung 	case WI_RID_FRAG_THRESH:
    309      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_fragthreshold);
    310      1.34  christos 		wreq->wi_len = 1;
    311       1.6    dyoung 		break;
    312       1.1    dyoung 	case WI_RID_RTS_THRESH:
    313      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_rtsthreshold);
    314      1.34  christos 		wreq->wi_len = 1;
    315       1.1    dyoung 		break;
    316       1.1    dyoung 	case WI_RID_CREATE_IBSS:
    317      1.34  christos 		wreq->wi_val[0] =
    318       1.1    dyoung 		    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
    319      1.34  christos 		wreq->wi_len = 1;
    320       1.1    dyoung 		break;
    321       1.1    dyoung 	case WI_RID_MICROWAVE_OVEN:
    322      1.34  christos 		wreq->wi_val[0] = 0;	/* no ... not supported */
    323      1.34  christos 		wreq->wi_len = 1;
    324       1.1    dyoung 		break;
    325       1.1    dyoung 	case WI_RID_ROAMING_MODE:
    326      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_roaming);	/* XXX map */
    327      1.34  christos 		wreq->wi_len = 1;
    328       1.1    dyoung 		break;
    329       1.1    dyoung 	case WI_RID_SYSTEM_SCALE:
    330      1.34  christos 		wreq->wi_val[0] = htole16(1);	/* low density ... not supp */
    331      1.34  christos 		wreq->wi_len = 1;
    332       1.1    dyoung 		break;
    333       1.1    dyoung 	case WI_RID_PM_ENABLED:
    334      1.34  christos 		wreq->wi_val[0] =
    335       1.1    dyoung 		    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
    336      1.34  christos 		wreq->wi_len = 1;
    337       1.1    dyoung 		break;
    338       1.1    dyoung 	case WI_RID_MAX_SLEEP:
    339      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_lintval);
    340      1.34  christos 		wreq->wi_len = 1;
    341       1.1    dyoung 		break;
    342       1.1    dyoung 	case WI_RID_CUR_BEACON_INT:
    343      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_bss->ni_intval);
    344      1.34  christos 		wreq->wi_len = 1;
    345       1.1    dyoung 		break;
    346       1.1    dyoung 	case WI_RID_WEP_AVAIL:
    347      1.34  christos 		wreq->wi_val[0] = htole16(1);	/* always available */
    348      1.34  christos 		wreq->wi_len = 1;
    349       1.1    dyoung 		break;
    350       1.1    dyoung 	case WI_RID_CNFAUTHMODE:
    351      1.34  christos 		wreq->wi_val[0] = htole16(1);	/* TODO: open system only */
    352      1.34  christos 		wreq->wi_len = 1;
    353       1.1    dyoung 		break;
    354       1.1    dyoung 	case WI_RID_ENCRYPTION:
    355      1.34  christos 		wreq->wi_val[0] =
    356      1.16   mycroft 		    htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
    357      1.34  christos 		wreq->wi_len = 1;
    358       1.1    dyoung 		break;
    359       1.1    dyoung 	case WI_RID_TX_CRYPT_KEY:
    360      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_def_txkey);
    361      1.34  christos 		wreq->wi_len = 1;
    362       1.1    dyoung 		break;
    363       1.1    dyoung 	case WI_RID_DEFLT_CRYPT_KEYS:
    364      1.37  drochner 		keys = (struct wi_ltv_keys *)wreq;
    365       1.1    dyoung 		/* do not show keys to non-root user */
    366      1.41      elad 		error = kauth_authorize_network(curlwp->l_cred,
    367      1.41      elad 		    KAUTH_NETWORK_INTERFACE,
    368      1.41      elad 		    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp,
    369      1.41      elad 		    NULL, NULL);
    370       1.1    dyoung 		if (error) {
    371       1.1    dyoung 			memset(keys, 0, sizeof(*keys));
    372       1.1    dyoung 			error = 0;
    373       1.1    dyoung 			break;
    374       1.1    dyoung 		}
    375       1.1    dyoung 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    376       1.1    dyoung 			keys->wi_keys[i].wi_keylen =
    377      1.19    dyoung 			    htole16(ic->ic_nw_keys[i].wk_keylen);
    378       1.1    dyoung 			memcpy(keys->wi_keys[i].wi_keydat,
    379      1.19    dyoung 			    ic->ic_nw_keys[i].wk_key,
    380      1.19    dyoung 			    ic->ic_nw_keys[i].wk_keylen);
    381       1.1    dyoung 		}
    382      1.34  christos 		wreq->wi_len = sizeof(*keys) / 2;
    383       1.1    dyoung 		break;
    384       1.1    dyoung 	case WI_RID_MAX_DATALEN:
    385      1.34  christos 		wreq->wi_val[0] = htole16(ic->ic_fragthreshold);
    386      1.34  christos 		wreq->wi_len = 1;
    387       1.1    dyoung 		break;
    388       1.8      onoe 	case WI_RID_DBM_ADJUST:
    389       1.8      onoe 		/* not supported, we just pass rssi value from driver. */
    390       1.8      onoe 		break;
    391       1.1    dyoung 	case WI_RID_IFACE_STATS:
    392       1.1    dyoung 		/* XXX: should be implemented in lower drivers */
    393       1.1    dyoung 		break;
    394       1.1    dyoung 	case WI_RID_READ_APS:
    395      1.19    dyoung 		/*
    396      1.19    dyoung 		 * Don't return results until active scan completes.
    397      1.19    dyoung 		 */
    398      1.19    dyoung 		if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
    399      1.19    dyoung 			struct wi_read_ap_args args;
    400      1.19    dyoung 
    401      1.19    dyoung 			args.i = 0;
    402      1.34  christos 			args.ap = (void *)((char *)wreq->wi_val + sizeof(i));
    403      1.37  drochner 			args.max = (void *)(wreq + 1);
    404  1.48.4.1     skrll 			ieee80211_iterate_nodes(&ic->ic_sta,
    405      1.19    dyoung 				wi_read_ap_result, &args);
    406      1.34  christos 			memcpy(wreq->wi_val, &args.i, sizeof(args.i));
    407      1.34  christos 			wreq->wi_len = (sizeof(int) +
    408      1.19    dyoung 				sizeof(struct wi_apinfo) * args.i) / 2;
    409      1.19    dyoung 		} else
    410      1.19    dyoung 			error = EINPROGRESS;
    411       1.1    dyoung 		break;
    412       1.4    dyoung #if 0
    413       1.1    dyoung 	case WI_RID_SCAN_RES:			/* compatibility interface */
    414      1.19    dyoung 		if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
    415      1.19    dyoung 			struct wi_read_prism2_args args;
    416      1.19    dyoung 			struct wi_scan_p2_hdr *p2;
    417      1.19    dyoung 
    418      1.19    dyoung 			/* NB: use Prism2 format so we can include rate info */
    419      1.34  christos 			p2 = (struct wi_scan_p2_hdr *)wreq->wi_val;
    420      1.19    dyoung 			args.i = 0;
    421      1.19    dyoung 			args.res = (void *)&p2[1];
    422      1.37  drochner 			args.max = (void *)(wreq + 1);
    423      1.19    dyoung 			ieee80211_iterate_nodes(&ic->ic_scan,
    424      1.19    dyoung 				wi_read_prism2_result, &args);
    425      1.19    dyoung 			p2->wi_rsvd = 0;
    426      1.19    dyoung 			p2->wi_reason = args.i;
    427      1.34  christos 			wreq->wi_len = (sizeof(*p2) +
    428      1.19    dyoung 				sizeof(struct wi_scan_res) * args.i) / 2;
    429      1.19    dyoung 		} else
    430       1.1    dyoung 			error = EINPROGRESS;
    431       1.1    dyoung 		break;
    432      1.19    dyoung 	case WI_RID_READ_CACHE: {
    433      1.19    dyoung 		struct wi_read_sigcache_args args;
    434      1.19    dyoung 		args.i = 0;
    435      1.34  christos 		args.wsc = (struct wi_sigcache *) wreq->wi_val;
    436      1.37  drochner 		args.max = (void *)(wreq + 1);
    437      1.19    dyoung 		ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args);
    438      1.34  christos 		wreq->wi_len = sizeof(struct wi_sigcache) * args.i / 2;
    439       1.1    dyoung 		break;
    440      1.19    dyoung 	}
    441      1.19    dyoung #endif
    442       1.1    dyoung 	default:
    443       1.1    dyoung 		error = EINVAL;
    444       1.1    dyoung 		break;
    445       1.1    dyoung 	}
    446       1.1    dyoung 	if (error == 0) {
    447      1.34  christos 		wreq->wi_len++;
    448      1.36  christos 		error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
    449       1.1    dyoung 	}
    450      1.34  christos out:
    451      1.34  christos 	free(wreq, M_TEMP);
    452       1.1    dyoung 	return error;
    453       1.1    dyoung }
    454       1.1    dyoung 
    455       1.1    dyoung static int
    456       1.1    dyoung findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    457       1.1    dyoung {
    458       1.1    dyoung #define	IEEERATE(_ic,_m,_i) \
    459       1.1    dyoung 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
    460       1.1    dyoung 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
    461       1.1    dyoung 	for (i = 0; i < nrates; i++)
    462       1.1    dyoung 		if (IEEERATE(ic, mode, i) == rate)
    463       1.1    dyoung 			return i;
    464       1.1    dyoung 	return -1;
    465       1.1    dyoung #undef IEEERATE
    466       1.1    dyoung }
    467       1.1    dyoung 
    468       1.7    dyoung /*
    469       1.7    dyoung  * Prepare to do a user-initiated scan for AP's.  If no
    470       1.7    dyoung  * current/default channel is setup or the current channel
    471       1.7    dyoung  * is invalid then pick the first available channel from
    472       1.7    dyoung  * the active list as the place to start the scan.
    473       1.7    dyoung  */
    474       1.7    dyoung static int
    475      1.19    dyoung ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
    476       1.7    dyoung {
    477       1.7    dyoung 
    478      1.19    dyoung 	/*
    479      1.19    dyoung 	 * XXX don't permit a scan to be started unless we
    480      1.19    dyoung 	 * know the device is ready.  For the moment this means
    481      1.19    dyoung 	 * the device is marked up as this is the required to
    482      1.19    dyoung 	 * initialize the hardware.  It would be better to permit
    483      1.19    dyoung 	 * scanning prior to being up but that'll require some
    484      1.19    dyoung 	 * changes to the infrastructure.
    485      1.19    dyoung 	 */
    486      1.19    dyoung 	if (!IS_UP(ic))
    487      1.19    dyoung 		return EINVAL;
    488      1.19    dyoung 	memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
    489       1.7    dyoung 	/*
    490      1.19    dyoung 	 * We force the state to INIT before calling ieee80211_new_state
    491      1.19    dyoung 	 * to get ieee80211_begin_scan called.  We really want to scan w/o
    492      1.19    dyoung 	 * altering the current state but that's not possible right now.
    493       1.7    dyoung 	 */
    494      1.19    dyoung 	/* XXX handle proberequest case */
    495      1.19    dyoung 	ic->ic_state = IEEE80211_S_INIT;	/* XXX bypass state machine */
    496      1.19    dyoung 	return 0;
    497       1.7    dyoung }
    498       1.7    dyoung 
    499       1.1    dyoung int
    500      1.45  christos ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, void *data)
    501       1.1    dyoung {
    502      1.19    dyoung 	struct ifnet *ifp = ic->ic_ifp;
    503       1.1    dyoung 	int i, j, len, error, rate;
    504       1.1    dyoung 	struct ifreq *ifr = (struct ifreq *)data;
    505       1.1    dyoung 	struct wi_ltv_keys *keys;
    506      1.34  christos 	struct wi_req *wreq;
    507      1.33  christos 	u_int8_t chanlist[IEEE80211_CHAN_BYTES];
    508       1.1    dyoung 
    509      1.34  christos 	wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK);
    510      1.34  christos 	error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
    511       1.1    dyoung 	if (error)
    512      1.34  christos 		goto out;
    513      1.34  christos 	len = wreq->wi_len ? (wreq->wi_len - 1) * 2 : 0;
    514      1.34  christos 	switch (wreq->wi_type) {
    515       1.1    dyoung 	case WI_RID_SERIALNO:
    516       1.1    dyoung 	case WI_RID_NODENAME:
    517       1.1    dyoung 	case WI_RID_CURRENT_SSID:
    518      1.34  christos 		error = EPERM;
    519      1.34  christos 		goto out;
    520       1.1    dyoung 	case WI_RID_OWN_SSID:
    521       1.1    dyoung 	case WI_RID_DESIRED_SSID:
    522      1.34  christos 		if (le16toh(wreq->wi_val[0]) * 2 > len ||
    523      1.34  christos 		    le16toh(wreq->wi_val[0]) > IEEE80211_NWID_LEN) {
    524       1.1    dyoung 			error = ENOSPC;
    525       1.1    dyoung 			break;
    526       1.1    dyoung 		}
    527  1.48.4.1     skrll 		memset(ic->ic_des_ssid[0].ssid, 0, sizeof(ic->ic_des_ssid[0].len));
    528  1.48.4.1     skrll 		ic->ic_des_ssid[0].len = le16toh(wreq->wi_val[0]) * 2;
    529  1.48.4.1     skrll 		memcpy(ic->ic_des_ssid[0].ssid, &wreq->wi_val[1], ic->ic_des_ssid[0].len);
    530       1.1    dyoung 		error = ENETRESET;
    531       1.1    dyoung 		break;
    532       1.1    dyoung 	case WI_RID_CURRENT_BSSID:
    533      1.34  christos 		error = EPERM;
    534      1.34  christos 		goto out;
    535       1.1    dyoung 	case WI_RID_OWN_CHNL:
    536       1.1    dyoung 		if (len != 2)
    537      1.34  christos 			goto invalid;
    538      1.34  christos 		i = le16toh(wreq->wi_val[0]);
    539       1.1    dyoung 		if (i < 0 ||
    540       1.1    dyoung 		    i > IEEE80211_CHAN_MAX ||
    541       1.1    dyoung 		    isclr(ic->ic_chan_active, i))
    542      1.34  christos 			goto invalid;
    543  1.48.4.1     skrll 		ic->ic_bsschan = &ic->ic_channels[i];
    544      1.19    dyoung 		if (ic->ic_opmode == IEEE80211_M_MONITOR)
    545      1.19    dyoung 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    546      1.19    dyoung 		else
    547       1.1    dyoung 			error = ENETRESET;
    548       1.1    dyoung 		break;
    549       1.1    dyoung 	case WI_RID_CURRENT_CHAN:
    550       1.1    dyoung 	case WI_RID_COMMS_QUALITY:
    551      1.34  christos 		error = EPERM;
    552      1.34  christos 		goto out;
    553       1.1    dyoung 	case WI_RID_PROMISC:
    554       1.1    dyoung 		if (len != 2)
    555      1.34  christos 			goto invalid;
    556       1.1    dyoung 		if (ifp->if_flags & IFF_PROMISC) {
    557      1.34  christos 			if (wreq->wi_val[0] == 0) {
    558       1.1    dyoung 				ifp->if_flags &= ~IFF_PROMISC;
    559       1.1    dyoung 				error = ENETRESET;
    560       1.1    dyoung 			}
    561       1.1    dyoung 		} else {
    562      1.34  christos 			if (wreq->wi_val[0] != 0) {
    563       1.1    dyoung 				ifp->if_flags |= IFF_PROMISC;
    564       1.1    dyoung 				error = ENETRESET;
    565       1.1    dyoung 			}
    566       1.1    dyoung 		}
    567       1.1    dyoung 		break;
    568       1.1    dyoung 	case WI_RID_PORTTYPE:
    569       1.1    dyoung 		if (len != 2)
    570      1.34  christos 			goto invalid;
    571      1.34  christos 		switch (le16toh(wreq->wi_val[0])) {
    572       1.1    dyoung 		case IEEE80211_M_STA:
    573       1.1    dyoung 			break;
    574       1.1    dyoung 		case IEEE80211_M_IBSS:
    575       1.1    dyoung 			if (!(ic->ic_caps & IEEE80211_C_IBSS))
    576      1.34  christos 				goto invalid;
    577       1.1    dyoung 			break;
    578       1.1    dyoung 		case IEEE80211_M_AHDEMO:
    579       1.1    dyoung 			if (ic->ic_phytype != IEEE80211_T_DS ||
    580       1.1    dyoung 			    !(ic->ic_caps & IEEE80211_C_AHDEMO))
    581      1.34  christos 				goto invalid;
    582       1.1    dyoung 			break;
    583       1.1    dyoung 		case IEEE80211_M_HOSTAP:
    584       1.1    dyoung 			if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
    585      1.34  christos 				goto invalid;
    586       1.1    dyoung 			break;
    587       1.1    dyoung 		default:
    588      1.34  christos 			goto invalid;
    589       1.1    dyoung 		}
    590      1.34  christos 		if (le16toh(wreq->wi_val[0]) != ic->ic_opmode) {
    591      1.34  christos 			ic->ic_opmode = le16toh(wreq->wi_val[0]);
    592      1.19    dyoung 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    593       1.1    dyoung 		}
    594       1.1    dyoung 		break;
    595       1.1    dyoung #if 0
    596       1.1    dyoung 	case WI_RID_MAC_NODE:
    597       1.1    dyoung 		if (len != IEEE80211_ADDR_LEN)
    598      1.34  christos 			goto invalid;
    599      1.34  christos 		IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq->wi_val);
    600       1.1    dyoung 		/* if_init will copy lladdr into ic_myaddr */
    601       1.1    dyoung 		error = ENETRESET;
    602       1.1    dyoung 		break;
    603       1.1    dyoung #endif
    604       1.1    dyoung 	case WI_RID_TX_RATE:
    605       1.1    dyoung 		if (len != 2)
    606      1.34  christos 			goto invalid;
    607      1.34  christos 		if (wreq->wi_val[0] == 0) {
    608       1.1    dyoung 			/* auto */
    609      1.26     skrll 			ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
    610       1.1    dyoung 			break;
    611       1.1    dyoung 		}
    612      1.34  christos 		rate = 2 * le16toh(wreq->wi_val[0]);
    613       1.1    dyoung 		if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
    614       1.1    dyoung 			/*
    615       1.1    dyoung 			 * In autoselect mode search for the rate.  We take
    616       1.1    dyoung 			 * the first instance which may not be right, but we
    617       1.1    dyoung 			 * are limited by the interface.  Note that we also
    618       1.1    dyoung 			 * lock the mode to insure the rate is meaningful
    619       1.1    dyoung 			 * when it is used.
    620       1.1    dyoung 			 */
    621       1.1    dyoung 			for (j = IEEE80211_MODE_11A;
    622       1.1    dyoung 			     j < IEEE80211_MODE_MAX; j++) {
    623  1.48.4.1     skrll 				if (isset(ic->ic_modecaps, j))
    624       1.1    dyoung 					continue;
    625       1.1    dyoung 				i = findrate(ic, j, rate);
    626       1.1    dyoung 				if (i != -1) {
    627       1.1    dyoung 					/* lock mode too */
    628       1.1    dyoung 					ic->ic_curmode = j;
    629       1.1    dyoung 					goto setrate;
    630       1.1    dyoung 				}
    631       1.1    dyoung 			}
    632       1.1    dyoung 		} else {
    633       1.1    dyoung 			i = findrate(ic, ic->ic_curmode, rate);
    634       1.1    dyoung 			if (i != -1)
    635       1.1    dyoung 				goto setrate;
    636       1.1    dyoung 		}
    637      1.34  christos 		goto invalid;
    638       1.1    dyoung 	setrate:
    639       1.1    dyoung 		ic->ic_fixed_rate = i;
    640      1.19    dyoung 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    641       1.1    dyoung 		break;
    642       1.1    dyoung 	case WI_RID_CUR_TX_RATE:
    643      1.34  christos 		error = EPERM;
    644      1.34  christos 		goto out;
    645       1.6    dyoung 	case WI_RID_FRAG_THRESH:
    646       1.6    dyoung 		if (len != 2)
    647      1.34  christos 			goto invalid;
    648      1.34  christos 		ic->ic_fragthreshold = le16toh(wreq->wi_val[0]);
    649       1.6    dyoung 		error = ENETRESET;
    650       1.6    dyoung 		break;
    651       1.1    dyoung 	case WI_RID_RTS_THRESH:
    652       1.1    dyoung 		if (len != 2)
    653      1.34  christos 			goto invalid;
    654      1.34  christos 		ic->ic_rtsthreshold = le16toh(wreq->wi_val[0]);
    655       1.6    dyoung 		error = ENETRESET;
    656       1.1    dyoung 		break;
    657       1.1    dyoung 	case WI_RID_CREATE_IBSS:
    658       1.1    dyoung 		if (len != 2)
    659      1.34  christos 			goto invalid;
    660      1.34  christos 		if (wreq->wi_val[0] != 0) {
    661       1.1    dyoung 			if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
    662      1.34  christos 				goto invalid;
    663       1.1    dyoung 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
    664       1.1    dyoung 				ic->ic_flags |= IEEE80211_F_IBSSON;
    665       1.1    dyoung 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
    666       1.1    dyoung 				    ic->ic_state == IEEE80211_S_SCAN)
    667      1.19    dyoung 					error = IS_UP_AUTO(ic) ? ENETRESET : 0;
    668       1.1    dyoung 			}
    669       1.1    dyoung 		} else {
    670       1.1    dyoung 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
    671       1.1    dyoung 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
    672       1.1    dyoung 				if (ic->ic_flags & IEEE80211_F_SIBSS) {
    673       1.1    dyoung 					ic->ic_flags &= ~IEEE80211_F_SIBSS;
    674      1.19    dyoung 					error = IS_UP_AUTO(ic) ? ENETRESET : 0;
    675       1.1    dyoung 				}
    676       1.1    dyoung 			}
    677       1.1    dyoung 		}
    678       1.1    dyoung 		break;
    679       1.1    dyoung 	case WI_RID_MICROWAVE_OVEN:
    680       1.1    dyoung 		if (len != 2)
    681      1.34  christos 			goto invalid;
    682      1.34  christos 		if (wreq->wi_val[0] != 0)
    683      1.34  christos 			goto invalid;		/* not supported */
    684       1.1    dyoung 		break;
    685       1.1    dyoung 	case WI_RID_ROAMING_MODE:
    686       1.1    dyoung 		if (len != 2)
    687      1.34  christos 			goto invalid;
    688      1.34  christos 		i = le16toh(wreq->wi_val[0]);
    689      1.19    dyoung 		if (i > IEEE80211_ROAMING_MANUAL)
    690      1.34  christos 			goto invalid;		/* not supported */
    691      1.19    dyoung 		ic->ic_roaming = i;
    692       1.1    dyoung 		break;
    693       1.1    dyoung 	case WI_RID_SYSTEM_SCALE:
    694       1.1    dyoung 		if (len != 2)
    695      1.34  christos 			goto invalid;
    696      1.34  christos 		if (le16toh(wreq->wi_val[0]) != 1)
    697      1.34  christos 			goto invalid;		/* not supported */
    698       1.1    dyoung 		break;
    699       1.1    dyoung 	case WI_RID_PM_ENABLED:
    700       1.1    dyoung 		if (len != 2)
    701      1.34  christos 			goto invalid;
    702      1.34  christos 		if (wreq->wi_val[0] != 0) {
    703       1.1    dyoung 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    704      1.34  christos 				goto invalid;
    705       1.1    dyoung 			if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
    706       1.1    dyoung 				ic->ic_flags |= IEEE80211_F_PMGTON;
    707      1.19    dyoung 				error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    708       1.1    dyoung 			}
    709       1.1    dyoung 		} else {
    710       1.1    dyoung 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
    711       1.1    dyoung 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
    712      1.19    dyoung 				error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    713       1.1    dyoung 			}
    714       1.1    dyoung 		}
    715       1.1    dyoung 		break;
    716       1.1    dyoung 	case WI_RID_MAX_SLEEP:
    717       1.1    dyoung 		if (len != 2)
    718      1.34  christos 			goto invalid;
    719      1.34  christos 		ic->ic_lintval = le16toh(wreq->wi_val[0]);
    720       1.1    dyoung 		if (ic->ic_flags & IEEE80211_F_PMGTON)
    721      1.19    dyoung 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    722       1.1    dyoung 		break;
    723       1.1    dyoung 	case WI_RID_CUR_BEACON_INT:
    724       1.1    dyoung 	case WI_RID_WEP_AVAIL:
    725      1.34  christos 		error = EPERM;
    726      1.34  christos 		goto out;
    727       1.1    dyoung 	case WI_RID_CNFAUTHMODE:
    728       1.1    dyoung 		if (len != 2)
    729      1.34  christos 			goto invalid;
    730      1.34  christos 		i = le16toh(wreq->wi_val[0]);
    731      1.19    dyoung 		if (i > IEEE80211_AUTH_WPA)
    732      1.34  christos 			goto invalid;
    733      1.19    dyoung 		ic->ic_bss->ni_authmode = i;		/* XXX ENETRESET? */
    734      1.19    dyoung 		error = ENETRESET;
    735       1.1    dyoung 		break;
    736       1.1    dyoung 	case WI_RID_ENCRYPTION:
    737       1.1    dyoung 		if (len != 2)
    738      1.34  christos 			goto invalid;
    739      1.34  christos 		if (wreq->wi_val[0] != 0) {
    740       1.1    dyoung 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    741      1.34  christos 				goto invalid;
    742      1.16   mycroft 			if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
    743      1.16   mycroft 				ic->ic_flags |= IEEE80211_F_PRIVACY;
    744       1.1    dyoung 				error = ENETRESET;
    745       1.1    dyoung 			}
    746       1.1    dyoung 		} else {
    747      1.16   mycroft 			if (ic->ic_flags & IEEE80211_F_PRIVACY) {
    748      1.16   mycroft 				ic->ic_flags &= ~IEEE80211_F_PRIVACY;
    749       1.1    dyoung 				error = ENETRESET;
    750       1.1    dyoung 			}
    751       1.1    dyoung 		}
    752       1.1    dyoung 		break;
    753       1.1    dyoung 	case WI_RID_TX_CRYPT_KEY:
    754       1.1    dyoung 		if (len != 2)
    755      1.34  christos 			goto invalid;
    756      1.34  christos 		i = le16toh(wreq->wi_val[0]);
    757       1.1    dyoung 		if (i >= IEEE80211_WEP_NKID)
    758      1.34  christos 			goto invalid;
    759      1.19    dyoung 		ic->ic_def_txkey = i;
    760      1.19    dyoung 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    761       1.1    dyoung 		break;
    762       1.1    dyoung 	case WI_RID_DEFLT_CRYPT_KEYS:
    763       1.1    dyoung 		if (len != sizeof(struct wi_ltv_keys))
    764      1.34  christos 			goto invalid;
    765      1.37  drochner 		keys = (struct wi_ltv_keys *)wreq;
    766       1.1    dyoung 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    767       1.1    dyoung 			len = le16toh(keys->wi_keys[i].wi_keylen);
    768       1.1    dyoung 			if (len != 0 && len < IEEE80211_WEP_KEYLEN)
    769      1.34  christos 				goto invalid;
    770      1.19    dyoung 			if (len > IEEE80211_KEYBUF_SIZE)
    771      1.34  christos 				goto invalid;
    772       1.1    dyoung 		}
    773       1.1    dyoung 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    774      1.19    dyoung 			struct ieee80211_key *k = &ic->ic_nw_keys[i];
    775      1.19    dyoung 
    776       1.1    dyoung 			len = le16toh(keys->wi_keys[i].wi_keylen);
    777      1.19    dyoung 			k->wk_keylen = len;
    778      1.19    dyoung 			k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
    779      1.19    dyoung 			memset(k->wk_key, 0, sizeof(k->wk_key));
    780      1.19    dyoung 			memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len);
    781      1.19    dyoung #if 0
    782      1.19    dyoung 			k->wk_type = IEEE80211_CIPHER_WEP;
    783      1.19    dyoung #endif
    784       1.1    dyoung 		}
    785       1.1    dyoung 		error = ENETRESET;
    786       1.1    dyoung 		break;
    787       1.1    dyoung 	case WI_RID_MAX_DATALEN:
    788       1.1    dyoung 		if (len != 2)
    789      1.34  christos 			goto invalid;
    790      1.34  christos 		len = le16toh(wreq->wi_val[0]);
    791       1.1    dyoung 		if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
    792      1.34  christos 			goto invalid;
    793       1.1    dyoung 		ic->ic_fragthreshold = len;
    794      1.19    dyoung 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
    795       1.1    dyoung 		break;
    796       1.1    dyoung 	case WI_RID_IFACE_STATS:
    797       1.1    dyoung 		error = EPERM;
    798       1.1    dyoung 		break;
    799       1.1    dyoung 	case WI_RID_SCAN_REQ:			/* XXX wicontrol */
    800       1.1    dyoung 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    801       1.1    dyoung 			break;
    802      1.19    dyoung 		error = ieee80211_setupscan(ic, ic->ic_chan_avail);
    803       1.7    dyoung 		if (error == 0)
    804       1.7    dyoung 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    805       1.1    dyoung 		break;
    806       1.1    dyoung 	case WI_RID_SCAN_APS:
    807       1.1    dyoung 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    808       1.1    dyoung 			break;
    809       1.1    dyoung 		len--;			/* XXX: tx rate? */
    810       1.1    dyoung 		/* FALLTHRU */
    811       1.1    dyoung 	case WI_RID_CHANNEL_LIST:
    812       1.1    dyoung 		memset(chanlist, 0, sizeof(chanlist));
    813       1.1    dyoung 		/*
    814       1.1    dyoung 		 * Since channel 0 is not available for DS, channel 1
    815       1.1    dyoung 		 * is assigned to LSB on WaveLAN.
    816       1.1    dyoung 		 */
    817       1.1    dyoung 		if (ic->ic_phytype == IEEE80211_T_DS)
    818       1.1    dyoung 			i = 1;
    819       1.1    dyoung 		else
    820       1.1    dyoung 			i = 0;
    821       1.1    dyoung 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
    822       1.1    dyoung 			if ((j / 8) >= len)
    823       1.1    dyoung 				break;
    824      1.34  christos 			if (isclr((u_int8_t *)wreq->wi_val, j))
    825       1.1    dyoung 				continue;
    826       1.1    dyoung 			if (isclr(ic->ic_chan_active, i)) {
    827      1.34  christos 				if (wreq->wi_type != WI_RID_CHANNEL_LIST)
    828       1.1    dyoung 					continue;
    829      1.34  christos 				if (isclr(ic->ic_chan_avail, i)) {
    830      1.34  christos 					error = EPERM;
    831      1.34  christos 					goto out;
    832      1.34  christos 				}
    833       1.1    dyoung 			}
    834       1.1    dyoung 			setbit(chanlist, i);
    835       1.1    dyoung 		}
    836      1.19    dyoung 		error = ieee80211_setupscan(ic, chanlist);
    837      1.34  christos 		if (wreq->wi_type == WI_RID_CHANNEL_LIST) {
    838       1.7    dyoung 			/* NB: ignore error from ieee80211_setupscan */
    839       1.1    dyoung 			error = ENETRESET;
    840       1.7    dyoung 		} else if (error == 0)
    841       1.1    dyoung 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    842       1.1    dyoung 		break;
    843       1.1    dyoung 	default:
    844      1.34  christos 		goto invalid;
    845       1.1    dyoung 	}
    846      1.19    dyoung 	if (error == ENETRESET && !IS_UP_AUTO(ic))
    847      1.19    dyoung 		error = 0;
    848      1.34  christos out:
    849      1.34  christos 	free(wreq, M_TEMP);
    850      1.19    dyoung 	return error;
    851      1.34  christos invalid:
    852      1.34  christos 	free(wreq, M_TEMP);
    853      1.34  christos 	return EINVAL;
    854      1.19    dyoung }
    855      1.19    dyoung 
    856      1.19    dyoung static int
    857      1.19    dyoung cap2cipher(int flag)
    858      1.19    dyoung {
    859      1.19    dyoung 	switch (flag) {
    860      1.19    dyoung 	case IEEE80211_C_WEP:		return IEEE80211_CIPHER_WEP;
    861      1.19    dyoung 	case IEEE80211_C_AES:		return IEEE80211_CIPHER_AES_OCB;
    862      1.19    dyoung 	case IEEE80211_C_AES_CCM:	return IEEE80211_CIPHER_AES_CCM;
    863      1.19    dyoung 	case IEEE80211_C_CKIP:		return IEEE80211_CIPHER_CKIP;
    864      1.19    dyoung 	case IEEE80211_C_TKIP:		return IEEE80211_CIPHER_TKIP;
    865      1.19    dyoung 	}
    866      1.19    dyoung 	return -1;
    867      1.19    dyoung }
    868      1.19    dyoung 
    869      1.19    dyoung static int
    870      1.19    dyoung ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
    871      1.19    dyoung {
    872      1.19    dyoung 	struct ieee80211_node *ni;
    873      1.19    dyoung 	struct ieee80211req_key ik;
    874      1.19    dyoung 	struct ieee80211_key *wk;
    875      1.19    dyoung 	const struct ieee80211_cipher *cip;
    876      1.19    dyoung 	u_int kid;
    877      1.19    dyoung 	int error;
    878      1.19    dyoung 
    879      1.19    dyoung 	if (ireq->i_len != sizeof(ik))
    880      1.19    dyoung 		return EINVAL;
    881      1.19    dyoung 	error = copyin(ireq->i_data, &ik, sizeof(ik));
    882      1.19    dyoung 	if (error)
    883      1.19    dyoung 		return error;
    884      1.19    dyoung 	kid = ik.ik_keyix;
    885      1.19    dyoung 	if (kid == IEEE80211_KEYIX_NONE) {
    886      1.19    dyoung 		ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
    887      1.19    dyoung 		if (ni == NULL)
    888      1.19    dyoung 			return EINVAL;		/* XXX */
    889      1.19    dyoung 		wk = &ni->ni_ucastkey;
    890      1.19    dyoung 	} else {
    891      1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
    892      1.19    dyoung 			return EINVAL;
    893      1.19    dyoung 		wk = &ic->ic_nw_keys[kid];
    894      1.19    dyoung 		IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
    895      1.19    dyoung 		ni = NULL;
    896      1.19    dyoung 	}
    897      1.19    dyoung 	cip = wk->wk_cipher;
    898      1.19    dyoung 	ik.ik_type = cip->ic_cipher;
    899      1.19    dyoung 	ik.ik_keylen = wk->wk_keylen;
    900      1.19    dyoung 	ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
    901      1.19    dyoung 	if (wk->wk_keyix == ic->ic_def_txkey)
    902      1.19    dyoung 		ik.ik_flags |= IEEE80211_KEY_DEFAULT;
    903      1.41      elad 	if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
    904      1.41      elad 	    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ic->ic_ifp, NULL, NULL) == 0) {
    905      1.19    dyoung 		/* NB: only root can read key data */
    906      1.19    dyoung 		ik.ik_keyrsc = wk->wk_keyrsc;
    907      1.19    dyoung 		ik.ik_keytsc = wk->wk_keytsc;
    908      1.19    dyoung 		memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
    909      1.19    dyoung 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
    910      1.19    dyoung 			memcpy(ik.ik_keydata+wk->wk_keylen,
    911      1.19    dyoung 				wk->wk_key + IEEE80211_KEYBUF_SIZE,
    912      1.19    dyoung 				IEEE80211_MICBUF_SIZE);
    913      1.19    dyoung 			ik.ik_keylen += IEEE80211_MICBUF_SIZE;
    914      1.19    dyoung 		}
    915      1.19    dyoung 	} else {
    916      1.19    dyoung 		ik.ik_keyrsc = 0;
    917      1.19    dyoung 		ik.ik_keytsc = 0;
    918      1.19    dyoung 		memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
    919      1.19    dyoung 	}
    920      1.19    dyoung 	if (ni != NULL)
    921      1.19    dyoung 		ieee80211_free_node(ni);
    922      1.19    dyoung 	return copyout(&ik, ireq->i_data, sizeof(ik));
    923      1.19    dyoung }
    924      1.19    dyoung 
    925      1.19    dyoung static int
    926      1.19    dyoung ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
    927      1.19    dyoung {
    928      1.27  christos 	size_t len = ireq->i_len;
    929      1.19    dyoung 
    930      1.27  christos 	if (sizeof(ic->ic_chan_active) < len) {
    931      1.27  christos 		len = sizeof(ic->ic_chan_active);
    932      1.27  christos 	}
    933      1.27  christos 	return copyout(&ic->ic_chan_active, ireq->i_data, len);
    934      1.19    dyoung }
    935      1.19    dyoung 
    936      1.19    dyoung static int
    937      1.19    dyoung ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
    938      1.19    dyoung {
    939  1.48.4.1     skrll 	int space;
    940      1.35  christos 
    941      1.19    dyoung 	space = __offsetof(struct ieee80211req_chaninfo,
    942  1.48.4.1     skrll 	    ic_chans[ic->ic_nchans]);
    943      1.19    dyoung 	if (space > ireq->i_len)
    944      1.19    dyoung 		space = ireq->i_len;
    945  1.48.4.1     skrll 	/* XXX assumes compatible layout */
    946  1.48.4.1     skrll 	return copyout(&ic->ic_nchans, ireq->i_data, space);
    947      1.19    dyoung }
    948      1.19    dyoung 
    949      1.19    dyoung static int
    950  1.48.4.1     skrll ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq, int req)
    951      1.19    dyoung {
    952      1.19    dyoung 	struct ieee80211_node *ni;
    953  1.48.4.1     skrll 	struct ieee80211req_wpaie2 wpaie;
    954      1.19    dyoung 	int error;
    955      1.19    dyoung 
    956      1.19    dyoung 	if (ireq->i_len < IEEE80211_ADDR_LEN)
    957      1.19    dyoung 		return EINVAL;
    958      1.19    dyoung 	error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
    959      1.19    dyoung 	if (error != 0)
    960      1.19    dyoung 		return error;
    961      1.19    dyoung 	ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
    962      1.19    dyoung 	if (ni == NULL)
    963  1.48.4.1     skrll 		return ENOENT;		/* XXX */
    964      1.19    dyoung 	memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
    965      1.19    dyoung 	if (ni->ni_wpa_ie != NULL) {
    966      1.19    dyoung 		int ielen = ni->ni_wpa_ie[1] + 2;
    967      1.19    dyoung 		if (ielen > sizeof(wpaie.wpa_ie))
    968      1.19    dyoung 			ielen = sizeof(wpaie.wpa_ie);
    969      1.19    dyoung 		memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
    970      1.19    dyoung 	}
    971  1.48.4.1     skrll 	if (req == IEEE80211_IOC_WPAIE2) {
    972  1.48.4.1     skrll 		memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie));
    973  1.48.4.1     skrll 		if (ni->ni_rsn_ie != NULL) {
    974  1.48.4.1     skrll 			int ielen = ni->ni_rsn_ie[1] + 2;
    975  1.48.4.1     skrll 			if (ielen > sizeof(wpaie.rsn_ie))
    976  1.48.4.1     skrll 				ielen = sizeof(wpaie.rsn_ie);
    977  1.48.4.1     skrll 			memcpy(wpaie.rsn_ie, ni->ni_rsn_ie, ielen);
    978  1.48.4.1     skrll 		}
    979  1.48.4.1     skrll 		if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
    980  1.48.4.1     skrll 			ireq->i_len = sizeof(struct ieee80211req_wpaie2);
    981  1.48.4.1     skrll 	} else {
    982  1.48.4.1     skrll 		/* compatibility op, may overwrite wpa ie */
    983  1.48.4.1     skrll 		/* XXX check ic_flags? */
    984  1.48.4.1     skrll 		if (ni->ni_rsn_ie != NULL) {
    985  1.48.4.1     skrll 			int ielen = ni->ni_rsn_ie[1] + 2;
    986  1.48.4.1     skrll 			if (ielen > sizeof(wpaie.wpa_ie))
    987  1.48.4.1     skrll 				ielen = sizeof(wpaie.wpa_ie);
    988  1.48.4.1     skrll 			memcpy(wpaie.wpa_ie, ni->ni_rsn_ie, ielen);
    989  1.48.4.1     skrll 		}
    990  1.48.4.1     skrll 		if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
    991  1.48.4.1     skrll 			ireq->i_len = sizeof(struct ieee80211req_wpaie);
    992  1.48.4.1     skrll 	}
    993      1.19    dyoung 	ieee80211_free_node(ni);
    994      1.19    dyoung 	return copyout(&wpaie, ireq->i_data, ireq->i_len);
    995      1.19    dyoung }
    996      1.19    dyoung 
    997      1.19    dyoung static int
    998      1.19    dyoung ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
    999      1.19    dyoung {
   1000      1.19    dyoung 	struct ieee80211_node *ni;
   1001  1.48.4.1     skrll 	uint8_t macaddr[IEEE80211_ADDR_LEN];
   1002      1.19    dyoung 	const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
   1003      1.19    dyoung 	int error;
   1004      1.19    dyoung 
   1005      1.19    dyoung 	if (ireq->i_len < off)
   1006      1.19    dyoung 		return EINVAL;
   1007      1.19    dyoung 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
   1008      1.19    dyoung 	if (error != 0)
   1009      1.19    dyoung 		return error;
   1010      1.19    dyoung 	ni = ieee80211_find_node(&ic->ic_sta, macaddr);
   1011      1.19    dyoung 	if (ni == NULL)
   1012  1.48.4.1     skrll 		return EINVAL;
   1013      1.19    dyoung 	if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
   1014      1.19    dyoung 		ireq->i_len = sizeof(struct ieee80211req_sta_stats);
   1015      1.19    dyoung 	/* NB: copy out only the statistics */
   1016  1.48.4.1     skrll 	error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
   1017      1.19    dyoung 			ireq->i_len - off);
   1018      1.19    dyoung 	ieee80211_free_node(ni);
   1019      1.19    dyoung 	return error;
   1020      1.19    dyoung }
   1021      1.19    dyoung 
   1022  1.48.4.1     skrll static __inline uint8_t *
   1023  1.48.4.1     skrll copyie(uint8_t *cp, const uint8_t *ie)
   1024  1.48.4.1     skrll {
   1025  1.48.4.1     skrll 	if (ie != NULL) {
   1026  1.48.4.1     skrll 		memcpy(cp, ie, 2+ie[1]);
   1027  1.48.4.1     skrll 		cp += 2+ie[1];
   1028  1.48.4.1     skrll 	}
   1029  1.48.4.1     skrll 	return cp;
   1030  1.48.4.1     skrll }
   1031  1.48.4.1     skrll 
   1032  1.48.4.1     skrll #ifdef COMPAT_FREEBSD6
   1033  1.48.4.1     skrll #define	IEEE80211_IOC_SCAN_RESULTS_OLD	24
   1034  1.48.4.1     skrll 
   1035  1.48.4.1     skrll struct scan_result_old {
   1036  1.48.4.1     skrll 	uint16_t	isr_len;		/* length (mult of 4) */
   1037  1.48.4.1     skrll 	uint16_t	isr_freq;		/* MHz */
   1038  1.48.4.1     skrll 	uint16_t	isr_flags;		/* channel flags */
   1039  1.48.4.1     skrll 	uint8_t		isr_noise;
   1040  1.48.4.1     skrll 	uint8_t		isr_rssi;
   1041  1.48.4.1     skrll 	uint8_t		isr_intval;		/* beacon interval */
   1042  1.48.4.1     skrll 	uint8_t		isr_capinfo;		/* capabilities */
   1043  1.48.4.1     skrll 	uint8_t		isr_erp;		/* ERP element */
   1044  1.48.4.1     skrll 	uint8_t		isr_bssid[IEEE80211_ADDR_LEN];
   1045  1.48.4.1     skrll 	uint8_t		isr_nrates;
   1046  1.48.4.1     skrll 	uint8_t		isr_rates[IEEE80211_RATE_MAXSIZE];
   1047  1.48.4.1     skrll 	uint8_t		isr_ssid_len;		/* SSID length */
   1048  1.48.4.1     skrll 	uint8_t		isr_ie_len;		/* IE length */
   1049  1.48.4.1     skrll 	uint8_t		isr_pad[5];
   1050  1.48.4.1     skrll 	/* variable length SSID followed by IE data */
   1051  1.48.4.1     skrll };
   1052  1.48.4.1     skrll 
   1053  1.48.4.1     skrll struct oscanreq {
   1054  1.48.4.1     skrll 	struct scan_result_old *sr;
   1055  1.48.4.1     skrll 	size_t space;
   1056  1.48.4.1     skrll };
   1057  1.48.4.1     skrll 
   1058  1.48.4.1     skrll static size_t
   1059  1.48.4.1     skrll old_scan_space(const struct ieee80211_scan_entry *se, int *ielen)
   1060  1.48.4.1     skrll {
   1061  1.48.4.1     skrll 	size_t len;
   1062  1.48.4.1     skrll 
   1063  1.48.4.1     skrll 	*ielen = 0;
   1064  1.48.4.1     skrll 	if (se->se_wpa_ie != NULL)
   1065  1.48.4.1     skrll 		*ielen += 2+se->se_wpa_ie[1];
   1066  1.48.4.1     skrll 	if (se->se_wme_ie != NULL)
   1067  1.48.4.1     skrll 		*ielen += 2+se->se_wme_ie[1];
   1068  1.48.4.1     skrll 	/*
   1069  1.48.4.1     skrll 	 * NB: ie's can be no more than 255 bytes and the max 802.11
   1070  1.48.4.1     skrll 	 * packet is <3Kbytes so we are sure this doesn't overflow
   1071  1.48.4.1     skrll 	 * 16-bits; if this is a concern we can drop the ie's.
   1072  1.48.4.1     skrll 	 */
   1073  1.48.4.1     skrll 	len = sizeof(struct scan_result_old) + se->se_ssid[1] + *ielen;
   1074  1.48.4.1     skrll 	return roundup(len, sizeof(uint32_t));
   1075  1.48.4.1     skrll }
   1076  1.48.4.1     skrll 
   1077      1.19    dyoung static void
   1078  1.48.4.1     skrll old_get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
   1079      1.19    dyoung {
   1080  1.48.4.1     skrll 	struct oscanreq *req = arg;
   1081  1.48.4.1     skrll 	int ielen = 0;
   1082      1.19    dyoung 
   1083  1.48.4.1     skrll 	req->space += old_scan_space(se, &ielen);
   1084  1.48.4.1     skrll }
   1085  1.48.4.1     skrll 
   1086  1.48.4.1     skrll static void
   1087  1.48.4.1     skrll old_get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
   1088  1.48.4.1     skrll {
   1089  1.48.4.1     skrll 	struct oscanreq *req = arg;
   1090  1.48.4.1     skrll 	struct scan_result_old *sr;
   1091  1.48.4.1     skrll 	int ielen, len, nr, nxr;
   1092  1.48.4.1     skrll 	uint8_t *cp;
   1093  1.48.4.1     skrll 
   1094  1.48.4.1     skrll 	len = old_scan_space(se, &ielen);
   1095  1.48.4.1     skrll 	if (len > req->space)
   1096  1.48.4.1     skrll 		return;
   1097      1.28  christos 
   1098  1.48.4.1     skrll 	sr = req->sr;
   1099  1.48.4.1     skrll 	memset(sr, 0, sizeof(*sr));
   1100  1.48.4.1     skrll 	sr->isr_ssid_len = se->se_ssid[1];
   1101      1.28  christos 	/*
   1102      1.28  christos 	 * The value sr->isr_ie_len is defined as a uint8_t, so we
   1103      1.28  christos 	 * need to be careful to avoid an integer overflow.  If the
   1104      1.28  christos 	 * value would overflow, we will set isr_ie_len to zero, and
   1105      1.28  christos 	 * ieee80211_ioctl_getscanresults (below) will avoid copying
   1106      1.28  christos 	 * the (overflowing) data.
   1107      1.28  christos 	 */
   1108      1.28  christos 	if (ielen > 255)
   1109      1.28  christos 		ielen = 0;
   1110      1.28  christos 	sr->isr_ie_len = ielen;
   1111  1.48.4.1     skrll 	sr->isr_len = len;
   1112  1.48.4.1     skrll 	sr->isr_freq = se->se_chan->ic_freq;
   1113  1.48.4.1     skrll 	sr->isr_flags = se->se_chan->ic_flags;
   1114  1.48.4.1     skrll 	sr->isr_rssi = se->se_rssi;
   1115  1.48.4.1     skrll 	sr->isr_noise = se->se_noise;
   1116  1.48.4.1     skrll 	sr->isr_intval = se->se_intval;
   1117  1.48.4.1     skrll 	sr->isr_capinfo = se->se_capinfo;
   1118  1.48.4.1     skrll 	sr->isr_erp = se->se_erp;
   1119  1.48.4.1     skrll 	IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
   1120  1.48.4.1     skrll 	nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
   1121  1.48.4.1     skrll 	memcpy(sr->isr_rates, se->se_rates+2, nr);
   1122  1.48.4.1     skrll 	nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
   1123  1.48.4.1     skrll 	memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
   1124  1.48.4.1     skrll 	sr->isr_nrates = nr + nxr;
   1125  1.48.4.1     skrll 
   1126  1.48.4.1     skrll 	cp = (uint8_t *)(sr+1);
   1127  1.48.4.1     skrll 	memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
   1128  1.48.4.1     skrll 	cp += sr->isr_ssid_len;
   1129  1.48.4.1     skrll 	if (sr->isr_ie_len) {
   1130  1.48.4.1     skrll 		cp = copyie(cp, se->se_wpa_ie);
   1131  1.48.4.1     skrll 		cp = copyie(cp, se->se_wme_ie);
   1132  1.48.4.1     skrll 	}
   1133  1.48.4.1     skrll 
   1134  1.48.4.1     skrll 	req->space -= len;
   1135  1.48.4.1     skrll 	req->sr = (struct scan_result_old *)(((uint8_t *)sr) + len);
   1136      1.19    dyoung }
   1137      1.19    dyoung 
   1138      1.19    dyoung static int
   1139  1.48.4.1     skrll old_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
   1140      1.19    dyoung {
   1141  1.48.4.1     skrll 	struct oscanreq req;
   1142  1.48.4.1     skrll 	int error;
   1143  1.48.4.1     skrll 
   1144  1.48.4.1     skrll 	if (ireq->i_len < sizeof(struct scan_result_old))
   1145  1.48.4.1     skrll 		return EFAULT;
   1146      1.19    dyoung 
   1147      1.19    dyoung 	error = 0;
   1148  1.48.4.1     skrll 	req.space = 0;
   1149  1.48.4.1     skrll 	ieee80211_scan_iterate(ic, old_get_scan_space, &req);
   1150  1.48.4.1     skrll 	if (req.space > ireq->i_len)
   1151  1.48.4.1     skrll 		req.space = ireq->i_len;
   1152  1.48.4.1     skrll 	if (req.space > 0) {
   1153  1.48.4.1     skrll 		size_t space;
   1154  1.48.4.1     skrll 		void *p;
   1155  1.48.4.1     skrll 
   1156  1.48.4.1     skrll 		space = req.space;
   1157  1.48.4.1     skrll 		/* XXX M_WAITOK after driver lock released */
   1158  1.48.4.1     skrll 		p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO);
   1159  1.48.4.1     skrll 		if (p == NULL)
   1160  1.48.4.1     skrll 			return ENOMEM;
   1161  1.48.4.1     skrll 		req.sr = p;
   1162  1.48.4.1     skrll 		ieee80211_scan_iterate(ic, old_get_scan_result, &req);
   1163  1.48.4.1     skrll 		ireq->i_len = space - req.space;
   1164  1.48.4.1     skrll 		error = copyout(p, ireq->i_data, ireq->i_len);
   1165  1.48.4.1     skrll 		FREE(p, M_TEMP);
   1166  1.48.4.1     skrll 	} else
   1167  1.48.4.1     skrll 		ireq->i_len = 0;
   1168  1.48.4.1     skrll 
   1169  1.48.4.1     skrll 	return error;
   1170  1.48.4.1     skrll }
   1171  1.48.4.1     skrll #endif /* COMPAT_FREEBSD6 */
   1172  1.48.4.1     skrll 
   1173  1.48.4.1     skrll struct scanreq {
   1174  1.48.4.1     skrll 	struct ieee80211req_scan_result *sr;
   1175  1.48.4.1     skrll 	size_t space;
   1176  1.48.4.1     skrll };
   1177  1.48.4.1     skrll 
   1178  1.48.4.1     skrll static size_t
   1179  1.48.4.1     skrll scan_space(const struct ieee80211_scan_entry *se, int *ielen)
   1180  1.48.4.1     skrll {
   1181  1.48.4.1     skrll 	size_t len;
   1182  1.48.4.1     skrll 
   1183  1.48.4.1     skrll 	*ielen = 0;
   1184  1.48.4.1     skrll 	if (se->se_wpa_ie != NULL)
   1185  1.48.4.1     skrll 		*ielen += 2+se->se_wpa_ie[1];
   1186  1.48.4.1     skrll 	if (se->se_rsn_ie != NULL)
   1187  1.48.4.1     skrll 		*ielen += 2+se->se_rsn_ie[1];
   1188  1.48.4.1     skrll 	if (se->se_wme_ie != NULL)
   1189  1.48.4.1     skrll 		*ielen += 2+se->se_wme_ie[1];
   1190  1.48.4.1     skrll 	if (se->se_ath_ie != NULL)
   1191  1.48.4.1     skrll 		*ielen += 2+se->se_ath_ie[1];
   1192  1.48.4.1     skrll 	/*
   1193  1.48.4.1     skrll 	 * NB: ie's can be no more than 255 bytes and the max 802.11
   1194  1.48.4.1     skrll 	 * packet is <3Kbytes so we are sure this doesn't overflow
   1195  1.48.4.1     skrll 	 * 16-bits; if this is a concern we can drop the ie's.
   1196  1.48.4.1     skrll 	 */
   1197  1.48.4.1     skrll 	len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] + *ielen;
   1198  1.48.4.1     skrll 	return roundup(len, sizeof(uint32_t));
   1199  1.48.4.1     skrll }
   1200  1.48.4.1     skrll 
   1201  1.48.4.1     skrll static void
   1202  1.48.4.1     skrll get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
   1203  1.48.4.1     skrll {
   1204  1.48.4.1     skrll 	struct scanreq *req = arg;
   1205  1.48.4.1     skrll 	int ielen;
   1206  1.48.4.1     skrll 
   1207  1.48.4.1     skrll 	req->space += scan_space(se, &ielen);
   1208  1.48.4.1     skrll }
   1209  1.48.4.1     skrll 
   1210  1.48.4.1     skrll static void
   1211  1.48.4.1     skrll get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
   1212  1.48.4.1     skrll {
   1213  1.48.4.1     skrll 	struct scanreq *req = arg;
   1214  1.48.4.1     skrll 	struct ieee80211req_scan_result *sr;
   1215  1.48.4.1     skrll 	int ielen, len, nr, nxr;
   1216  1.48.4.1     skrll 	uint8_t *cp;
   1217  1.48.4.1     skrll 
   1218  1.48.4.1     skrll 	len = scan_space(se, &ielen);
   1219  1.48.4.1     skrll 	if (len > req->space)
   1220  1.48.4.1     skrll 		return;
   1221  1.48.4.1     skrll 
   1222  1.48.4.1     skrll 	sr = req->sr;
   1223  1.48.4.1     skrll 	IASSERT(len <= 65535 && ielen <= 65535,
   1224  1.48.4.1     skrll 	    ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
   1225  1.48.4.1     skrll 	sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
   1226  1.48.4.1     skrll 	sr->isr_ie_len = ielen;
   1227  1.48.4.1     skrll 	sr->isr_len = len;
   1228  1.48.4.1     skrll 	sr->isr_freq = se->se_chan->ic_freq;
   1229  1.48.4.1     skrll 	sr->isr_flags = se->se_chan->ic_flags;
   1230  1.48.4.1     skrll 	sr->isr_rssi = se->se_rssi;
   1231  1.48.4.1     skrll 	sr->isr_noise = se->se_noise;
   1232  1.48.4.1     skrll 	sr->isr_intval = se->se_intval;
   1233  1.48.4.1     skrll 	sr->isr_capinfo = se->se_capinfo;
   1234  1.48.4.1     skrll 	sr->isr_erp = se->se_erp;
   1235  1.48.4.1     skrll 	IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
   1236  1.48.4.1     skrll 	nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
   1237  1.48.4.1     skrll 	memcpy(sr->isr_rates, se->se_rates+2, nr);
   1238  1.48.4.1     skrll 	nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
   1239  1.48.4.1     skrll 	memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
   1240  1.48.4.1     skrll 	sr->isr_nrates = nr + nxr;
   1241  1.48.4.1     skrll 
   1242  1.48.4.1     skrll 	sr->isr_ssid_len = se->se_ssid[1];
   1243  1.48.4.1     skrll 	cp = ((uint8_t *)sr) + sr->isr_ie_off;
   1244  1.48.4.1     skrll 	memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
   1245  1.48.4.1     skrll 
   1246  1.48.4.1     skrll 	if (ielen) {
   1247  1.48.4.1     skrll 		cp += sr->isr_ssid_len;
   1248  1.48.4.1     skrll 		cp = copyie(cp, se->se_wpa_ie);
   1249  1.48.4.1     skrll 		cp = copyie(cp, se->se_rsn_ie);
   1250  1.48.4.1     skrll 		cp = copyie(cp, se->se_wme_ie);
   1251  1.48.4.1     skrll 		cp = copyie(cp, se->se_ath_ie);
   1252  1.48.4.1     skrll 		cp = copyie(cp, se->se_htcap_ie);
   1253      1.19    dyoung 	}
   1254  1.48.4.1     skrll 
   1255  1.48.4.1     skrll 	req->space -= len;
   1256  1.48.4.1     skrll 	req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
   1257  1.48.4.1     skrll }
   1258  1.48.4.1     skrll 
   1259  1.48.4.1     skrll static int
   1260  1.48.4.1     skrll ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
   1261  1.48.4.1     skrll {
   1262  1.48.4.1     skrll 	struct scanreq req;
   1263  1.48.4.1     skrll 	int error;
   1264  1.48.4.1     skrll 
   1265  1.48.4.1     skrll 	if (ireq->i_len < sizeof(struct ieee80211req_scan_result))
   1266  1.48.4.1     skrll 		return EFAULT;
   1267  1.48.4.1     skrll 
   1268  1.48.4.1     skrll 	error = 0;
   1269  1.48.4.1     skrll 	req.space = 0;
   1270  1.48.4.1     skrll 	ieee80211_scan_iterate(ic, get_scan_space, &req);
   1271  1.48.4.1     skrll 	if (req.space > ireq->i_len)
   1272  1.48.4.1     skrll 		req.space = ireq->i_len;
   1273  1.48.4.1     skrll 	if (req.space > 0) {
   1274  1.48.4.1     skrll 		size_t space;
   1275  1.48.4.1     skrll 		void *p;
   1276  1.48.4.1     skrll 
   1277  1.48.4.1     skrll 		space = req.space;
   1278  1.48.4.1     skrll 		/* XXX M_WAITOK after driver lock released */
   1279  1.48.4.1     skrll 		p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO);
   1280  1.48.4.1     skrll 		if (p == NULL)
   1281  1.48.4.1     skrll 			return ENOMEM;
   1282  1.48.4.1     skrll 		req.sr = p;
   1283  1.48.4.1     skrll 		ieee80211_scan_iterate(ic, get_scan_result, &req);
   1284  1.48.4.1     skrll 		ireq->i_len = space - req.space;
   1285  1.48.4.1     skrll 		error = copyout(p, ireq->i_data, ireq->i_len);
   1286  1.48.4.1     skrll 		FREE(p, M_TEMP);
   1287  1.48.4.1     skrll 	} else
   1288  1.48.4.1     skrll 		ireq->i_len = 0;
   1289  1.48.4.1     skrll 
   1290      1.19    dyoung 	return error;
   1291      1.19    dyoung }
   1292      1.19    dyoung 
   1293      1.26     skrll struct stainforeq {
   1294      1.26     skrll 	struct ieee80211com *ic;
   1295      1.26     skrll 	struct ieee80211req_sta_info *si;
   1296      1.26     skrll 	size_t	space;
   1297      1.26     skrll };
   1298      1.26     skrll 
   1299      1.26     skrll static size_t
   1300      1.26     skrll sta_space(const struct ieee80211_node *ni, size_t *ielen)
   1301      1.26     skrll {
   1302      1.26     skrll 	*ielen = 0;
   1303      1.26     skrll 	if (ni->ni_wpa_ie != NULL)
   1304      1.26     skrll 		*ielen += 2+ni->ni_wpa_ie[1];
   1305  1.48.4.1     skrll 	if (ni->ni_rsn_ie != NULL)
   1306  1.48.4.1     skrll 		*ielen += 2+ni->ni_rsn_ie[1];
   1307      1.26     skrll 	if (ni->ni_wme_ie != NULL)
   1308      1.26     skrll 		*ielen += 2+ni->ni_wme_ie[1];
   1309  1.48.4.1     skrll 	if (ni->ni_ath_ie != NULL)
   1310  1.48.4.1     skrll 		*ielen += 2+ni->ni_ath_ie[1];
   1311      1.26     skrll 	return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
   1312  1.48.4.1     skrll 		      sizeof(uint32_t));
   1313      1.26     skrll }
   1314      1.26     skrll 
   1315      1.19    dyoung static void
   1316      1.26     skrll get_sta_space(void *arg, struct ieee80211_node *ni)
   1317      1.19    dyoung {
   1318      1.26     skrll 	struct stainforeq *req = arg;
   1319      1.19    dyoung 	struct ieee80211com *ic = ni->ni_ic;
   1320      1.26     skrll 	size_t ielen;
   1321      1.19    dyoung 
   1322      1.26     skrll 	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
   1323      1.26     skrll 	    ni->ni_associd == 0)	/* only associated stations */
   1324      1.26     skrll 		return;
   1325      1.26     skrll 	req->space += sta_space(ni, &ielen);
   1326      1.26     skrll }
   1327      1.26     skrll 
   1328      1.26     skrll static void
   1329      1.26     skrll get_sta_info(void *arg, struct ieee80211_node *ni)
   1330      1.26     skrll {
   1331      1.26     skrll 	struct stainforeq *req = arg;
   1332      1.26     skrll 	struct ieee80211com *ic = ni->ni_ic;
   1333      1.26     skrll 	struct ieee80211req_sta_info *si;
   1334      1.26     skrll 	size_t ielen, len;
   1335  1.48.4.1     skrll 	uint8_t *cp;
   1336      1.26     skrll 
   1337      1.26     skrll 	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
   1338      1.26     skrll 	    ni->ni_associd == 0)	/* only associated stations */
   1339      1.26     skrll 		return;
   1340      1.26     skrll 	if (ni->ni_chan == IEEE80211_CHAN_ANYC)	/* XXX bogus entry */
   1341      1.26     skrll 		return;
   1342      1.26     skrll 	len = sta_space(ni, &ielen);
   1343      1.26     skrll 	if (len > req->space)
   1344      1.26     skrll 		return;
   1345      1.26     skrll 	si = req->si;
   1346      1.26     skrll 	si->isi_len = len;
   1347  1.48.4.1     skrll 	si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
   1348      1.26     skrll 	si->isi_ie_len = ielen;
   1349      1.19    dyoung 	si->isi_freq = ni->ni_chan->ic_freq;
   1350      1.19    dyoung 	si->isi_flags = ni->ni_chan->ic_flags;
   1351      1.19    dyoung 	si->isi_state = ni->ni_flags;
   1352      1.19    dyoung 	si->isi_authmode = ni->ni_authmode;
   1353  1.48.4.1     skrll 	ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
   1354  1.48.4.1     skrll 	si->isi_noise = 0;		/* XXX */
   1355      1.19    dyoung 	si->isi_capinfo = ni->ni_capinfo;
   1356      1.19    dyoung 	si->isi_erp = ni->ni_erp;
   1357      1.19    dyoung 	IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
   1358      1.19    dyoung 	si->isi_nrates = ni->ni_rates.rs_nrates;
   1359      1.19    dyoung 	if (si->isi_nrates > 15)
   1360      1.19    dyoung 		si->isi_nrates = 15;
   1361      1.19    dyoung 	memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
   1362      1.19    dyoung 	si->isi_txrate = ni->ni_txrate;
   1363  1.48.4.1     skrll 	si->isi_ie_len = ielen;
   1364      1.19    dyoung 	si->isi_associd = ni->ni_associd;
   1365      1.19    dyoung 	si->isi_txpower = ni->ni_txpower;
   1366      1.19    dyoung 	si->isi_vlan = ni->ni_vlan;
   1367      1.19    dyoung 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
   1368      1.19    dyoung 		memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
   1369      1.19    dyoung 		memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
   1370      1.19    dyoung 	} else {
   1371  1.48.4.1     skrll 		si->isi_txseqs[0] = ni->ni_txseqs[IEEE80211_NONQOS_TID];
   1372  1.48.4.1     skrll 		si->isi_rxseqs[0] = ni->ni_rxseqs[IEEE80211_NONQOS_TID];
   1373      1.19    dyoung 	}
   1374      1.26     skrll 	/* NB: leave all cases in case we relax ni_associd == 0 check */
   1375      1.26     skrll 	if (ieee80211_node_is_authorized(ni))
   1376      1.19    dyoung 		si->isi_inact = ic->ic_inact_run;
   1377      1.26     skrll 	else if (ni->ni_associd != 0)
   1378      1.19    dyoung 		si->isi_inact = ic->ic_inact_auth;
   1379      1.19    dyoung 	else
   1380      1.19    dyoung 		si->isi_inact = ic->ic_inact_init;
   1381      1.19    dyoung 	si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
   1382      1.26     skrll 
   1383  1.48.4.1     skrll 	if (ielen) {
   1384  1.48.4.1     skrll 		cp = ((uint8_t *)si) + si->isi_ie_off;
   1385  1.48.4.1     skrll 		cp = copyie(cp, ni->ni_wpa_ie);
   1386  1.48.4.1     skrll 		cp = copyie(cp, ni->ni_rsn_ie);
   1387  1.48.4.1     skrll 		cp = copyie(cp, ni->ni_wme_ie);
   1388  1.48.4.1     skrll 		cp = copyie(cp, ni->ni_ath_ie);
   1389      1.26     skrll 	}
   1390      1.26     skrll 
   1391  1.48.4.1     skrll 	req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
   1392      1.26     skrll 	req->space -= len;
   1393      1.19    dyoung }
   1394      1.19    dyoung 
   1395      1.19    dyoung static int
   1396  1.48.4.1     skrll getstainfo_common(struct ieee80211com *ic, struct ieee80211req *ireq,
   1397  1.48.4.1     skrll 	struct ieee80211_node *ni, int off)
   1398      1.19    dyoung {
   1399      1.26     skrll 	struct stainforeq req;
   1400  1.48.4.1     skrll 	size_t space;
   1401  1.48.4.1     skrll 	void *p;
   1402      1.26     skrll 	int error;
   1403      1.26     skrll 
   1404      1.19    dyoung 	error = 0;
   1405      1.26     skrll 	req.space = 0;
   1406  1.48.4.1     skrll 	if (ni == NULL)
   1407  1.48.4.1     skrll 		ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
   1408  1.48.4.1     skrll 	else
   1409  1.48.4.1     skrll 		get_sta_space(&req, ni);
   1410      1.26     skrll 	if (req.space > ireq->i_len)
   1411      1.26     skrll 		req.space = ireq->i_len;
   1412      1.26     skrll 	if (req.space > 0) {
   1413      1.26     skrll 		space = req.space;
   1414      1.26     skrll 		/* XXX M_WAITOK after driver lock released */
   1415      1.31  christos 		p = malloc(space, M_TEMP, M_NOWAIT);
   1416  1.48.4.1     skrll 		if (p == NULL) {
   1417  1.48.4.1     skrll 			error = ENOMEM;
   1418  1.48.4.1     skrll 			goto bad;
   1419  1.48.4.1     skrll 		}
   1420      1.26     skrll 		req.si = p;
   1421  1.48.4.1     skrll 		if (ni == NULL)
   1422  1.48.4.1     skrll 			ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
   1423  1.48.4.1     skrll 		else
   1424  1.48.4.1     skrll 			get_sta_info(&req, ni);
   1425      1.26     skrll 		ireq->i_len = space - req.space;
   1426  1.48.4.1     skrll 		error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
   1427      1.26     skrll 		FREE(p, M_TEMP);
   1428      1.26     skrll 	} else
   1429      1.26     skrll 		ireq->i_len = 0;
   1430  1.48.4.1     skrll bad:
   1431  1.48.4.1     skrll 	if (ni != NULL)
   1432  1.48.4.1     skrll 		ieee80211_free_node(ni);
   1433      1.19    dyoung 	return error;
   1434      1.19    dyoung }
   1435      1.19    dyoung 
   1436      1.19    dyoung static int
   1437  1.48.4.1     skrll ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
   1438  1.48.4.1     skrll {
   1439  1.48.4.1     skrll 	uint8_t macaddr[IEEE80211_ADDR_LEN];
   1440  1.48.4.1     skrll 	const int off = __offsetof(struct ieee80211req_sta_req, info);
   1441  1.48.4.1     skrll 	struct ieee80211_node *ni;
   1442  1.48.4.1     skrll 	int error;
   1443  1.48.4.1     skrll 
   1444  1.48.4.1     skrll 	if (ireq->i_len < sizeof(struct ieee80211req_sta_req))
   1445  1.48.4.1     skrll 		return EFAULT;
   1446  1.48.4.1     skrll 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
   1447  1.48.4.1     skrll 	if (error != 0)
   1448  1.48.4.1     skrll 		return error;
   1449  1.48.4.1     skrll 	if (IEEE80211_ADDR_EQ(macaddr, ic->ic_ifp->if_broadcastaddr)) {
   1450  1.48.4.1     skrll 		ni = NULL;
   1451  1.48.4.1     skrll 	} else {
   1452  1.48.4.1     skrll 		ni = ieee80211_find_node(&ic->ic_sta, macaddr);
   1453  1.48.4.1     skrll 		if (ni == NULL)
   1454  1.48.4.1     skrll 			return EINVAL;
   1455  1.48.4.1     skrll 	}
   1456  1.48.4.1     skrll 	return getstainfo_common(ic, ireq, ni, off);
   1457  1.48.4.1     skrll }
   1458  1.48.4.1     skrll 
   1459  1.48.4.1     skrll #ifdef COMPAT_FREEBSD6
   1460  1.48.4.1     skrll #define	IEEE80211_IOC_STA_INFO_OLD	45
   1461  1.48.4.1     skrll 
   1462  1.48.4.1     skrll static int
   1463  1.48.4.1     skrll old_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
   1464  1.48.4.1     skrll {
   1465  1.48.4.1     skrll 	if (ireq->i_len < sizeof(struct ieee80211req_sta_info))
   1466  1.48.4.1     skrll 		return EFAULT;
   1467  1.48.4.1     skrll 	return getstainfo_common(ic, ireq, NULL, 0);
   1468  1.48.4.1     skrll }
   1469  1.48.4.1     skrll #endif /* COMPAT_FREEBSD6 */
   1470  1.48.4.1     skrll 
   1471  1.48.4.1     skrll static int
   1472      1.19    dyoung ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
   1473      1.19    dyoung {
   1474      1.19    dyoung 	struct ieee80211_node *ni;
   1475      1.19    dyoung 	struct ieee80211req_sta_txpow txpow;
   1476      1.19    dyoung 	int error;
   1477      1.19    dyoung 
   1478      1.19    dyoung 	if (ireq->i_len != sizeof(txpow))
   1479      1.19    dyoung 		return EINVAL;
   1480      1.19    dyoung 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
   1481      1.19    dyoung 	if (error != 0)
   1482      1.19    dyoung 		return error;
   1483      1.19    dyoung 	ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
   1484      1.19    dyoung 	if (ni == NULL)
   1485      1.19    dyoung 		return EINVAL;		/* XXX */
   1486      1.19    dyoung 	txpow.it_txpow = ni->ni_txpower;
   1487      1.19    dyoung 	error = copyout(&txpow, ireq->i_data, sizeof(txpow));
   1488      1.19    dyoung 	ieee80211_free_node(ni);
   1489       1.1    dyoung 	return error;
   1490       1.1    dyoung }
   1491       1.1    dyoung 
   1492      1.19    dyoung static int
   1493      1.19    dyoung ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
   1494      1.19    dyoung {
   1495      1.19    dyoung 	struct ieee80211_wme_state *wme = &ic->ic_wme;
   1496      1.19    dyoung 	struct wmeParams *wmep;
   1497      1.19    dyoung 	int ac;
   1498      1.19    dyoung 
   1499      1.19    dyoung 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
   1500      1.19    dyoung 		return EINVAL;
   1501      1.19    dyoung 
   1502      1.19    dyoung 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
   1503      1.19    dyoung 	if (ac >= WME_NUM_AC)
   1504      1.19    dyoung 		ac = WME_AC_BE;
   1505      1.19    dyoung 	if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
   1506      1.19    dyoung 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
   1507      1.19    dyoung 	else
   1508      1.19    dyoung 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
   1509      1.19    dyoung 	switch (ireq->i_type) {
   1510      1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   1511      1.19    dyoung 		ireq->i_val = wmep->wmep_logcwmin;
   1512      1.19    dyoung 		break;
   1513      1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   1514      1.19    dyoung 		ireq->i_val = wmep->wmep_logcwmax;
   1515      1.19    dyoung 		break;
   1516      1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   1517      1.19    dyoung 		ireq->i_val = wmep->wmep_aifsn;
   1518      1.19    dyoung 		break;
   1519      1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   1520      1.19    dyoung 		ireq->i_val = wmep->wmep_txopLimit;
   1521      1.19    dyoung 		break;
   1522      1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   1523      1.19    dyoung 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
   1524      1.19    dyoung 		ireq->i_val = wmep->wmep_acm;
   1525      1.19    dyoung 		break;
   1526      1.19    dyoung 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
   1527      1.19    dyoung 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
   1528      1.19    dyoung 		ireq->i_val = !wmep->wmep_noackPolicy;
   1529      1.19    dyoung 		break;
   1530      1.19    dyoung 	}
   1531      1.19    dyoung 	return 0;
   1532      1.19    dyoung }
   1533      1.19    dyoung 
   1534      1.26     skrll static int
   1535      1.26     skrll ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
   1536      1.26     skrll {
   1537      1.26     skrll 	const struct ieee80211_aclator *acl = ic->ic_acl;
   1538      1.26     skrll 
   1539      1.26     skrll 	return (acl == NULL ? EINVAL : acl->iac_getioctl(ic, ireq));
   1540      1.26     skrll }
   1541      1.26     skrll 
   1542  1.48.4.1     skrll /*
   1543  1.48.4.1     skrll  * Return the current ``state'' of an Atheros capbility.
   1544  1.48.4.1     skrll  * If associated in station mode report the negotiated
   1545  1.48.4.1     skrll  * setting. Otherwise report the current setting.
   1546  1.48.4.1     skrll  */
   1547  1.48.4.1     skrll static int
   1548  1.48.4.1     skrll getathcap(struct ieee80211com *ic, int cap)
   1549  1.48.4.1     skrll {
   1550  1.48.4.1     skrll 	if (ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN)
   1551  1.48.4.1     skrll 		return IEEE80211_ATH_CAP(ic, ic->ic_bss, cap) != 0;
   1552  1.48.4.1     skrll 	else
   1553  1.48.4.1     skrll 		return (ic->ic_flags & cap) != 0;
   1554  1.48.4.1     skrll }
   1555  1.48.4.1     skrll 
   1556  1.48.4.1     skrll static int
   1557  1.48.4.1     skrll ieee80211_ioctl_getcurchan(struct ieee80211com *ic, struct ieee80211req *ireq)
   1558  1.48.4.1     skrll {
   1559  1.48.4.1     skrll 	if (ireq->i_len != sizeof(struct ieee80211_channel))
   1560  1.48.4.1     skrll 		return EINVAL;
   1561  1.48.4.1     skrll 	return copyout(ic->ic_curchan, ireq->i_data, sizeof(*ic->ic_curchan));
   1562  1.48.4.1     skrll }
   1563  1.48.4.1     skrll 
   1564      1.44    dyoung #if defined(COMPAT_FREEBSD_NET80211)
   1565      1.19    dyoung static int
   1566      1.44    dyoung ieee80211_ioctl_get80211_fbsd(struct ieee80211com *ic, u_long cmd,
   1567      1.40  christos     struct ieee80211req *ireq)
   1568       1.1    dyoung {
   1569  1.48.4.1     skrll 	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
   1570  1.48.4.1     skrll 	int error = 0;
   1571  1.48.4.1     skrll 	u_int kid, len, m;
   1572  1.48.4.1     skrll 	uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
   1573       1.1    dyoung 	char tmpssid[IEEE80211_NWID_LEN];
   1574      1.47  degroote 	struct ifnet *ifp = ic->ic_ifp;
   1575      1.44    dyoung 
   1576      1.44    dyoung 	int error = 0;
   1577       1.1    dyoung 
   1578      1.19    dyoung 	switch (ireq->i_type) {
   1579      1.19    dyoung 	case IEEE80211_IOC_SSID:
   1580      1.19    dyoung 		switch (ic->ic_state) {
   1581      1.19    dyoung 		case IEEE80211_S_INIT:
   1582      1.19    dyoung 		case IEEE80211_S_SCAN:
   1583  1.48.4.1     skrll 			ireq->i_len = ic->ic_des_ssid[0].len;
   1584  1.48.4.1     skrll 			memcpy(tmpssid, ic->ic_des_ssid[0].ssid, ireq->i_len);
   1585       1.1    dyoung 			break;
   1586      1.19    dyoung 		default:
   1587      1.19    dyoung 			ireq->i_len = ic->ic_bss->ni_esslen;
   1588      1.19    dyoung 			memcpy(tmpssid, ic->ic_bss->ni_essid,
   1589      1.19    dyoung 				ireq->i_len);
   1590       1.1    dyoung 			break;
   1591      1.19    dyoung 		}
   1592      1.19    dyoung 		error = copyout(tmpssid, ireq->i_data, ireq->i_len);
   1593      1.19    dyoung 		break;
   1594      1.19    dyoung 	case IEEE80211_IOC_NUMSSIDS:
   1595      1.19    dyoung 		ireq->i_val = 1;
   1596      1.19    dyoung 		break;
   1597      1.19    dyoung 	case IEEE80211_IOC_WEP:
   1598      1.19    dyoung 		if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
   1599      1.19    dyoung 			ireq->i_val = IEEE80211_WEP_OFF;
   1600      1.19    dyoung 		else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
   1601      1.19    dyoung 			ireq->i_val = IEEE80211_WEP_ON;
   1602      1.19    dyoung 		else
   1603      1.19    dyoung 			ireq->i_val = IEEE80211_WEP_MIXED;
   1604      1.19    dyoung 		break;
   1605      1.19    dyoung 	case IEEE80211_IOC_WEPKEY:
   1606      1.19    dyoung 		kid = (u_int) ireq->i_val;
   1607      1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
   1608      1.19    dyoung 			return EINVAL;
   1609      1.19    dyoung 		len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
   1610      1.19    dyoung 		/* NB: only root can read WEP keys */
   1611      1.41      elad 		if (kauth_authorize_network(curlwp->l_cred,
   1612      1.41      elad 		    KAUTH_NETWORK_INTERFACE,
   1613      1.42      elad 		    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, NULL,
   1614      1.41      elad 		    NULL) == 0) {
   1615      1.19    dyoung 			bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
   1616      1.19    dyoung 		} else {
   1617      1.19    dyoung 			bzero(tmpkey, len);
   1618      1.19    dyoung 		}
   1619      1.19    dyoung 		ireq->i_len = len;
   1620      1.19    dyoung 		error = copyout(tmpkey, ireq->i_data, len);
   1621      1.19    dyoung 		break;
   1622      1.19    dyoung 	case IEEE80211_IOC_NUMWEPKEYS:
   1623      1.19    dyoung 		ireq->i_val = IEEE80211_WEP_NKID;
   1624      1.19    dyoung 		break;
   1625      1.19    dyoung 	case IEEE80211_IOC_WEPTXKEY:
   1626      1.19    dyoung 		ireq->i_val = ic->ic_def_txkey;
   1627      1.19    dyoung 		break;
   1628      1.19    dyoung 	case IEEE80211_IOC_CHANNEL:
   1629      1.26     skrll 		ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
   1630      1.19    dyoung 		break;
   1631      1.19    dyoung 	case IEEE80211_IOC_POWERSAVE:
   1632      1.19    dyoung 		if (ic->ic_flags & IEEE80211_F_PMGTON)
   1633      1.19    dyoung 			ireq->i_val = IEEE80211_POWERSAVE_ON;
   1634      1.19    dyoung 		else
   1635      1.19    dyoung 			ireq->i_val = IEEE80211_POWERSAVE_OFF;
   1636      1.19    dyoung 		break;
   1637      1.19    dyoung 	case IEEE80211_IOC_POWERSAVESLEEP:
   1638      1.19    dyoung 		ireq->i_val = ic->ic_lintval;
   1639      1.19    dyoung 		break;
   1640      1.44    dyoung 	case IEEE80211_IOC_BSSID:
   1641      1.44    dyoung 		if (ireq->i_len != IEEE80211_ADDR_LEN)
   1642      1.44    dyoung 			return EINVAL;
   1643      1.44    dyoung 		error = copyout(ic->ic_state == IEEE80211_S_RUN ?
   1644      1.44    dyoung 					ic->ic_bss->ni_bssid :
   1645      1.44    dyoung 					ic->ic_des_bssid,
   1646      1.44    dyoung 				ireq->i_data, ireq->i_len);
   1647      1.44    dyoung 		break;
   1648      1.44    dyoung 	default:
   1649      1.44    dyoung 		error = EINVAL;
   1650      1.44    dyoung 		break;
   1651      1.44    dyoung 	}
   1652      1.44    dyoung 	return error;
   1653      1.44    dyoung }
   1654      1.44    dyoung #endif /* COMPAT_FREEBSD_NET80211 */
   1655      1.44    dyoung 
   1656      1.44    dyoung /*
   1657      1.44    dyoung  * When building the kernel with -O2 on the i386 architecture, gcc
   1658      1.44    dyoung  * seems to want to inline this function into ieee80211_ioctl()
   1659      1.44    dyoung  * (which is the only routine that calls it). When this happens,
   1660      1.44    dyoung  * ieee80211_ioctl() ends up consuming an additional 2K of stack
   1661      1.44    dyoung  * space. (Exactly why it needs so much is unclear.) The problem
   1662      1.44    dyoung  * is that it's possible for ieee80211_ioctl() to invoke other
   1663      1.44    dyoung  * routines (including driver init functions) which could then find
   1664      1.44    dyoung  * themselves perilously close to exhausting the stack.
   1665      1.44    dyoung  *
   1666      1.44    dyoung  * To avoid this, we deliberately prevent gcc from inlining this
   1667      1.44    dyoung  * routine. Another way to avoid this is to use less agressive
   1668      1.44    dyoung  * optimization when compiling this file (i.e. -O instead of -O2)
   1669      1.44    dyoung  * but special-casing the compilation of this one module in the
   1670      1.44    dyoung  * build system would be awkward.
   1671      1.44    dyoung  */
   1672      1.44    dyoung #ifdef __GNUC__
   1673      1.44    dyoung __attribute__ ((__noinline__))
   1674      1.44    dyoung #endif
   1675      1.44    dyoung static int
   1676      1.44    dyoung ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd,
   1677      1.44    dyoung     struct ieee80211req *ireq)
   1678      1.44    dyoung {
   1679      1.44    dyoung 	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
   1680      1.44    dyoung 	int error = 0;
   1681      1.44    dyoung 	u_int m;
   1682      1.44    dyoung 
   1683      1.44    dyoung 	switch (ireq->i_type) {
   1684      1.44    dyoung 	case IEEE80211_IOC_AUTHMODE:
   1685      1.44    dyoung 		if (ic->ic_flags & IEEE80211_F_WPA)
   1686      1.44    dyoung 			ireq->i_val = IEEE80211_AUTH_WPA;
   1687      1.44    dyoung 		else
   1688      1.44    dyoung 			ireq->i_val = ic->ic_bss->ni_authmode;
   1689      1.44    dyoung 		break;
   1690      1.19    dyoung 	case IEEE80211_IOC_RTSTHRESHOLD:
   1691      1.19    dyoung 		ireq->i_val = ic->ic_rtsthreshold;
   1692      1.19    dyoung 		break;
   1693      1.19    dyoung 	case IEEE80211_IOC_PROTMODE:
   1694      1.19    dyoung 		ireq->i_val = ic->ic_protmode;
   1695      1.19    dyoung 		break;
   1696      1.19    dyoung 	case IEEE80211_IOC_TXPOWER:
   1697      1.19    dyoung 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
   1698      1.19    dyoung 			return EINVAL;
   1699      1.19    dyoung 		ireq->i_val = ic->ic_txpowlimit;
   1700      1.19    dyoung 		break;
   1701      1.19    dyoung 	case IEEE80211_IOC_MCASTCIPHER:
   1702      1.19    dyoung 		ireq->i_val = rsn->rsn_mcastcipher;
   1703      1.19    dyoung 		break;
   1704      1.19    dyoung 	case IEEE80211_IOC_MCASTKEYLEN:
   1705      1.19    dyoung 		ireq->i_val = rsn->rsn_mcastkeylen;
   1706      1.19    dyoung 		break;
   1707      1.19    dyoung 	case IEEE80211_IOC_UCASTCIPHERS:
   1708      1.19    dyoung 		ireq->i_val = 0;
   1709      1.19    dyoung 		for (m = 0x1; m != 0; m <<= 1)
   1710      1.19    dyoung 			if (rsn->rsn_ucastcipherset & m)
   1711      1.19    dyoung 				ireq->i_val |= 1<<cap2cipher(m);
   1712      1.19    dyoung 		break;
   1713      1.19    dyoung 	case IEEE80211_IOC_UCASTCIPHER:
   1714      1.19    dyoung 		ireq->i_val = rsn->rsn_ucastcipher;
   1715      1.19    dyoung 		break;
   1716      1.19    dyoung 	case IEEE80211_IOC_UCASTKEYLEN:
   1717      1.19    dyoung 		ireq->i_val = rsn->rsn_ucastkeylen;
   1718      1.19    dyoung 		break;
   1719      1.19    dyoung 	case IEEE80211_IOC_KEYMGTALGS:
   1720      1.19    dyoung 		ireq->i_val = rsn->rsn_keymgmtset;
   1721      1.19    dyoung 		break;
   1722      1.19    dyoung 	case IEEE80211_IOC_RSNCAPS:
   1723      1.19    dyoung 		ireq->i_val = rsn->rsn_caps;
   1724      1.19    dyoung 		break;
   1725      1.19    dyoung 	case IEEE80211_IOC_WPA:
   1726      1.19    dyoung 		switch (ic->ic_flags & IEEE80211_F_WPA) {
   1727      1.19    dyoung 		case IEEE80211_F_WPA1:
   1728      1.19    dyoung 			ireq->i_val = 1;
   1729      1.19    dyoung 			break;
   1730      1.19    dyoung 		case IEEE80211_F_WPA2:
   1731      1.19    dyoung 			ireq->i_val = 2;
   1732      1.19    dyoung 			break;
   1733      1.19    dyoung 		case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
   1734      1.19    dyoung 			ireq->i_val = 3;
   1735      1.19    dyoung 			break;
   1736      1.19    dyoung 		default:
   1737      1.19    dyoung 			ireq->i_val = 0;
   1738      1.19    dyoung 			break;
   1739      1.19    dyoung 		}
   1740      1.19    dyoung 		break;
   1741      1.19    dyoung 	case IEEE80211_IOC_CHANLIST:
   1742      1.19    dyoung 		error = ieee80211_ioctl_getchanlist(ic, ireq);
   1743      1.19    dyoung 		break;
   1744      1.19    dyoung 	case IEEE80211_IOC_ROAMING:
   1745      1.19    dyoung 		ireq->i_val = ic->ic_roaming;
   1746      1.19    dyoung 		break;
   1747      1.19    dyoung 	case IEEE80211_IOC_PRIVACY:
   1748      1.19    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
   1749      1.19    dyoung 		break;
   1750      1.19    dyoung 	case IEEE80211_IOC_DROPUNENCRYPTED:
   1751      1.19    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
   1752      1.19    dyoung 		break;
   1753      1.19    dyoung 	case IEEE80211_IOC_COUNTERMEASURES:
   1754      1.19    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
   1755      1.19    dyoung 		break;
   1756      1.19    dyoung 	case IEEE80211_IOC_DRIVER_CAPS:
   1757      1.19    dyoung 		ireq->i_val = ic->ic_caps>>16;
   1758      1.19    dyoung 		ireq->i_len = ic->ic_caps&0xffff;
   1759      1.19    dyoung 		break;
   1760      1.19    dyoung 	case IEEE80211_IOC_WME:
   1761      1.19    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
   1762      1.19    dyoung 		break;
   1763      1.19    dyoung 	case IEEE80211_IOC_HIDESSID:
   1764      1.19    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
   1765      1.19    dyoung 		break;
   1766      1.19    dyoung 	case IEEE80211_IOC_APBRIDGE:
   1767      1.19    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
   1768      1.19    dyoung 		break;
   1769      1.19    dyoung 	case IEEE80211_IOC_OPTIE:
   1770      1.19    dyoung 		if (ic->ic_opt_ie == NULL)
   1771      1.19    dyoung 			return EINVAL;
   1772      1.19    dyoung 		/* NB: truncate, caller can check length */
   1773      1.19    dyoung 		if (ireq->i_len > ic->ic_opt_ie_len)
   1774      1.19    dyoung 			ireq->i_len = ic->ic_opt_ie_len;
   1775      1.19    dyoung 		error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
   1776      1.19    dyoung 		break;
   1777      1.19    dyoung 	case IEEE80211_IOC_WPAKEY:
   1778      1.19    dyoung 		error = ieee80211_ioctl_getkey(ic, ireq);
   1779      1.19    dyoung 		break;
   1780      1.19    dyoung 	case IEEE80211_IOC_CHANINFO:
   1781      1.19    dyoung 		error = ieee80211_ioctl_getchaninfo(ic, ireq);
   1782      1.19    dyoung 		break;
   1783      1.19    dyoung 	case IEEE80211_IOC_WPAIE:
   1784  1.48.4.1     skrll 		error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
   1785  1.48.4.1     skrll 		break;
   1786  1.48.4.1     skrll 	case IEEE80211_IOC_WPAIE2:
   1787  1.48.4.1     skrll 		error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
   1788  1.48.4.1     skrll 		break;
   1789  1.48.4.1     skrll #ifdef COMPAT_FREEBSD6
   1790  1.48.4.1     skrll 	case IEEE80211_IOC_SCAN_RESULTS_OLD:
   1791  1.48.4.1     skrll 		error = old_getscanresults(ic, ireq);
   1792      1.19    dyoung 		break;
   1793  1.48.4.1     skrll #endif
   1794      1.19    dyoung 	case IEEE80211_IOC_SCAN_RESULTS:
   1795      1.19    dyoung 		error = ieee80211_ioctl_getscanresults(ic, ireq);
   1796      1.19    dyoung 		break;
   1797      1.19    dyoung 	case IEEE80211_IOC_STA_STATS:
   1798      1.19    dyoung 		error = ieee80211_ioctl_getstastats(ic, ireq);
   1799      1.19    dyoung 		break;
   1800      1.19    dyoung 	case IEEE80211_IOC_TXPOWMAX:
   1801      1.19    dyoung 		ireq->i_val = ic->ic_bss->ni_txpower;
   1802      1.19    dyoung 		break;
   1803      1.19    dyoung 	case IEEE80211_IOC_STA_TXPOW:
   1804      1.19    dyoung 		error = ieee80211_ioctl_getstatxpow(ic, ireq);
   1805      1.19    dyoung 		break;
   1806  1.48.4.1     skrll #ifdef COMPAT_FREEBSD6
   1807  1.48.4.1     skrll 	case IEEE80211_IOC_STA_INFO_OLD:
   1808  1.48.4.1     skrll 		error = old_getstainfo(ic, ireq);
   1809  1.48.4.1     skrll 		break;
   1810  1.48.4.1     skrll #endif
   1811      1.19    dyoung 	case IEEE80211_IOC_STA_INFO:
   1812      1.19    dyoung 		error = ieee80211_ioctl_getstainfo(ic, ireq);
   1813      1.19    dyoung 		break;
   1814      1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   1815      1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   1816      1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   1817      1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   1818      1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   1819      1.19    dyoung 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
   1820      1.19    dyoung 		error = ieee80211_ioctl_getwmeparam(ic, ireq);
   1821      1.19    dyoung 		break;
   1822      1.19    dyoung 	case IEEE80211_IOC_DTIM_PERIOD:
   1823      1.19    dyoung 		ireq->i_val = ic->ic_dtim_period;
   1824      1.19    dyoung 		break;
   1825      1.19    dyoung 	case IEEE80211_IOC_BEACON_INTERVAL:
   1826      1.19    dyoung 		/* NB: get from ic_bss for station mode */
   1827      1.19    dyoung 		ireq->i_val = ic->ic_bss->ni_intval;
   1828      1.19    dyoung 		break;
   1829      1.21    dyoung 	case IEEE80211_IOC_PUREG:
   1830      1.21    dyoung 		ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
   1831      1.21    dyoung 		break;
   1832  1.48.4.1     skrll 	case IEEE80211_IOC_FF:
   1833  1.48.4.1     skrll 		ireq->i_val = getathcap(ic, IEEE80211_F_FF);
   1834  1.48.4.1     skrll 		break;
   1835  1.48.4.1     skrll 	case IEEE80211_IOC_TURBOP:
   1836  1.48.4.1     skrll 		ireq->i_val = getathcap(ic, IEEE80211_F_TURBOP);
   1837  1.48.4.1     skrll 		break;
   1838  1.48.4.1     skrll 	case IEEE80211_IOC_BGSCAN:
   1839  1.48.4.1     skrll 		ireq->i_val = (ic->ic_flags & IEEE80211_F_BGSCAN) != 0;
   1840  1.48.4.1     skrll 		break;
   1841  1.48.4.1     skrll 	case IEEE80211_IOC_BGSCAN_IDLE:
   1842  1.48.4.1     skrll 		ireq->i_val = ic->ic_bgscanidle*hz/1000;	/* ms */
   1843  1.48.4.1     skrll 		break;
   1844  1.48.4.1     skrll 	case IEEE80211_IOC_BGSCAN_INTERVAL:
   1845  1.48.4.1     skrll 		ireq->i_val = ic->ic_bgscanintvl/hz;		/* seconds */
   1846  1.48.4.1     skrll 		break;
   1847  1.48.4.1     skrll 	case IEEE80211_IOC_SCANVALID:
   1848  1.48.4.1     skrll 		ireq->i_val = ic->ic_scanvalid/hz;		/* seconds */
   1849  1.48.4.1     skrll 		break;
   1850  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RSSI_11A:
   1851  1.48.4.1     skrll 		ireq->i_val = ic->ic_roam.rssi11a;
   1852  1.48.4.1     skrll 		break;
   1853  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RSSI_11B:
   1854  1.48.4.1     skrll 		ireq->i_val = ic->ic_roam.rssi11bOnly;
   1855  1.48.4.1     skrll 		break;
   1856  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RSSI_11G:
   1857  1.48.4.1     skrll 		ireq->i_val = ic->ic_roam.rssi11b;
   1858  1.48.4.1     skrll 		break;
   1859  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RATE_11A:
   1860  1.48.4.1     skrll 		ireq->i_val = ic->ic_roam.rate11a;
   1861  1.48.4.1     skrll 		break;
   1862  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RATE_11B:
   1863  1.48.4.1     skrll 		ireq->i_val = ic->ic_roam.rate11bOnly;
   1864  1.48.4.1     skrll 		break;
   1865  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RATE_11G:
   1866  1.48.4.1     skrll 		ireq->i_val = ic->ic_roam.rate11b;
   1867  1.48.4.1     skrll 		break;
   1868      1.30    dyoung 	case IEEE80211_IOC_MCAST_RATE:
   1869      1.30    dyoung 		ireq->i_val = ic->ic_mcast_rate;
   1870      1.30    dyoung 		break;
   1871      1.26     skrll 	case IEEE80211_IOC_FRAGTHRESHOLD:
   1872      1.26     skrll 		ireq->i_val = ic->ic_fragthreshold;
   1873      1.26     skrll 		break;
   1874      1.26     skrll 	case IEEE80211_IOC_MACCMD:
   1875      1.26     skrll 		error = ieee80211_ioctl_getmaccmd(ic, ireq);
   1876      1.26     skrll 		break;
   1877  1.48.4.1     skrll 	case IEEE80211_IOC_BURST:
   1878  1.48.4.1     skrll 		ireq->i_val = (ic->ic_flags & IEEE80211_F_BURST) != 0;
   1879  1.48.4.1     skrll 		break;
   1880  1.48.4.1     skrll 	case IEEE80211_IOC_BMISSTHRESHOLD:
   1881  1.48.4.1     skrll 		ireq->i_val = ic->ic_bmissthreshold;
   1882  1.48.4.1     skrll 		break;
   1883  1.48.4.1     skrll 	case IEEE80211_IOC_CURCHAN:
   1884  1.48.4.1     skrll 		error = ieee80211_ioctl_getcurchan(ic, ireq);
   1885  1.48.4.1     skrll 		break;
   1886  1.48.4.1     skrll 	case IEEE80211_IOC_SHORTGI:
   1887  1.48.4.1     skrll 		ireq->i_val = 0;
   1888  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20)
   1889  1.48.4.1     skrll 			ireq->i_val |= IEEE80211_HTCAP_SHORTGI20;
   1890  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40)
   1891  1.48.4.1     skrll 			ireq->i_val |= IEEE80211_HTCAP_SHORTGI40;
   1892  1.48.4.1     skrll 		break;
   1893  1.48.4.1     skrll 	case IEEE80211_IOC_AMPDU:
   1894  1.48.4.1     skrll 		ireq->i_val = 0;
   1895  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)
   1896  1.48.4.1     skrll 			ireq->i_val |= 1;
   1897  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX)
   1898  1.48.4.1     skrll 			ireq->i_val |= 2;
   1899  1.48.4.1     skrll 		break;
   1900  1.48.4.1     skrll 	case IEEE80211_IOC_AMPDU_LIMIT:
   1901  1.48.4.1     skrll 		ireq->i_val = ic->ic_ampdu_limit;	/* XXX truncation? */
   1902  1.48.4.1     skrll 		break;
   1903  1.48.4.1     skrll 	case IEEE80211_IOC_AMPDU_DENSITY:
   1904  1.48.4.1     skrll 		ireq->i_val = ic->ic_ampdu_density;
   1905  1.48.4.1     skrll 		break;
   1906  1.48.4.1     skrll 	case IEEE80211_IOC_AMSDU:
   1907  1.48.4.1     skrll 		ireq->i_val = 0;
   1908  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_TX)
   1909  1.48.4.1     skrll 			ireq->i_val |= 1;
   1910  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_RX)
   1911  1.48.4.1     skrll 			ireq->i_val |= 2;
   1912  1.48.4.1     skrll 		break;
   1913  1.48.4.1     skrll 	case IEEE80211_IOC_AMSDU_LIMIT:
   1914  1.48.4.1     skrll 		ireq->i_val = ic->ic_amsdu_limit;	/* XXX truncation? */
   1915  1.48.4.1     skrll 		break;
   1916  1.48.4.1     skrll 	case IEEE80211_IOC_PUREN:
   1917  1.48.4.1     skrll 		ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_PUREN) != 0;
   1918  1.48.4.1     skrll 		break;
   1919  1.48.4.1     skrll 	case IEEE80211_IOC_DOTH:
   1920  1.48.4.1     skrll 		ireq->i_val = (ic->ic_flags & IEEE80211_F_DOTH) != 0;
   1921  1.48.4.1     skrll 		break;
   1922  1.48.4.1     skrll 	case IEEE80211_IOC_HTCOMPAT:
   1923  1.48.4.1     skrll 		ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) != 0;
   1924  1.48.4.1     skrll 		break;
   1925  1.48.4.1     skrll 	case IEEE80211_IOC_INACTIVITY:
   1926  1.48.4.1     skrll 		ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_INACT) != 0;
   1927  1.48.4.1     skrll 		break;
   1928  1.48.4.1     skrll 	case IEEE80211_IOC_HTPROTMODE:
   1929  1.48.4.1     skrll 		ireq->i_val = ic->ic_htprotmode;
   1930  1.48.4.1     skrll 		break;
   1931  1.48.4.1     skrll 	case IEEE80211_IOC_HTCONF:
   1932  1.48.4.1     skrll 		if (ic->ic_flags_ext & IEEE80211_FEXT_HT) {
   1933  1.48.4.1     skrll 			ireq->i_val = 1;
   1934  1.48.4.1     skrll 			if (ic->ic_flags_ext & IEEE80211_FEXT_USEHT40)
   1935  1.48.4.1     skrll 				ireq->i_val |= 2;
   1936  1.48.4.1     skrll 		} else
   1937  1.48.4.1     skrll 			ireq->i_val = 0;
   1938  1.48.4.1     skrll 		break;
   1939      1.19    dyoung 	default:
   1940      1.44    dyoung #if defined(COMPAT_FREEBSD_NET80211)
   1941      1.44    dyoung 		error = ieee80211_ioctl_get80211_fbsd(ic, cmd, ireq);
   1942      1.44    dyoung #else
   1943      1.19    dyoung 		error = EINVAL;
   1944      1.44    dyoung #endif /* COMPAT_FREEBSD_NET80211 */
   1945      1.19    dyoung 		break;
   1946      1.19    dyoung 	}
   1947      1.19    dyoung 	return error;
   1948      1.19    dyoung }
   1949      1.19    dyoung 
   1950      1.19    dyoung static int
   1951      1.19    dyoung ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
   1952      1.19    dyoung {
   1953      1.19    dyoung 	int error;
   1954  1.48.4.1     skrll 	void *ie, *oie;
   1955      1.19    dyoung 
   1956      1.19    dyoung 	/*
   1957      1.19    dyoung 	 * NB: Doing this for ap operation could be useful (e.g. for
   1958      1.19    dyoung 	 *     WPA and/or WME) except that it typically is worthless
   1959      1.19    dyoung 	 *     without being able to intervene when processing
   1960      1.19    dyoung 	 *     association response frames--so disallow it for now.
   1961      1.19    dyoung 	 */
   1962      1.19    dyoung 	if (ic->ic_opmode != IEEE80211_M_STA)
   1963      1.19    dyoung 		return EINVAL;
   1964      1.19    dyoung 	if (ireq->i_len > IEEE80211_MAX_OPT_IE)
   1965      1.19    dyoung 		return EINVAL;
   1966      1.19    dyoung 	/* NB: data.length is validated by the wireless extensions code */
   1967  1.48.4.1     skrll 	/* XXX M_WAITOK after driver lock released */
   1968  1.48.4.1     skrll 	if (ireq->i_len > 0) {
   1969  1.48.4.1     skrll 		ie = malloc(ireq->i_len, M_DEVBUF, M_WAITOK);
   1970  1.48.4.1     skrll 		if (ie == NULL)
   1971  1.48.4.1     skrll 			return ENOMEM;
   1972  1.48.4.1     skrll 		error = copyin(ireq->i_data, ie, ireq->i_len);
   1973  1.48.4.1     skrll 		if (error) {
   1974  1.48.4.1     skrll 			free(ie, M_DEVBUF);
   1975  1.48.4.1     skrll 			return error;
   1976  1.48.4.1     skrll 		}
   1977  1.48.4.1     skrll 	} else {
   1978  1.48.4.1     skrll 		ie = NULL;
   1979  1.48.4.1     skrll 		ireq->i_len = 0;
   1980  1.48.4.1     skrll 	}
   1981      1.19    dyoung 	/* XXX sanity check data? */
   1982  1.48.4.1     skrll 	oie = ic->ic_opt_ie;
   1983      1.19    dyoung 	ic->ic_opt_ie = ie;
   1984      1.19    dyoung 	ic->ic_opt_ie_len = ireq->i_len;
   1985  1.48.4.1     skrll 	if (oie != NULL)
   1986  1.48.4.1     skrll 		FREE(oie, M_DEVBUF);
   1987      1.19    dyoung 	return 0;
   1988      1.19    dyoung }
   1989      1.19    dyoung 
   1990      1.19    dyoung static int
   1991      1.19    dyoung ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
   1992      1.19    dyoung {
   1993      1.19    dyoung 	struct ieee80211req_key ik;
   1994      1.19    dyoung 	struct ieee80211_node *ni;
   1995      1.19    dyoung 	struct ieee80211_key *wk;
   1996  1.48.4.1     skrll 	uint16_t kid;
   1997      1.19    dyoung 	int error;
   1998      1.19    dyoung 
   1999      1.19    dyoung 	if (ireq->i_len != sizeof(ik))
   2000      1.19    dyoung 		return EINVAL;
   2001      1.19    dyoung 	error = copyin(ireq->i_data, &ik, sizeof(ik));
   2002      1.19    dyoung 	if (error)
   2003      1.19    dyoung 		return error;
   2004      1.19    dyoung 	/* NB: cipher support is verified by ieee80211_crypt_newkey */
   2005      1.19    dyoung 	/* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
   2006      1.19    dyoung 	if (ik.ik_keylen > sizeof(ik.ik_keydata))
   2007      1.19    dyoung 		return E2BIG;
   2008      1.19    dyoung 	kid = ik.ik_keyix;
   2009      1.19    dyoung 	if (kid == IEEE80211_KEYIX_NONE) {
   2010      1.19    dyoung 		/* XXX unicast keys currently must be tx/rx */
   2011      1.19    dyoung 		if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
   2012      1.19    dyoung 			return EINVAL;
   2013      1.19    dyoung 		if (ic->ic_opmode == IEEE80211_M_STA) {
   2014      1.21    dyoung 			ni = ieee80211_ref_node(ic->ic_bss);
   2015      1.21    dyoung 			if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
   2016      1.21    dyoung 				ieee80211_free_node(ni);
   2017      1.19    dyoung 				return EADDRNOTAVAIL;
   2018      1.21    dyoung 			}
   2019      1.19    dyoung 		} else {
   2020      1.19    dyoung 			ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
   2021      1.19    dyoung 			if (ni == NULL)
   2022      1.19    dyoung 				return ENOENT;
   2023      1.19    dyoung 		}
   2024      1.19    dyoung 		wk = &ni->ni_ucastkey;
   2025      1.19    dyoung 	} else {
   2026      1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
   2027      1.19    dyoung 			return EINVAL;
   2028      1.19    dyoung 		wk = &ic->ic_nw_keys[kid];
   2029  1.48.4.1     skrll 		/*
   2030  1.48.4.1     skrll 		 * Global slots start off w/o any assigned key index.
   2031  1.48.4.1     skrll 		 * Force one here for consistency with IEEE80211_IOC_WEPKEY.
   2032  1.48.4.1     skrll 		 */
   2033  1.48.4.1     skrll 		if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
   2034  1.48.4.1     skrll 			wk->wk_keyix = kid;
   2035      1.19    dyoung 		ni = NULL;
   2036      1.19    dyoung 	}
   2037      1.19    dyoung 	error = 0;
   2038      1.19    dyoung 	ieee80211_key_update_begin(ic);
   2039      1.19    dyoung 	if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
   2040      1.19    dyoung 		wk->wk_keylen = ik.ik_keylen;
   2041      1.19    dyoung 		/* NB: MIC presence is implied by cipher type */
   2042      1.19    dyoung 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
   2043      1.19    dyoung 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
   2044      1.19    dyoung 		wk->wk_keyrsc = ik.ik_keyrsc;
   2045      1.19    dyoung 		wk->wk_keytsc = 0;			/* new key, reset */
   2046      1.19    dyoung 		memset(wk->wk_key, 0, sizeof(wk->wk_key));
   2047      1.19    dyoung 		memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
   2048      1.19    dyoung 		if (!ieee80211_crypto_setkey(ic, wk,
   2049      1.19    dyoung 		    ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
   2050      1.19    dyoung 			error = EIO;
   2051      1.19    dyoung 		else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
   2052      1.19    dyoung 			ic->ic_def_txkey = kid;
   2053      1.19    dyoung 	} else
   2054      1.19    dyoung 		error = ENXIO;
   2055      1.19    dyoung 	ieee80211_key_update_end(ic);
   2056      1.19    dyoung 	if (ni != NULL)
   2057      1.19    dyoung 		ieee80211_free_node(ni);
   2058      1.19    dyoung 	return error;
   2059      1.19    dyoung }
   2060      1.19    dyoung 
   2061      1.19    dyoung static int
   2062      1.19    dyoung ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
   2063      1.19    dyoung {
   2064      1.19    dyoung 	struct ieee80211req_del_key dk;
   2065      1.19    dyoung 	int kid, error;
   2066      1.19    dyoung 
   2067      1.19    dyoung 	if (ireq->i_len != sizeof(dk))
   2068      1.19    dyoung 		return EINVAL;
   2069      1.19    dyoung 	error = copyin(ireq->i_data, &dk, sizeof(dk));
   2070      1.19    dyoung 	if (error)
   2071      1.19    dyoung 		return error;
   2072      1.19    dyoung 	kid = dk.idk_keyix;
   2073  1.48.4.1     skrll 	/* XXX uint8_t -> uint16_t */
   2074  1.48.4.1     skrll 	if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
   2075      1.19    dyoung 		struct ieee80211_node *ni;
   2076      1.19    dyoung 
   2077      1.21    dyoung 		if (ic->ic_opmode == IEEE80211_M_STA) {
   2078      1.21    dyoung 			ni = ieee80211_ref_node(ic->ic_bss);
   2079      1.21    dyoung 			if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
   2080      1.21    dyoung 				ieee80211_free_node(ni);
   2081      1.21    dyoung 				return EADDRNOTAVAIL;
   2082      1.21    dyoung 			}
   2083      1.21    dyoung 		} else {
   2084      1.21    dyoung 			ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
   2085      1.21    dyoung 			if (ni == NULL)
   2086      1.21    dyoung 				return ENOENT;
   2087      1.21    dyoung 		}
   2088      1.19    dyoung 		/* XXX error return */
   2089      1.26     skrll 		ieee80211_node_delucastkey(ni);
   2090      1.19    dyoung 		ieee80211_free_node(ni);
   2091      1.19    dyoung 	} else {
   2092      1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
   2093      1.19    dyoung 			return EINVAL;
   2094      1.19    dyoung 		/* XXX error return */
   2095      1.19    dyoung 		ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
   2096      1.19    dyoung 	}
   2097      1.19    dyoung 	return 0;
   2098      1.19    dyoung }
   2099      1.19    dyoung 
   2100      1.20    dyoung #ifndef IEEE80211_NO_HOSTAP
   2101      1.19    dyoung static void
   2102      1.19    dyoung domlme(void *arg, struct ieee80211_node *ni)
   2103      1.19    dyoung {
   2104      1.19    dyoung 	struct ieee80211com *ic = ni->ni_ic;
   2105      1.19    dyoung 	struct ieee80211req_mlme *mlme = arg;
   2106      1.19    dyoung 
   2107      1.19    dyoung 	if (ni->ni_associd != 0) {
   2108      1.19    dyoung 		IEEE80211_SEND_MGMT(ic, ni,
   2109      1.19    dyoung 			mlme->im_op == IEEE80211_MLME_DEAUTH ?
   2110      1.19    dyoung 				IEEE80211_FC0_SUBTYPE_DEAUTH :
   2111      1.19    dyoung 				IEEE80211_FC0_SUBTYPE_DISASSOC,
   2112      1.19    dyoung 			mlme->im_reason);
   2113      1.19    dyoung 	}
   2114      1.19    dyoung 	ieee80211_node_leave(ic, ni);
   2115      1.19    dyoung }
   2116      1.20    dyoung #endif /* !IEEE80211_NO_HOSTAP */
   2117      1.19    dyoung 
   2118  1.48.4.1     skrll struct scanlookup {
   2119  1.48.4.1     skrll 	const uint8_t *mac;
   2120  1.48.4.1     skrll 	int esslen;
   2121  1.48.4.1     skrll 	const uint8_t *essid;
   2122  1.48.4.1     skrll 	const struct ieee80211_scan_entry *se;
   2123  1.48.4.1     skrll };
   2124  1.48.4.1     skrll 
   2125  1.48.4.1     skrll /*
   2126  1.48.4.1     skrll  * Match mac address and any ssid.
   2127  1.48.4.1     skrll  */
   2128  1.48.4.1     skrll static void
   2129  1.48.4.1     skrll mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
   2130  1.48.4.1     skrll {
   2131  1.48.4.1     skrll 	struct scanlookup *look = arg;
   2132  1.48.4.1     skrll 
   2133  1.48.4.1     skrll 	if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
   2134  1.48.4.1     skrll 		return;
   2135  1.48.4.1     skrll 	if (look->esslen != 0) {
   2136  1.48.4.1     skrll 		if (se->se_ssid[1] != look->esslen)
   2137  1.48.4.1     skrll 			return;
   2138  1.48.4.1     skrll 		if (memcmp(look->essid, se->se_ssid+2, look->esslen))
   2139  1.48.4.1     skrll 			return;
   2140  1.48.4.1     skrll 	}
   2141  1.48.4.1     skrll 	look->se = se;
   2142  1.48.4.1     skrll }
   2143  1.48.4.1     skrll 
   2144      1.19    dyoung static int
   2145      1.19    dyoung ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
   2146      1.19    dyoung {
   2147      1.19    dyoung 	struct ieee80211req_mlme mlme;
   2148      1.19    dyoung 	struct ieee80211_node *ni;
   2149      1.19    dyoung 	int error;
   2150      1.19    dyoung 
   2151      1.19    dyoung 	if (ireq->i_len != sizeof(mlme))
   2152      1.19    dyoung 		return EINVAL;
   2153      1.19    dyoung 	error = copyin(ireq->i_data, &mlme, sizeof(mlme));
   2154      1.19    dyoung 	if (error)
   2155      1.19    dyoung 		return error;
   2156      1.19    dyoung 	switch (mlme.im_op) {
   2157      1.19    dyoung 	case IEEE80211_MLME_ASSOC:
   2158  1.48.4.1     skrll 		/* XXX ibss/ahdemo */
   2159  1.48.4.1     skrll 		if (ic->ic_opmode == IEEE80211_M_STA) {
   2160  1.48.4.1     skrll 			struct scanlookup lookup;
   2161      1.19    dyoung 
   2162  1.48.4.1     skrll 			lookup.se = NULL;
   2163  1.48.4.1     skrll 			lookup.mac = mlme.im_macaddr;
   2164  1.48.4.1     skrll 			/* XXX use revised api w/ explicit ssid */
   2165  1.48.4.1     skrll 			lookup.esslen = ic->ic_des_ssid[0].len;
   2166  1.48.4.1     skrll 			lookup.essid = ic->ic_des_ssid[0].ssid;
   2167  1.48.4.1     skrll 			ieee80211_scan_iterate(ic, mlmelookup, &lookup);
   2168  1.48.4.1     skrll 			if (lookup.se != NULL &&
   2169  1.48.4.1     skrll 			    ieee80211_sta_join(ic, lookup.se))
   2170  1.48.4.1     skrll 				return 0;
   2171      1.19    dyoung 		}
   2172  1.48.4.1     skrll 		return EINVAL;
   2173      1.19    dyoung 	case IEEE80211_MLME_DISASSOC:
   2174      1.19    dyoung 	case IEEE80211_MLME_DEAUTH:
   2175      1.19    dyoung 		switch (ic->ic_opmode) {
   2176      1.19    dyoung 		case IEEE80211_M_STA:
   2177      1.19    dyoung 			/* XXX not quite right */
   2178      1.19    dyoung 			ieee80211_new_state(ic, IEEE80211_S_INIT,
   2179      1.19    dyoung 				mlme.im_reason);
   2180      1.19    dyoung 			break;
   2181      1.19    dyoung 		case IEEE80211_M_HOSTAP:
   2182      1.20    dyoung #ifndef IEEE80211_NO_HOSTAP
   2183      1.19    dyoung 			/* NB: the broadcast address means do 'em all */
   2184      1.19    dyoung 			if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
   2185      1.19    dyoung 				if ((ni = ieee80211_find_node(&ic->ic_sta,
   2186      1.19    dyoung 						mlme.im_macaddr)) == NULL)
   2187      1.19    dyoung 					return EINVAL;
   2188      1.19    dyoung 				domlme(&mlme, ni);
   2189      1.19    dyoung 				ieee80211_free_node(ni);
   2190       1.1    dyoung 			} else {
   2191      1.19    dyoung 				ieee80211_iterate_nodes(&ic->ic_sta,
   2192      1.19    dyoung 						domlme, &mlme);
   2193       1.1    dyoung 			}
   2194      1.20    dyoung #endif /* !IEEE80211_NO_HOSTAP */
   2195       1.1    dyoung 			break;
   2196      1.19    dyoung 		default:
   2197      1.19    dyoung 			return EINVAL;
   2198      1.19    dyoung 		}
   2199      1.19    dyoung 		break;
   2200      1.19    dyoung 	case IEEE80211_MLME_AUTHORIZE:
   2201      1.19    dyoung 	case IEEE80211_MLME_UNAUTHORIZE:
   2202      1.19    dyoung 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
   2203      1.19    dyoung 			return EINVAL;
   2204      1.19    dyoung 		ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
   2205      1.19    dyoung 		if (ni == NULL)
   2206      1.19    dyoung 			return EINVAL;
   2207      1.19    dyoung 		if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
   2208      1.26     skrll 			ieee80211_node_authorize(ni);
   2209      1.19    dyoung 		else
   2210      1.26     skrll 			ieee80211_node_unauthorize(ni);
   2211      1.19    dyoung 		ieee80211_free_node(ni);
   2212      1.19    dyoung 		break;
   2213      1.19    dyoung 	default:
   2214      1.19    dyoung 		return EINVAL;
   2215      1.19    dyoung 	}
   2216      1.19    dyoung 	return 0;
   2217      1.19    dyoung }
   2218      1.19    dyoung 
   2219      1.19    dyoung static int
   2220      1.19    dyoung ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
   2221      1.19    dyoung {
   2222  1.48.4.1     skrll 	uint8_t mac[IEEE80211_ADDR_LEN];
   2223      1.19    dyoung 	const struct ieee80211_aclator *acl = ic->ic_acl;
   2224      1.19    dyoung 	int error;
   2225      1.19    dyoung 
   2226      1.19    dyoung 	if (ireq->i_len != sizeof(mac))
   2227      1.19    dyoung 		return EINVAL;
   2228      1.19    dyoung 	error = copyin(ireq->i_data, mac, ireq->i_len);
   2229      1.19    dyoung 	if (error)
   2230      1.19    dyoung 		return error;
   2231      1.19    dyoung 	if (acl == NULL) {
   2232      1.19    dyoung 		acl = ieee80211_aclator_get("mac");
   2233      1.19    dyoung 		if (acl == NULL || !acl->iac_attach(ic))
   2234      1.19    dyoung 			return EINVAL;
   2235      1.19    dyoung 		ic->ic_acl = acl;
   2236      1.19    dyoung 	}
   2237      1.19    dyoung 	if (ireq->i_type == IEEE80211_IOC_ADDMAC)
   2238      1.19    dyoung 		acl->iac_add(ic, mac);
   2239      1.19    dyoung 	else
   2240      1.19    dyoung 		acl->iac_remove(ic, mac);
   2241      1.19    dyoung 	return 0;
   2242      1.19    dyoung }
   2243      1.19    dyoung 
   2244      1.19    dyoung static int
   2245      1.26     skrll ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
   2246      1.19    dyoung {
   2247      1.19    dyoung 	const struct ieee80211_aclator *acl = ic->ic_acl;
   2248      1.19    dyoung 
   2249      1.19    dyoung 	switch (ireq->i_val) {
   2250      1.19    dyoung 	case IEEE80211_MACCMD_POLICY_OPEN:
   2251      1.19    dyoung 	case IEEE80211_MACCMD_POLICY_ALLOW:
   2252      1.19    dyoung 	case IEEE80211_MACCMD_POLICY_DENY:
   2253      1.19    dyoung 		if (acl == NULL) {
   2254      1.19    dyoung 			acl = ieee80211_aclator_get("mac");
   2255      1.19    dyoung 			if (acl == NULL || !acl->iac_attach(ic))
   2256      1.19    dyoung 				return EINVAL;
   2257      1.19    dyoung 			ic->ic_acl = acl;
   2258      1.19    dyoung 		}
   2259      1.19    dyoung 		acl->iac_setpolicy(ic, ireq->i_val);
   2260      1.19    dyoung 		break;
   2261      1.19    dyoung 	case IEEE80211_MACCMD_FLUSH:
   2262      1.19    dyoung 		if (acl != NULL)
   2263      1.19    dyoung 			acl->iac_flush(ic);
   2264      1.19    dyoung 		/* NB: silently ignore when not in use */
   2265      1.19    dyoung 		break;
   2266      1.19    dyoung 	case IEEE80211_MACCMD_DETACH:
   2267      1.19    dyoung 		if (acl != NULL) {
   2268      1.19    dyoung 			ic->ic_acl = NULL;
   2269      1.19    dyoung 			acl->iac_detach(ic);
   2270      1.19    dyoung 		}
   2271      1.19    dyoung 		break;
   2272      1.19    dyoung 	default:
   2273      1.26     skrll 		if (acl == NULL)
   2274      1.26     skrll 			return EINVAL;
   2275      1.26     skrll 		else
   2276      1.26     skrll 			return acl->iac_setioctl(ic, ireq);
   2277      1.19    dyoung 	}
   2278      1.19    dyoung 	return 0;
   2279      1.19    dyoung }
   2280      1.19    dyoung 
   2281      1.19    dyoung static int
   2282      1.19    dyoung ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
   2283      1.19    dyoung {
   2284      1.19    dyoung 	struct ieee80211req_chanlist list;
   2285      1.33  christos 	u_int8_t chanlist[IEEE80211_CHAN_BYTES];
   2286  1.48.4.1     skrll 	int i, j, nchan, error;
   2287      1.19    dyoung 
   2288      1.19    dyoung 	if (ireq->i_len != sizeof(list))
   2289      1.19    dyoung 		return EINVAL;
   2290      1.19    dyoung 	error = copyin(ireq->i_data, &list, sizeof(list));
   2291      1.19    dyoung 	if (error)
   2292      1.19    dyoung 		return error;
   2293      1.19    dyoung 	memset(chanlist, 0, sizeof(chanlist));
   2294      1.19    dyoung 	/*
   2295      1.19    dyoung 	 * Since channel 0 is not available for DS, channel 1
   2296      1.19    dyoung 	 * is assigned to LSB on WaveLAN.
   2297      1.19    dyoung 	 */
   2298      1.19    dyoung 	if (ic->ic_phytype == IEEE80211_T_DS)
   2299      1.19    dyoung 		i = 1;
   2300      1.19    dyoung 	else
   2301      1.19    dyoung 		i = 0;
   2302  1.48.4.1     skrll 	nchan = 0;
   2303      1.19    dyoung 	for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
   2304      1.19    dyoung 		/*
   2305      1.19    dyoung 		 * NB: silently discard unavailable channels so users
   2306      1.19    dyoung 		 *     can specify 1-255 to get all available channels.
   2307      1.19    dyoung 		 */
   2308  1.48.4.1     skrll 		if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) {
   2309      1.19    dyoung 			setbit(chanlist, i);
   2310  1.48.4.1     skrll 			nchan++;
   2311  1.48.4.1     skrll 		}
   2312      1.19    dyoung 	}
   2313  1.48.4.1     skrll 	if (nchan == 0)
   2314  1.48.4.1     skrll 		return EINVAL;
   2315  1.48.4.1     skrll 	if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&	/* XXX */
   2316  1.48.4.1     skrll 	    isclr(chanlist, ic->ic_bsschan->ic_ieee))
   2317  1.48.4.1     skrll 		ic->ic_bsschan = IEEE80211_CHAN_ANYC;
   2318      1.19    dyoung 	memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
   2319  1.48.4.1     skrll 	return IS_UP_AUTO(ic) ? ieee80211_init(ic, RESCAN) : 0;
   2320  1.48.4.1     skrll }
   2321  1.48.4.1     skrll 
   2322  1.48.4.1     skrll static int
   2323  1.48.4.1     skrll ieee80211_ioctl_setstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
   2324  1.48.4.1     skrll {
   2325  1.48.4.1     skrll 	struct ieee80211_node *ni;
   2326  1.48.4.1     skrll 	uint8_t macaddr[IEEE80211_ADDR_LEN];
   2327  1.48.4.1     skrll 	int error;
   2328  1.48.4.1     skrll 
   2329  1.48.4.1     skrll 	/*
   2330  1.48.4.1     skrll 	 * NB: we could copyin ieee80211req_sta_stats so apps
   2331  1.48.4.1     skrll 	 *     could make selective changes but that's overkill;
   2332  1.48.4.1     skrll 	 *     just clear all stats for now.
   2333  1.48.4.1     skrll 	 */
   2334  1.48.4.1     skrll 	if (ireq->i_len < IEEE80211_ADDR_LEN)
   2335  1.48.4.1     skrll 		return EINVAL;
   2336  1.48.4.1     skrll 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
   2337  1.48.4.1     skrll 	if (error != 0)
   2338  1.48.4.1     skrll 		return error;
   2339  1.48.4.1     skrll 	ni = ieee80211_find_node(&ic->ic_sta, macaddr);
   2340  1.48.4.1     skrll 	if (ni == NULL)
   2341  1.48.4.1     skrll 		return EINVAL;		/* XXX */
   2342  1.48.4.1     skrll 	memset(&ni->ni_stats, 0, sizeof(ni->ni_stats));
   2343  1.48.4.1     skrll 	ieee80211_free_node(ni);
   2344  1.48.4.1     skrll 	return 0;
   2345      1.19    dyoung }
   2346      1.19    dyoung 
   2347      1.19    dyoung static int
   2348      1.19    dyoung ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
   2349      1.19    dyoung {
   2350      1.19    dyoung 	struct ieee80211_node *ni;
   2351      1.19    dyoung 	struct ieee80211req_sta_txpow txpow;
   2352      1.19    dyoung 	int error;
   2353      1.19    dyoung 
   2354      1.19    dyoung 	if (ireq->i_len != sizeof(txpow))
   2355      1.19    dyoung 		return EINVAL;
   2356      1.19    dyoung 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
   2357      1.19    dyoung 	if (error != 0)
   2358      1.19    dyoung 		return error;
   2359      1.19    dyoung 	ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
   2360      1.19    dyoung 	if (ni == NULL)
   2361      1.19    dyoung 		return EINVAL;		/* XXX */
   2362      1.19    dyoung 	ni->ni_txpower = txpow.it_txpow;
   2363      1.19    dyoung 	ieee80211_free_node(ni);
   2364      1.19    dyoung 	return error;
   2365      1.19    dyoung }
   2366      1.19    dyoung 
   2367      1.19    dyoung static int
   2368      1.19    dyoung ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
   2369      1.19    dyoung {
   2370      1.19    dyoung 	struct ieee80211_wme_state *wme = &ic->ic_wme;
   2371      1.19    dyoung 	struct wmeParams *wmep, *chanp;
   2372      1.19    dyoung 	int isbss, ac;
   2373      1.19    dyoung 
   2374      1.19    dyoung 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
   2375      1.19    dyoung 		return EINVAL;
   2376      1.19    dyoung 
   2377      1.19    dyoung 	isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
   2378      1.19    dyoung 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
   2379      1.19    dyoung 	if (ac >= WME_NUM_AC)
   2380      1.19    dyoung 		ac = WME_AC_BE;
   2381      1.19    dyoung 	if (isbss) {
   2382      1.19    dyoung 		chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
   2383      1.19    dyoung 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
   2384      1.19    dyoung 	} else {
   2385      1.19    dyoung 		chanp = &wme->wme_chanParams.cap_wmeParams[ac];
   2386      1.19    dyoung 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
   2387      1.19    dyoung 	}
   2388      1.19    dyoung 	switch (ireq->i_type) {
   2389      1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   2390      1.19    dyoung 		if (isbss) {
   2391      1.19    dyoung 			wmep->wmep_logcwmin = ireq->i_val;
   2392      1.19    dyoung 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
   2393      1.19    dyoung 				chanp->wmep_logcwmin = ireq->i_val;
   2394      1.19    dyoung 		} else {
   2395      1.19    dyoung 			wmep->wmep_logcwmin = chanp->wmep_logcwmin =
   2396      1.19    dyoung 				ireq->i_val;
   2397      1.19    dyoung 		}
   2398      1.19    dyoung 		break;
   2399      1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   2400      1.19    dyoung 		if (isbss) {
   2401      1.19    dyoung 			wmep->wmep_logcwmax = ireq->i_val;
   2402      1.19    dyoung 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
   2403      1.19    dyoung 				chanp->wmep_logcwmax = ireq->i_val;
   2404      1.19    dyoung 		} else {
   2405      1.19    dyoung 			wmep->wmep_logcwmax = chanp->wmep_logcwmax =
   2406      1.19    dyoung 				ireq->i_val;
   2407      1.19    dyoung 		}
   2408      1.19    dyoung 		break;
   2409      1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   2410      1.19    dyoung 		if (isbss) {
   2411      1.19    dyoung 			wmep->wmep_aifsn = ireq->i_val;
   2412      1.19    dyoung 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
   2413      1.19    dyoung 				chanp->wmep_aifsn = ireq->i_val;
   2414      1.19    dyoung 		} else {
   2415      1.19    dyoung 			wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
   2416      1.19    dyoung 		}
   2417      1.19    dyoung 		break;
   2418      1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   2419      1.19    dyoung 		if (isbss) {
   2420      1.19    dyoung 			wmep->wmep_txopLimit = ireq->i_val;
   2421      1.19    dyoung 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
   2422      1.19    dyoung 				chanp->wmep_txopLimit = ireq->i_val;
   2423      1.19    dyoung 		} else {
   2424      1.19    dyoung 			wmep->wmep_txopLimit = chanp->wmep_txopLimit =
   2425      1.19    dyoung 				ireq->i_val;
   2426      1.19    dyoung 		}
   2427      1.19    dyoung 		break;
   2428      1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   2429      1.19    dyoung 		wmep->wmep_acm = ireq->i_val;
   2430      1.19    dyoung 		if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
   2431      1.19    dyoung 			chanp->wmep_acm = ireq->i_val;
   2432      1.19    dyoung 		break;
   2433      1.19    dyoung 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
   2434      1.19    dyoung 		wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
   2435      1.19    dyoung 			(ireq->i_val) == 0;
   2436      1.19    dyoung 		break;
   2437      1.19    dyoung 	}
   2438      1.19    dyoung 	ieee80211_wme_updateparams(ic);
   2439      1.19    dyoung 	return 0;
   2440      1.19    dyoung }
   2441      1.19    dyoung 
   2442      1.19    dyoung static int
   2443      1.19    dyoung cipher2cap(int cipher)
   2444      1.19    dyoung {
   2445      1.19    dyoung 	switch (cipher) {
   2446      1.19    dyoung 	case IEEE80211_CIPHER_WEP:	return IEEE80211_C_WEP;
   2447      1.19    dyoung 	case IEEE80211_CIPHER_AES_OCB:	return IEEE80211_C_AES;
   2448      1.19    dyoung 	case IEEE80211_CIPHER_AES_CCM:	return IEEE80211_C_AES_CCM;
   2449      1.19    dyoung 	case IEEE80211_CIPHER_CKIP:	return IEEE80211_C_CKIP;
   2450      1.19    dyoung 	case IEEE80211_CIPHER_TKIP:	return IEEE80211_C_TKIP;
   2451      1.19    dyoung 	}
   2452      1.19    dyoung 	return 0;
   2453      1.19    dyoung }
   2454      1.19    dyoung 
   2455  1.48.4.1     skrll #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   2456      1.19    dyoung static int
   2457  1.48.4.1     skrll find11gchannel(struct ieee80211com *ic, int start, int freq)
   2458      1.19    dyoung {
   2459  1.48.4.1     skrll 	const struct ieee80211_channel *c;
   2460  1.48.4.1     skrll 	int i;
   2461  1.48.4.1     skrll 
   2462  1.48.4.1     skrll 	for (i = start+1; i < ic->ic_nchans; i++) {
   2463  1.48.4.1     skrll 		c = &ic->ic_channels[i];
   2464  1.48.4.1     skrll 		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
   2465  1.48.4.1     skrll 			return 1;
   2466  1.48.4.1     skrll 	}
   2467  1.48.4.1     skrll 	/* NB: should not be needed but in case things are mis-sorted */
   2468  1.48.4.1     skrll 	for (i = 0; i < start; i++) {
   2469  1.48.4.1     skrll 		c = &ic->ic_channels[i];
   2470  1.48.4.1     skrll 		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
   2471  1.48.4.1     skrll 			return 1;
   2472  1.48.4.1     skrll 	}
   2473  1.48.4.1     skrll 	return 0;
   2474  1.48.4.1     skrll }
   2475  1.48.4.1     skrll 
   2476  1.48.4.1     skrll static struct ieee80211_channel *
   2477  1.48.4.1     skrll findchannel(struct ieee80211com *ic, int ieee, int mode)
   2478  1.48.4.1     skrll {
   2479  1.48.4.1     skrll 	static const u_int chanflags[IEEE80211_MODE_MAX] = {
   2480  1.48.4.1     skrll 		0,			/* IEEE80211_MODE_AUTO */
   2481  1.48.4.1     skrll 		IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
   2482  1.48.4.1     skrll 		IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
   2483  1.48.4.1     skrll 		IEEE80211_CHAN_G,	/* IEEE80211_MODE_11G */
   2484  1.48.4.1     skrll 		IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
   2485  1.48.4.1     skrll 		IEEE80211_CHAN_108A,	/* IEEE80211_MODE_TURBO_A */
   2486  1.48.4.1     skrll 		IEEE80211_CHAN_108G,	/* IEEE80211_MODE_TURBO_G */
   2487  1.48.4.1     skrll 		IEEE80211_CHAN_STURBO,	/* IEEE80211_MODE_STURBO_A */
   2488  1.48.4.1     skrll 		/* NB: handled specially below */
   2489  1.48.4.1     skrll 		IEEE80211_CHAN_A,	/* IEEE80211_MODE_11NA */
   2490  1.48.4.1     skrll 		IEEE80211_CHAN_G,	/* IEEE80211_MODE_11NG */
   2491  1.48.4.1     skrll 	};
   2492  1.48.4.1     skrll 	u_int modeflags;
   2493  1.48.4.1     skrll 	int i;
   2494  1.48.4.1     skrll 
   2495  1.48.4.1     skrll 	IASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
   2496  1.48.4.1     skrll 	modeflags = chanflags[mode];
   2497  1.48.4.1     skrll 	IASSERT(modeflags != 0 || mode == IEEE80211_MODE_AUTO,
   2498  1.48.4.1     skrll 	    ("no chanflags for mode %u", mode));
   2499  1.48.4.1     skrll 	for (i = 0; i < ic->ic_nchans; i++) {
   2500  1.48.4.1     skrll 		struct ieee80211_channel *c = &ic->ic_channels[i];
   2501  1.48.4.1     skrll 
   2502  1.48.4.1     skrll 		if (c->ic_ieee != ieee)
   2503  1.48.4.1     skrll 			continue;
   2504  1.48.4.1     skrll 		if (mode == IEEE80211_MODE_AUTO) {
   2505  1.48.4.1     skrll 			/* ignore turbo channels for autoselect */
   2506  1.48.4.1     skrll 			if (IEEE80211_IS_CHAN_TURBO(c))
   2507  1.48.4.1     skrll 				continue;
   2508  1.48.4.1     skrll 			/*
   2509  1.48.4.1     skrll 			 * XXX special-case 11b/g channels so we
   2510  1.48.4.1     skrll 			 *     always select the g channel if both
   2511  1.48.4.1     skrll 			 *     are present.
   2512  1.48.4.1     skrll 			 * XXX prefer HT to non-HT?
   2513  1.48.4.1     skrll 			 */
   2514  1.48.4.1     skrll 			if (!IEEE80211_IS_CHAN_B(c) ||
   2515  1.48.4.1     skrll 			    !find11gchannel(ic, i, c->ic_freq))
   2516  1.48.4.1     skrll 				return c;
   2517  1.48.4.1     skrll 		} else {
   2518  1.48.4.1     skrll 			/* must check HT specially */
   2519  1.48.4.1     skrll 			if ((mode == IEEE80211_MODE_11NA ||
   2520  1.48.4.1     skrll 			    mode == IEEE80211_MODE_11NG) &&
   2521  1.48.4.1     skrll 			    !IEEE80211_IS_CHAN_HT(c))
   2522  1.48.4.1     skrll 				continue;
   2523  1.48.4.1     skrll 			if ((c->ic_flags & modeflags) == modeflags)
   2524  1.48.4.1     skrll 				return c;
   2525  1.48.4.1     skrll 		}
   2526  1.48.4.1     skrll 	}
   2527  1.48.4.1     skrll 	return NULL;
   2528  1.48.4.1     skrll }
   2529  1.48.4.1     skrll #endif /*__FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   2530  1.48.4.1     skrll 
   2531  1.48.4.1     skrll /*
   2532  1.48.4.1     skrll  * Check the specified against any desired mode (aka netband).
   2533  1.48.4.1     skrll  * This is only used (presently) when operating in hostap mode
   2534  1.48.4.1     skrll  * to enforce consistency.
   2535  1.48.4.1     skrll  */
   2536  1.48.4.1     skrll static int
   2537  1.48.4.1     skrll check_mode_consistency(const struct ieee80211_channel *c, int mode)
   2538  1.48.4.1     skrll {
   2539  1.48.4.1     skrll 	IASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
   2540  1.48.4.1     skrll 
   2541  1.48.4.1     skrll 	switch (mode) {
   2542  1.48.4.1     skrll 	case IEEE80211_MODE_11B:
   2543  1.48.4.1     skrll 		return (IEEE80211_IS_CHAN_B(c));
   2544  1.48.4.1     skrll 	case IEEE80211_MODE_11G:
   2545  1.48.4.1     skrll 		return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
   2546  1.48.4.1     skrll 	case IEEE80211_MODE_11A:
   2547  1.48.4.1     skrll 		return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
   2548  1.48.4.1     skrll 	case IEEE80211_MODE_STURBO_A:
   2549  1.48.4.1     skrll 		return (IEEE80211_IS_CHAN_STURBO(c));
   2550  1.48.4.1     skrll 	case IEEE80211_MODE_11NA:
   2551  1.48.4.1     skrll 		return (IEEE80211_IS_CHAN_HTA(c));
   2552  1.48.4.1     skrll 	case IEEE80211_MODE_11NG:
   2553  1.48.4.1     skrll 		return (IEEE80211_IS_CHAN_HTG(c));
   2554  1.48.4.1     skrll 	}
   2555  1.48.4.1     skrll 	return 1;
   2556  1.48.4.1     skrll 
   2557  1.48.4.1     skrll }
   2558  1.48.4.1     skrll 
   2559  1.48.4.1     skrll /*
   2560  1.48.4.1     skrll  * Common code to set the current channel.  If the device
   2561  1.48.4.1     skrll  * is up and running this may result in an immediate channel
   2562  1.48.4.1     skrll  * change or a kick of the state machine.
   2563  1.48.4.1     skrll  */
   2564  1.48.4.1     skrll static int
   2565  1.48.4.1     skrll setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
   2566  1.48.4.1     skrll {
   2567  1.48.4.1     skrll 	int error;
   2568  1.48.4.1     skrll 
   2569  1.48.4.1     skrll 	if (c != IEEE80211_CHAN_ANYC) {
   2570  1.48.4.1     skrll 		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
   2571  1.48.4.1     skrll 		    !check_mode_consistency(c, ic->ic_des_mode))
   2572  1.48.4.1     skrll 			return EINVAL;
   2573  1.48.4.1     skrll 		if (ic->ic_state == IEEE80211_S_RUN && c == ic->ic_curchan)
   2574  1.48.4.1     skrll 			return 0;	/* NB: nothing to do */
   2575  1.48.4.1     skrll 	}
   2576  1.48.4.1     skrll 	ic->ic_des_chan = c;
   2577  1.48.4.1     skrll 
   2578  1.48.4.1     skrll 	error = 0;
   2579  1.48.4.1     skrll 	if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
   2580  1.48.4.1     skrll 	    ic->ic_opmode == IEEE80211_M_WDS) &&
   2581  1.48.4.1     skrll 	    ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
   2582  1.48.4.1     skrll 		/*
   2583  1.48.4.1     skrll 		 * Monitor and wds modes can switch directly.
   2584  1.48.4.1     skrll 		 */
   2585  1.48.4.1     skrll 		ic->ic_curchan = ic->ic_des_chan;
   2586  1.48.4.1     skrll 		if (ic->ic_state == IEEE80211_S_RUN)
   2587  1.48.4.1     skrll 			ic->ic_set_channel(ic);
   2588  1.48.4.1     skrll 	} else {
   2589  1.48.4.1     skrll 		/*
   2590  1.48.4.1     skrll 		 * Need to go through the state machine in case we
   2591  1.48.4.1     skrll 		 * need to reassociate or the like.  The state machine
   2592  1.48.4.1     skrll 		 * will pickup the desired channel and avoid scanning.
   2593  1.48.4.1     skrll 		 */
   2594  1.48.4.1     skrll 		if (IS_UP_AUTO(ic))
   2595  1.48.4.1     skrll 			error = ieee80211_init(ic, RESCAN);
   2596  1.48.4.1     skrll 		else if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
   2597  1.48.4.1     skrll 			/*
   2598  1.48.4.1     skrll 			 * When not up+running and a real channel has
   2599  1.48.4.1     skrll 			 * been specified fix the current channel so
   2600  1.48.4.1     skrll 			 * there is immediate feedback; e.g. via ifconfig.
   2601  1.48.4.1     skrll 			 */
   2602  1.48.4.1     skrll 			ic->ic_curchan = ic->ic_des_chan;
   2603  1.48.4.1     skrll 		}
   2604  1.48.4.1     skrll 	}
   2605  1.48.4.1     skrll 	return error;
   2606  1.48.4.1     skrll }
   2607  1.48.4.1     skrll 
   2608      1.30    dyoung #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   2609  1.48.4.1     skrll /*
   2610  1.48.4.1     skrll  * Old api for setting the current channel; this is
   2611  1.48.4.1     skrll  * deprecated because channel numbers are ambiguous.
   2612  1.48.4.1     skrll  */
   2613  1.48.4.1     skrll static int
   2614  1.48.4.1     skrll ieee80211_ioctl_setchannel(struct ieee80211com *ic,
   2615  1.48.4.1     skrll 	const struct ieee80211req *ireq)
   2616  1.48.4.1     skrll {
   2617  1.48.4.1     skrll 	struct ieee80211_channel *c;
   2618  1.48.4.1     skrll 
   2619  1.48.4.1     skrll 	/* XXX 0xffff overflows 16-bit signed */
   2620  1.48.4.1     skrll 	if (ireq->i_val == 0 ||
   2621  1.48.4.1     skrll 	    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
   2622  1.48.4.1     skrll 		c = IEEE80211_CHAN_ANYC;
   2623  1.48.4.1     skrll 	} else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX) {
   2624  1.48.4.1     skrll 		return EINVAL;
   2625  1.48.4.1     skrll 	} else {
   2626  1.48.4.1     skrll 		struct ieee80211_channel *c2;
   2627  1.48.4.1     skrll 
   2628  1.48.4.1     skrll 		c = findchannel(ic, ireq->i_val, ic->ic_des_mode);
   2629  1.48.4.1     skrll 		if (c == NULL) {
   2630  1.48.4.1     skrll 			c = findchannel(ic, ireq->i_val,
   2631  1.48.4.1     skrll 				IEEE80211_MODE_AUTO);
   2632  1.48.4.1     skrll 			if (c == NULL)
   2633  1.48.4.1     skrll 				return EINVAL;
   2634  1.48.4.1     skrll 		}
   2635  1.48.4.1     skrll 		/*
   2636  1.48.4.1     skrll 		 * Fine tune channel selection based on desired mode:
   2637  1.48.4.1     skrll 		 *   if 11b is requested, find the 11b version of any
   2638  1.48.4.1     skrll 		 *      11g channel returned,
   2639  1.48.4.1     skrll 		 *   if static turbo, find the turbo version of any
   2640  1.48.4.1     skrll 		 *	11a channel return,
   2641  1.48.4.1     skrll 		 *   if 11na is requested, find the ht version of any
   2642  1.48.4.1     skrll 		 *      11a channel returned,
   2643  1.48.4.1     skrll 		 *   if 11ng is requested, find the ht version of any
   2644  1.48.4.1     skrll 		 *      11g channel returned,
   2645  1.48.4.1     skrll 		 *   otherwise we should be ok with what we've got.
   2646  1.48.4.1     skrll 		 */
   2647  1.48.4.1     skrll 		switch (ic->ic_des_mode) {
   2648  1.48.4.1     skrll 		case IEEE80211_MODE_11B:
   2649  1.48.4.1     skrll 			if (IEEE80211_IS_CHAN_ANYG(c)) {
   2650  1.48.4.1     skrll 				c2 = findchannel(ic, ireq->i_val,
   2651  1.48.4.1     skrll 					IEEE80211_MODE_11B);
   2652  1.48.4.1     skrll 				/* NB: should not happen, =>'s 11g w/o 11b */
   2653  1.48.4.1     skrll 				if (c2 != NULL)
   2654  1.48.4.1     skrll 					c = c2;
   2655  1.48.4.1     skrll 			}
   2656  1.48.4.1     skrll 			break;
   2657  1.48.4.1     skrll 		case IEEE80211_MODE_TURBO_A:
   2658  1.48.4.1     skrll 			if (IEEE80211_IS_CHAN_A(c)) {
   2659  1.48.4.1     skrll 				c2 = findchannel(ic, ireq->i_val,
   2660  1.48.4.1     skrll 					IEEE80211_MODE_TURBO_A);
   2661  1.48.4.1     skrll 				if (c2 != NULL)
   2662  1.48.4.1     skrll 					c = c2;
   2663  1.48.4.1     skrll 			}
   2664  1.48.4.1     skrll 			break;
   2665  1.48.4.1     skrll 		case IEEE80211_MODE_11NA:
   2666  1.48.4.1     skrll 			if (IEEE80211_IS_CHAN_A(c)) {
   2667  1.48.4.1     skrll 				c2 = findchannel(ic, ireq->i_val,
   2668  1.48.4.1     skrll 					IEEE80211_MODE_11NA);
   2669  1.48.4.1     skrll 				if (c2 != NULL)
   2670  1.48.4.1     skrll 					c = c2;
   2671  1.48.4.1     skrll 			}
   2672  1.48.4.1     skrll 			break;
   2673  1.48.4.1     skrll 		case IEEE80211_MODE_11NG:
   2674  1.48.4.1     skrll 			if (IEEE80211_IS_CHAN_ANYG(c)) {
   2675  1.48.4.1     skrll 				c2 = findchannel(ic, ireq->i_val,
   2676  1.48.4.1     skrll 					IEEE80211_MODE_11NG);
   2677  1.48.4.1     skrll 				if (c2 != NULL)
   2678  1.48.4.1     skrll 					c = c2;
   2679  1.48.4.1     skrll 			}
   2680  1.48.4.1     skrll 			break;
   2681  1.48.4.1     skrll 		default:		/* NB: no static turboG */
   2682  1.48.4.1     skrll 			break;
   2683  1.48.4.1     skrll 		}
   2684  1.48.4.1     skrll 	}
   2685  1.48.4.1     skrll 	return setcurchan(ic, c);
   2686  1.48.4.1     skrll }
   2687  1.48.4.1     skrll #endif /*__FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   2688  1.48.4.1     skrll 
   2689  1.48.4.1     skrll /*
   2690  1.48.4.1     skrll  * New/current api for setting the current channel; a complete
   2691  1.48.4.1     skrll  * channel description is provide so there is no ambiguity in
   2692  1.48.4.1     skrll  * identifying the channel.
   2693  1.48.4.1     skrll  */
   2694  1.48.4.1     skrll static int
   2695  1.48.4.1     skrll ieee80211_ioctl_setcurchan(struct ieee80211com *ic,
   2696  1.48.4.1     skrll 	const struct ieee80211req *ireq)
   2697  1.48.4.1     skrll {
   2698  1.48.4.1     skrll 	struct ieee80211_channel chan, *c;
   2699  1.48.4.1     skrll 	int error;
   2700  1.48.4.1     skrll 
   2701  1.48.4.1     skrll 	if (ireq->i_len != sizeof(chan))
   2702  1.48.4.1     skrll 		return EINVAL;
   2703  1.48.4.1     skrll 	error = copyin(ireq->i_data, &chan, sizeof(chan));
   2704  1.48.4.1     skrll 	if (error != 0)
   2705  1.48.4.1     skrll 		return error;
   2706  1.48.4.1     skrll 	/* XXX 0xffff overflows 16-bit signed */
   2707  1.48.4.1     skrll 	if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
   2708  1.48.4.1     skrll 		c = IEEE80211_CHAN_ANYC;
   2709  1.48.4.1     skrll 	} else {
   2710  1.48.4.1     skrll 		c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
   2711  1.48.4.1     skrll 		if (c == NULL)
   2712  1.48.4.1     skrll 			return EINVAL;
   2713  1.48.4.1     skrll 	}
   2714  1.48.4.1     skrll 	return setcurchan(ic, c);
   2715  1.48.4.1     skrll }
   2716  1.48.4.1     skrll 
   2717  1.48.4.1     skrll static int
   2718  1.48.4.1     skrll ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
   2719  1.48.4.1     skrll {
   2720  1.48.4.1     skrll #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   2721  1.48.4.1     skrll 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
   2722  1.48.4.1     skrll 	struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
   2723  1.48.4.1     skrll 	int error;
   2724  1.48.4.1     skrll 	const struct ieee80211_authenticator *auth;
   2725  1.48.4.1     skrll 	uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
   2726      1.19    dyoung 	char tmpssid[IEEE80211_NWID_LEN];
   2727  1.48.4.1     skrll 	uint8_t tmpbssid[IEEE80211_ADDR_LEN];
   2728      1.19    dyoung 	struct ieee80211_key *k;
   2729      1.23    dyoung 	u_int kid;
   2730      1.30    dyoung #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   2731      1.23    dyoung 	struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
   2732      1.23    dyoung 	int error;
   2733      1.23    dyoung 	const struct ieee80211_authenticator *auth;
   2734      1.19    dyoung 	int j, caps;
   2735      1.19    dyoung 
   2736      1.19    dyoung 	error = 0;
   2737      1.19    dyoung 	switch (ireq->i_type) {
   2738      1.30    dyoung #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   2739      1.19    dyoung 	case IEEE80211_IOC_SSID:
   2740      1.19    dyoung 		if (ireq->i_val != 0 ||
   2741      1.19    dyoung 		    ireq->i_len > IEEE80211_NWID_LEN)
   2742      1.19    dyoung 			return EINVAL;
   2743      1.19    dyoung 		error = copyin(ireq->i_data, tmpssid, ireq->i_len);
   2744      1.19    dyoung 		if (error)
   2745       1.1    dyoung 			break;
   2746  1.48.4.1     skrll 		memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
   2747  1.48.4.1     skrll 		ic->ic_des_ssid[0].len = ireq->i_len;
   2748  1.48.4.1     skrll 		memcpy(ic->ic_des_ssid[0].ssid, tmpssid, ireq->i_len);
   2749  1.48.4.1     skrll 		ic->ic_des_nssid = (ireq->i_len > 0);
   2750  1.48.4.1     skrll 		if (IS_UP_AUTO(ic))
   2751  1.48.4.1     skrll 			error = ieee80211_init(ic, RESCAN);
   2752      1.19    dyoung 		break;
   2753      1.30    dyoung #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   2754      1.19    dyoung 	case IEEE80211_IOC_WEP:
   2755      1.19    dyoung 		switch (ireq->i_val) {
   2756      1.19    dyoung 		case IEEE80211_WEP_OFF:
   2757      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
   2758      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
   2759       1.1    dyoung 			break;
   2760      1.19    dyoung 		case IEEE80211_WEP_ON:
   2761      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_PRIVACY;
   2762      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
   2763       1.1    dyoung 			break;
   2764      1.19    dyoung 		case IEEE80211_WEP_MIXED:
   2765      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_PRIVACY;
   2766      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
   2767       1.1    dyoung 			break;
   2768      1.19    dyoung 		}
   2769  1.48.4.1     skrll 		if (IS_UP_AUTO(ic))
   2770  1.48.4.1     skrll 			error = ieee80211_init(ic, RESCAN);
   2771      1.19    dyoung 		break;
   2772      1.30    dyoung #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   2773      1.19    dyoung 	case IEEE80211_IOC_WEPKEY:
   2774      1.19    dyoung 		kid = (u_int) ireq->i_val;
   2775      1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID)
   2776      1.19    dyoung 			return EINVAL;
   2777      1.19    dyoung 		k = &ic->ic_nw_keys[kid];
   2778      1.19    dyoung 		if (ireq->i_len == 0) {
   2779      1.19    dyoung 			/* zero-len =>'s delete any existing key */
   2780      1.19    dyoung 			(void) ieee80211_crypto_delkey(ic, k);
   2781       1.1    dyoung 			break;
   2782      1.19    dyoung 		}
   2783      1.19    dyoung 		if (ireq->i_len > sizeof(tmpkey))
   2784      1.19    dyoung 			return EINVAL;
   2785      1.19    dyoung 		memset(tmpkey, 0, sizeof(tmpkey));
   2786      1.19    dyoung 		error = copyin(ireq->i_data, tmpkey, ireq->i_len);
   2787      1.19    dyoung 		if (error)
   2788       1.1    dyoung 			break;
   2789      1.19    dyoung 		ieee80211_key_update_begin(ic);
   2790      1.19    dyoung 		k->wk_keyix = kid;	/* NB: force fixed key id */
   2791      1.19    dyoung 		if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
   2792      1.19    dyoung 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
   2793      1.19    dyoung 			k->wk_keylen = ireq->i_len;
   2794      1.19    dyoung 			memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
   2795      1.19    dyoung 			if  (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
   2796      1.19    dyoung 				error = EINVAL;
   2797      1.19    dyoung 		} else
   2798      1.19    dyoung 			error = EINVAL;
   2799      1.19    dyoung 		ieee80211_key_update_end(ic);
   2800      1.19    dyoung 		break;
   2801      1.19    dyoung 	case IEEE80211_IOC_WEPTXKEY:
   2802      1.19    dyoung 		kid = (u_int) ireq->i_val;
   2803      1.19    dyoung 		if (kid >= IEEE80211_WEP_NKID &&
   2804  1.48.4.1     skrll 		    (uint16_t) kid != IEEE80211_KEYIX_NONE)
   2805      1.19    dyoung 			return EINVAL;
   2806      1.19    dyoung 		ic->ic_def_txkey = kid;
   2807      1.19    dyoung 		break;
   2808      1.30    dyoung #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   2809      1.19    dyoung 	case IEEE80211_IOC_AUTHMODE:
   2810      1.19    dyoung 		switch (ireq->i_val) {
   2811      1.19    dyoung 		case IEEE80211_AUTH_WPA:
   2812      1.19    dyoung 		case IEEE80211_AUTH_8021X:	/* 802.1x */
   2813      1.19    dyoung 		case IEEE80211_AUTH_OPEN:	/* open */
   2814      1.19    dyoung 		case IEEE80211_AUTH_SHARED:	/* shared-key */
   2815      1.19    dyoung 		case IEEE80211_AUTH_AUTO:	/* auto */
   2816      1.19    dyoung 			auth = ieee80211_authenticator_get(ireq->i_val);
   2817      1.19    dyoung 			if (auth == NULL)
   2818      1.19    dyoung 				return EINVAL;
   2819       1.1    dyoung 			break;
   2820      1.19    dyoung 		default:
   2821      1.19    dyoung 			return EINVAL;
   2822      1.19    dyoung 		}
   2823      1.19    dyoung 		switch (ireq->i_val) {
   2824      1.19    dyoung 		case IEEE80211_AUTH_WPA:	/* WPA w/ 802.1x */
   2825      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_PRIVACY;
   2826      1.19    dyoung 			ireq->i_val = IEEE80211_AUTH_8021X;
   2827       1.1    dyoung 			break;
   2828      1.19    dyoung 		case IEEE80211_AUTH_OPEN:	/* open */
   2829      1.19    dyoung 			ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
   2830      1.10    dyoung 			break;
   2831      1.19    dyoung 		case IEEE80211_AUTH_SHARED:	/* shared-key */
   2832      1.19    dyoung 		case IEEE80211_AUTH_8021X:	/* 802.1x */
   2833      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_WPA;
   2834      1.19    dyoung 			/* both require a key so mark the PRIVACY capability */
   2835      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_PRIVACY;
   2836      1.10    dyoung 			break;
   2837      1.19    dyoung 		case IEEE80211_AUTH_AUTO:	/* auto */
   2838      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_WPA;
   2839      1.19    dyoung 			/* XXX PRIVACY handling? */
   2840      1.19    dyoung 			/* XXX what's the right way to do this? */
   2841      1.10    dyoung 			break;
   2842       1.1    dyoung 		}
   2843      1.19    dyoung 		/* NB: authenticator attach/detach happens on state change */
   2844      1.19    dyoung 		ic->ic_bss->ni_authmode = ireq->i_val;
   2845      1.19    dyoung 		/* XXX mixed/mode/usage? */
   2846      1.19    dyoung 		ic->ic_auth = auth;
   2847  1.48.4.1     skrll 		if (IS_UP_AUTO(ic))
   2848  1.48.4.1     skrll 			error = ieee80211_init(ic, RESCAN);
   2849       1.1    dyoung 		break;
   2850      1.30    dyoung #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   2851      1.19    dyoung 	case IEEE80211_IOC_CHANNEL:
   2852  1.48.4.1     skrll 		error = ieee80211_ioctl_setchannel(ic, ireq);
   2853      1.19    dyoung 		break;
   2854      1.19    dyoung 	case IEEE80211_IOC_POWERSAVE:
   2855      1.19    dyoung 		switch (ireq->i_val) {
   2856      1.19    dyoung 		case IEEE80211_POWERSAVE_OFF:
   2857      1.19    dyoung 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
   2858      1.19    dyoung 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
   2859      1.19    dyoung 				error = ENETRESET;
   2860      1.18     perry 			}
   2861       1.1    dyoung 			break;
   2862      1.19    dyoung 		case IEEE80211_POWERSAVE_ON:
   2863      1.19    dyoung 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
   2864       1.1    dyoung 				error = EINVAL;
   2865      1.19    dyoung 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
   2866      1.19    dyoung 				ic->ic_flags |= IEEE80211_F_PMGTON;
   2867      1.19    dyoung 				error = ENETRESET;
   2868       1.1    dyoung 			}
   2869       1.1    dyoung 			break;
   2870      1.19    dyoung 		default:
   2871      1.19    dyoung 			error = EINVAL;
   2872       1.1    dyoung 			break;
   2873      1.19    dyoung 		}
   2874  1.48.4.1     skrll 		if (error == ENETRESET) {
   2875  1.48.4.1     skrll 			/*
   2876  1.48.4.1     skrll 			 * Switching in+out of power save mode
   2877  1.48.4.1     skrll 			 * should not require a state change.
   2878  1.48.4.1     skrll 			 */
   2879  1.48.4.1     skrll 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   2880  1.48.4.1     skrll 		}
   2881      1.19    dyoung 		break;
   2882      1.19    dyoung 	case IEEE80211_IOC_POWERSAVESLEEP:
   2883      1.19    dyoung 		if (ireq->i_val < 0)
   2884      1.19    dyoung 			return EINVAL;
   2885      1.19    dyoung 		ic->ic_lintval = ireq->i_val;
   2886      1.19    dyoung 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   2887      1.19    dyoung 		break;
   2888      1.30    dyoung #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   2889      1.19    dyoung 	case IEEE80211_IOC_RTSTHRESHOLD:
   2890      1.26     skrll 		if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
   2891      1.26     skrll 		      ireq->i_val <= IEEE80211_RTS_MAX))
   2892      1.19    dyoung 			return EINVAL;
   2893      1.19    dyoung 		ic->ic_rtsthreshold = ireq->i_val;
   2894      1.19    dyoung 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   2895      1.19    dyoung 		break;
   2896      1.19    dyoung 	case IEEE80211_IOC_PROTMODE:
   2897      1.19    dyoung 		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
   2898      1.19    dyoung 			return EINVAL;
   2899      1.19    dyoung 		ic->ic_protmode = ireq->i_val;
   2900      1.19    dyoung 		/* NB: if not operating in 11g this can wait */
   2901  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   2902  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
   2903      1.19    dyoung 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   2904      1.19    dyoung 		break;
   2905      1.19    dyoung 	case IEEE80211_IOC_TXPOWER:
   2906      1.19    dyoung 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
   2907      1.19    dyoung 			return EINVAL;
   2908  1.48.4.1     skrll 		if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
   2909  1.48.4.1     skrll 		      ireq->i_val <= IEEE80211_TXPOWER_MAX))
   2910      1.19    dyoung 			return EINVAL;
   2911      1.19    dyoung 		ic->ic_txpowlimit = ireq->i_val;
   2912      1.19    dyoung 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   2913      1.19    dyoung 		break;
   2914      1.19    dyoung 	case IEEE80211_IOC_ROAMING:
   2915      1.19    dyoung 		if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
   2916      1.19    dyoung 		    ireq->i_val <= IEEE80211_ROAMING_MANUAL))
   2917      1.19    dyoung 			return EINVAL;
   2918      1.19    dyoung 		ic->ic_roaming = ireq->i_val;
   2919      1.19    dyoung 		/* XXXX reset? */
   2920      1.19    dyoung 		break;
   2921      1.19    dyoung 	case IEEE80211_IOC_PRIVACY:
   2922      1.19    dyoung 		if (ireq->i_val) {
   2923      1.19    dyoung 			/* XXX check for key state? */
   2924      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_PRIVACY;
   2925      1.19    dyoung 		} else
   2926      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
   2927      1.19    dyoung 		break;
   2928      1.19    dyoung 	case IEEE80211_IOC_DROPUNENCRYPTED:
   2929      1.19    dyoung 		if (ireq->i_val)
   2930      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
   2931      1.19    dyoung 		else
   2932      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
   2933      1.19    dyoung 		break;
   2934      1.19    dyoung 	case IEEE80211_IOC_WPAKEY:
   2935      1.19    dyoung 		error = ieee80211_ioctl_setkey(ic, ireq);
   2936      1.19    dyoung 		break;
   2937      1.19    dyoung 	case IEEE80211_IOC_DELKEY:
   2938      1.19    dyoung 		error = ieee80211_ioctl_delkey(ic, ireq);
   2939      1.19    dyoung 		break;
   2940      1.19    dyoung 	case IEEE80211_IOC_MLME:
   2941      1.19    dyoung 		error = ieee80211_ioctl_setmlme(ic, ireq);
   2942      1.19    dyoung 		break;
   2943      1.19    dyoung 	case IEEE80211_IOC_OPTIE:
   2944      1.19    dyoung 		error = ieee80211_ioctl_setoptie(ic, ireq);
   2945      1.19    dyoung 		break;
   2946      1.19    dyoung 	case IEEE80211_IOC_COUNTERMEASURES:
   2947      1.19    dyoung 		if (ireq->i_val) {
   2948      1.19    dyoung 			if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
   2949      1.19    dyoung 				return EINVAL;
   2950      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_COUNTERM;
   2951      1.19    dyoung 		} else
   2952      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_COUNTERM;
   2953      1.19    dyoung 		break;
   2954      1.19    dyoung 	case IEEE80211_IOC_WPA:
   2955      1.19    dyoung 		if (ireq->i_val > 3)
   2956      1.19    dyoung 			return EINVAL;
   2957      1.19    dyoung 		/* XXX verify ciphers available */
   2958      1.19    dyoung 		ic->ic_flags &= ~IEEE80211_F_WPA;
   2959      1.19    dyoung 		switch (ireq->i_val) {
   2960      1.19    dyoung 		case 1:
   2961      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_WPA1;
   2962       1.1    dyoung 			break;
   2963      1.19    dyoung 		case 2:
   2964      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_WPA2;
   2965       1.1    dyoung 			break;
   2966      1.19    dyoung 		case 3:
   2967      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
   2968       1.1    dyoung 			break;
   2969      1.19    dyoung 		}
   2970  1.48.4.1     skrll 		error = ENETRESET;
   2971      1.19    dyoung 		break;
   2972      1.19    dyoung 	case IEEE80211_IOC_WME:
   2973      1.19    dyoung 		if (ireq->i_val) {
   2974      1.19    dyoung 			if ((ic->ic_caps & IEEE80211_C_WME) == 0)
   2975      1.19    dyoung 				return EINVAL;
   2976      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_WME;
   2977      1.19    dyoung 		} else
   2978      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_WME;
   2979  1.48.4.1     skrll 		if (IS_UP_AUTO(ic))
   2980  1.48.4.1     skrll 			error = ieee80211_init(ic, 0);
   2981      1.19    dyoung 		break;
   2982      1.19    dyoung 	case IEEE80211_IOC_HIDESSID:
   2983      1.19    dyoung 		if (ireq->i_val)
   2984      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_HIDESSID;
   2985      1.19    dyoung 		else
   2986      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_HIDESSID;
   2987      1.19    dyoung 		error = ENETRESET;
   2988      1.19    dyoung 		break;
   2989      1.19    dyoung 	case IEEE80211_IOC_APBRIDGE:
   2990      1.19    dyoung 		if (ireq->i_val == 0)
   2991      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_NOBRIDGE;
   2992      1.19    dyoung 		else
   2993      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
   2994      1.19    dyoung 		break;
   2995      1.19    dyoung 	case IEEE80211_IOC_MCASTCIPHER:
   2996      1.19    dyoung 		if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
   2997      1.19    dyoung 		    !ieee80211_crypto_available(ireq->i_val))
   2998      1.19    dyoung 			return EINVAL;
   2999      1.19    dyoung 		rsn->rsn_mcastcipher = ireq->i_val;
   3000      1.19    dyoung 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
   3001      1.19    dyoung 		break;
   3002      1.19    dyoung 	case IEEE80211_IOC_MCASTKEYLEN:
   3003      1.19    dyoung 		if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
   3004      1.19    dyoung 			return EINVAL;
   3005      1.19    dyoung 		/* XXX no way to verify driver capability */
   3006      1.19    dyoung 		rsn->rsn_mcastkeylen = ireq->i_val;
   3007      1.19    dyoung 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
   3008      1.19    dyoung 		break;
   3009      1.19    dyoung 	case IEEE80211_IOC_UCASTCIPHERS:
   3010      1.19    dyoung 		/*
   3011      1.19    dyoung 		 * Convert user-specified cipher set to the set
   3012      1.19    dyoung 		 * we can support (via hardware or software).
   3013      1.19    dyoung 		 * NB: this logic intentionally ignores unknown and
   3014      1.19    dyoung 		 * unsupported ciphers so folks can specify 0xff or
   3015      1.19    dyoung 		 * similar and get all available ciphers.
   3016      1.19    dyoung 		 */
   3017      1.19    dyoung 		caps = 0;
   3018      1.19    dyoung 		for (j = 1; j < 32; j++)	/* NB: skip WEP */
   3019      1.19    dyoung 			if ((ireq->i_val & (1<<j)) &&
   3020      1.19    dyoung 			    ((ic->ic_caps & cipher2cap(j)) ||
   3021      1.19    dyoung 			     ieee80211_crypto_available(j)))
   3022      1.19    dyoung 				caps |= 1<<j;
   3023      1.19    dyoung 		if (caps == 0)			/* nothing available */
   3024      1.19    dyoung 			return EINVAL;
   3025      1.19    dyoung 		/* XXX verify ciphers ok for unicast use? */
   3026      1.19    dyoung 		/* XXX disallow if running as it'll have no effect */
   3027      1.19    dyoung 		rsn->rsn_ucastcipherset = caps;
   3028      1.19    dyoung 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
   3029      1.19    dyoung 		break;
   3030      1.19    dyoung 	case IEEE80211_IOC_UCASTCIPHER:
   3031      1.19    dyoung 		if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
   3032      1.19    dyoung 			return EINVAL;
   3033      1.19    dyoung 		rsn->rsn_ucastcipher = ireq->i_val;
   3034      1.19    dyoung 		break;
   3035      1.19    dyoung 	case IEEE80211_IOC_UCASTKEYLEN:
   3036      1.19    dyoung 		if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
   3037      1.19    dyoung 			return EINVAL;
   3038      1.19    dyoung 		/* XXX no way to verify driver capability */
   3039      1.19    dyoung 		rsn->rsn_ucastkeylen = ireq->i_val;
   3040      1.19    dyoung 		break;
   3041      1.19    dyoung 	case IEEE80211_IOC_DRIVER_CAPS:
   3042      1.19    dyoung 		/* NB: for testing */
   3043  1.48.4.1     skrll 		ic->ic_caps = (((uint16_t) ireq->i_val) << 16) |
   3044  1.48.4.1     skrll 			       ((uint16_t) ireq->i_len);
   3045      1.19    dyoung 		break;
   3046      1.19    dyoung 	case IEEE80211_IOC_KEYMGTALGS:
   3047      1.19    dyoung 		/* XXX check */
   3048      1.19    dyoung 		rsn->rsn_keymgmtset = ireq->i_val;
   3049      1.19    dyoung 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
   3050      1.19    dyoung 		break;
   3051      1.19    dyoung 	case IEEE80211_IOC_RSNCAPS:
   3052      1.19    dyoung 		/* XXX check */
   3053      1.19    dyoung 		rsn->rsn_caps = ireq->i_val;
   3054      1.19    dyoung 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
   3055      1.19    dyoung 		break;
   3056      1.30    dyoung #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
   3057      1.19    dyoung 	case IEEE80211_IOC_BSSID:
   3058      1.19    dyoung 		if (ireq->i_len != sizeof(tmpbssid))
   3059      1.19    dyoung 			return EINVAL;
   3060      1.19    dyoung 		error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
   3061      1.19    dyoung 		if (error)
   3062       1.1    dyoung 			break;
   3063      1.19    dyoung 		IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
   3064      1.19    dyoung 		if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
   3065      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
   3066      1.19    dyoung 		else
   3067      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_DESBSSID;
   3068  1.48.4.1     skrll 		if (IS_UP_AUTO(ic))
   3069  1.48.4.1     skrll 			error = ieee80211_init(ic, RESCAN);
   3070      1.19    dyoung 		break;
   3071      1.30    dyoung #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
   3072      1.19    dyoung 	case IEEE80211_IOC_CHANLIST:
   3073      1.19    dyoung 		error = ieee80211_ioctl_setchanlist(ic, ireq);
   3074      1.19    dyoung 		break;
   3075      1.19    dyoung 	case IEEE80211_IOC_SCAN_REQ:
   3076  1.48.4.1     skrll 		if (!IS_UP(ic))
   3077  1.48.4.1     skrll 			return EINVAL;
   3078  1.48.4.1     skrll 		(void) ieee80211_start_scan(ic,
   3079  1.48.4.1     skrll 			IEEE80211_SCAN_ACTIVE |
   3080  1.48.4.1     skrll 			IEEE80211_SCAN_NOPICK |
   3081  1.48.4.1     skrll 			IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER,
   3082  1.48.4.1     skrll 			/* XXX use ioctl params */
   3083  1.48.4.1     skrll 			ic->ic_des_nssid, ic->ic_des_ssid);
   3084      1.19    dyoung 		break;
   3085      1.19    dyoung 	case IEEE80211_IOC_ADDMAC:
   3086      1.19    dyoung 	case IEEE80211_IOC_DELMAC:
   3087      1.19    dyoung 		error = ieee80211_ioctl_macmac(ic, ireq);
   3088      1.19    dyoung 		break;
   3089      1.19    dyoung 	case IEEE80211_IOC_MACCMD:
   3090      1.26     skrll 		error = ieee80211_ioctl_setmaccmd(ic, ireq);
   3091      1.19    dyoung 		break;
   3092  1.48.4.1     skrll 	case IEEE80211_IOC_STA_STATS:
   3093  1.48.4.1     skrll 		error = ieee80211_ioctl_setstastats(ic, ireq);
   3094  1.48.4.1     skrll 		break;
   3095      1.19    dyoung 	case IEEE80211_IOC_STA_TXPOW:
   3096      1.19    dyoung 		error = ieee80211_ioctl_setstatxpow(ic, ireq);
   3097      1.19    dyoung 		break;
   3098      1.19    dyoung 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
   3099      1.19    dyoung 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
   3100      1.19    dyoung 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
   3101      1.19    dyoung 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
   3102      1.19    dyoung 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
   3103      1.19    dyoung 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
   3104      1.19    dyoung 		error = ieee80211_ioctl_setwmeparam(ic, ireq);
   3105      1.19    dyoung 		break;
   3106      1.19    dyoung 	case IEEE80211_IOC_DTIM_PERIOD:
   3107      1.19    dyoung 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
   3108      1.19    dyoung 		    ic->ic_opmode != IEEE80211_M_IBSS)
   3109      1.19    dyoung 			return EINVAL;
   3110      1.19    dyoung 		if (IEEE80211_DTIM_MIN <= ireq->i_val &&
   3111      1.19    dyoung 		    ireq->i_val <= IEEE80211_DTIM_MAX) {
   3112      1.19    dyoung 			ic->ic_dtim_period = ireq->i_val;
   3113      1.19    dyoung 			error = ENETRESET;		/* requires restart */
   3114      1.19    dyoung 		} else
   3115      1.19    dyoung 			error = EINVAL;
   3116      1.19    dyoung 		break;
   3117      1.19    dyoung 	case IEEE80211_IOC_BEACON_INTERVAL:
   3118      1.19    dyoung 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
   3119      1.19    dyoung 		    ic->ic_opmode != IEEE80211_M_IBSS)
   3120      1.19    dyoung 			return EINVAL;
   3121      1.19    dyoung 		if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
   3122      1.19    dyoung 		    ireq->i_val <= IEEE80211_BINTVAL_MAX) {
   3123      1.26     skrll 			ic->ic_bintval = ireq->i_val;
   3124      1.19    dyoung 			error = ENETRESET;		/* requires restart */
   3125      1.19    dyoung 		} else
   3126       1.1    dyoung 			error = EINVAL;
   3127      1.19    dyoung 		break;
   3128      1.21    dyoung 	case IEEE80211_IOC_PUREG:
   3129      1.21    dyoung 		if (ireq->i_val)
   3130      1.21    dyoung 			ic->ic_flags |= IEEE80211_F_PUREG;
   3131      1.21    dyoung 		else
   3132      1.21    dyoung 			ic->ic_flags &= ~IEEE80211_F_PUREG;
   3133      1.21    dyoung 		/* NB: reset only if we're operating on an 11g channel */
   3134  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3135  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
   3136      1.21    dyoung 			error = ENETRESET;
   3137      1.21    dyoung 		break;
   3138  1.48.4.1     skrll 	case IEEE80211_IOC_FF:
   3139  1.48.4.1     skrll 		if (ireq->i_val) {
   3140  1.48.4.1     skrll 			if ((ic->ic_caps & IEEE80211_C_FF) == 0)
   3141  1.48.4.1     skrll 				return EINVAL;
   3142  1.48.4.1     skrll 			ic->ic_flags |= IEEE80211_F_FF;
   3143  1.48.4.1     skrll 		} else
   3144  1.48.4.1     skrll 			ic->ic_flags &= ~IEEE80211_F_FF;
   3145  1.48.4.1     skrll 		error = ENETRESET;
   3146  1.48.4.1     skrll 		break;
   3147  1.48.4.1     skrll 	case IEEE80211_IOC_TURBOP:
   3148  1.48.4.1     skrll 		if (ireq->i_val) {
   3149  1.48.4.1     skrll 			if ((ic->ic_caps & IEEE80211_C_TURBOP) == 0)
   3150  1.48.4.1     skrll 				return EINVAL;
   3151  1.48.4.1     skrll 			ic->ic_flags |= IEEE80211_F_TURBOP;
   3152  1.48.4.1     skrll 		} else
   3153  1.48.4.1     skrll 			ic->ic_flags &= ~IEEE80211_F_TURBOP;
   3154  1.48.4.1     skrll 		error = ENETRESET;
   3155  1.48.4.1     skrll 		break;
   3156  1.48.4.1     skrll 	case IEEE80211_IOC_BGSCAN:
   3157  1.48.4.1     skrll 		if (ireq->i_val) {
   3158  1.48.4.1     skrll 			if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0)
   3159  1.48.4.1     skrll 				return EINVAL;
   3160  1.48.4.1     skrll 			ic->ic_flags |= IEEE80211_F_BGSCAN;
   3161  1.48.4.1     skrll 		} else
   3162  1.48.4.1     skrll 			ic->ic_flags &= ~IEEE80211_F_BGSCAN;
   3163  1.48.4.1     skrll 		break;
   3164  1.48.4.1     skrll 	case IEEE80211_IOC_BGSCAN_IDLE:
   3165  1.48.4.1     skrll 		if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
   3166  1.48.4.1     skrll 			ic->ic_bgscanidle = ireq->i_val*hz/1000;
   3167  1.48.4.1     skrll 		else
   3168  1.48.4.1     skrll 			error = EINVAL;
   3169  1.48.4.1     skrll 		break;
   3170  1.48.4.1     skrll 	case IEEE80211_IOC_BGSCAN_INTERVAL:
   3171  1.48.4.1     skrll 		if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
   3172  1.48.4.1     skrll 			ic->ic_bgscanintvl = ireq->i_val*hz;
   3173  1.48.4.1     skrll 		else
   3174  1.48.4.1     skrll 			error = EINVAL;
   3175  1.48.4.1     skrll 		break;
   3176  1.48.4.1     skrll 	case IEEE80211_IOC_SCANVALID:
   3177  1.48.4.1     skrll 		if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
   3178  1.48.4.1     skrll 			ic->ic_scanvalid = ireq->i_val*hz;
   3179  1.48.4.1     skrll 		else
   3180  1.48.4.1     skrll 			error = EINVAL;
   3181  1.48.4.1     skrll 		break;
   3182  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RSSI_11A:
   3183  1.48.4.1     skrll 		ic->ic_roam.rssi11a = ireq->i_val;
   3184  1.48.4.1     skrll 		break;
   3185  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RSSI_11B:
   3186  1.48.4.1     skrll 		ic->ic_roam.rssi11bOnly = ireq->i_val;
   3187  1.48.4.1     skrll 		break;
   3188  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RSSI_11G:
   3189  1.48.4.1     skrll 		ic->ic_roam.rssi11b = ireq->i_val;
   3190  1.48.4.1     skrll 		break;
   3191  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RATE_11A:
   3192  1.48.4.1     skrll 		ic->ic_roam.rate11a = ireq->i_val & IEEE80211_RATE_VAL;
   3193  1.48.4.1     skrll 		break;
   3194  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RATE_11B:
   3195  1.48.4.1     skrll 		ic->ic_roam.rate11bOnly = ireq->i_val & IEEE80211_RATE_VAL;
   3196  1.48.4.1     skrll 		break;
   3197  1.48.4.1     skrll 	case IEEE80211_IOC_ROAM_RATE_11G:
   3198  1.48.4.1     skrll 		ic->ic_roam.rate11b = ireq->i_val & IEEE80211_RATE_VAL;
   3199  1.48.4.1     skrll 		break;
   3200      1.30    dyoung 	case IEEE80211_IOC_MCAST_RATE:
   3201      1.30    dyoung 		ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
   3202      1.30    dyoung 		break;
   3203      1.26     skrll 	case IEEE80211_IOC_FRAGTHRESHOLD:
   3204      1.26     skrll 		if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
   3205      1.26     skrll 		    ireq->i_val != IEEE80211_FRAG_MAX)
   3206      1.26     skrll 			return EINVAL;
   3207      1.26     skrll 		if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
   3208      1.26     skrll 		      ireq->i_val <= IEEE80211_FRAG_MAX))
   3209      1.26     skrll 			return EINVAL;
   3210      1.26     skrll 		ic->ic_fragthreshold = ireq->i_val;
   3211      1.26     skrll 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   3212      1.26     skrll 		break;
   3213  1.48.4.1     skrll 	case IEEE80211_IOC_BURST:
   3214  1.48.4.1     skrll 		if (ireq->i_val) {
   3215  1.48.4.1     skrll 			if ((ic->ic_caps & IEEE80211_C_BURST) == 0)
   3216  1.48.4.1     skrll 				return EINVAL;
   3217  1.48.4.1     skrll 			ic->ic_flags |= IEEE80211_F_BURST;
   3218  1.48.4.1     skrll 		} else
   3219  1.48.4.1     skrll 			ic->ic_flags &= ~IEEE80211_F_BURST;
   3220  1.48.4.1     skrll 		error = ENETRESET;		/* XXX maybe not for station? */
   3221  1.48.4.1     skrll 		break;
   3222  1.48.4.1     skrll 	case IEEE80211_IOC_BMISSTHRESHOLD:
   3223  1.48.4.1     skrll 		if (!(IEEE80211_HWBMISS_MIN <= ireq->i_val &&
   3224  1.48.4.1     skrll 		      ireq->i_val <= IEEE80211_HWBMISS_MAX))
   3225  1.48.4.1     skrll 			return EINVAL;
   3226  1.48.4.1     skrll 		ic->ic_bmissthreshold = ireq->i_val;
   3227  1.48.4.1     skrll 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   3228  1.48.4.1     skrll 		break;
   3229  1.48.4.1     skrll 	case IEEE80211_IOC_CURCHAN:
   3230  1.48.4.1     skrll 		error = ieee80211_ioctl_setcurchan(ic, ireq);
   3231  1.48.4.1     skrll 		break;
   3232  1.48.4.1     skrll 	case IEEE80211_IOC_SHORTGI:
   3233  1.48.4.1     skrll 		if (ireq->i_val) {
   3234  1.48.4.1     skrll #define	IEEE80211_HTCAP_SHORTGI \
   3235  1.48.4.1     skrll 	(IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
   3236  1.48.4.1     skrll 			if (((ireq->i_val ^ ic->ic_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
   3237  1.48.4.1     skrll 				return EINVAL;
   3238  1.48.4.1     skrll 			if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
   3239  1.48.4.1     skrll 				ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
   3240  1.48.4.1     skrll 			if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
   3241  1.48.4.1     skrll 				ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
   3242  1.48.4.1     skrll #undef IEEE80211_HTCAP_SHORTGI
   3243  1.48.4.1     skrll 		} else
   3244  1.48.4.1     skrll 			ic->ic_flags_ext &=
   3245  1.48.4.1     skrll 			    ~(IEEE80211_FEXT_SHORTGI20 | IEEE80211_FEXT_SHORTGI40);
   3246  1.48.4.1     skrll 		/* XXX kick state machine? */
   3247  1.48.4.1     skrll 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   3248  1.48.4.1     skrll 		break;
   3249  1.48.4.1     skrll 	case IEEE80211_IOC_AMPDU:
   3250  1.48.4.1     skrll 		if (ireq->i_val) {
   3251  1.48.4.1     skrll 			if ((ic->ic_htcaps & IEEE80211_HTC_AMPDU) == 0)
   3252  1.48.4.1     skrll 				return EINVAL;
   3253  1.48.4.1     skrll 			if (ireq->i_val & 1)
   3254  1.48.4.1     skrll 				ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
   3255  1.48.4.1     skrll 			if (ireq->i_val & 2)
   3256  1.48.4.1     skrll 				ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
   3257  1.48.4.1     skrll 		} else
   3258  1.48.4.1     skrll 			ic->ic_flags_ext &=
   3259  1.48.4.1     skrll 			    ~(IEEE80211_FEXT_AMPDU_TX|IEEE80211_FEXT_AMPDU_RX);
   3260  1.48.4.1     skrll 		/* NB: reset only if we're operating on an 11n channel */
   3261  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3262  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
   3263  1.48.4.1     skrll 			error = ENETRESET;
   3264  1.48.4.1     skrll 		break;
   3265  1.48.4.1     skrll 	case IEEE80211_IOC_AMPDU_LIMIT:
   3266  1.48.4.1     skrll 		/* XXX validate */
   3267  1.48.4.1     skrll 		ic->ic_ampdu_limit = ireq->i_val;
   3268  1.48.4.1     skrll 		break;
   3269  1.48.4.1     skrll 	case IEEE80211_IOC_AMPDU_DENSITY:
   3270  1.48.4.1     skrll 		/* XXX validate */
   3271  1.48.4.1     skrll 		ic->ic_ampdu_density = ireq->i_val;
   3272  1.48.4.1     skrll 		break;
   3273  1.48.4.1     skrll 	case IEEE80211_IOC_AMSDU:
   3274  1.48.4.1     skrll 		if (ireq->i_val) {
   3275  1.48.4.1     skrll 			if ((ic->ic_htcaps & IEEE80211_HTC_AMSDU) == 0)
   3276  1.48.4.1     skrll 				return EINVAL;
   3277  1.48.4.1     skrll 			if (ireq->i_val & 1)
   3278  1.48.4.1     skrll 				ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
   3279  1.48.4.1     skrll 			if (ireq->i_val & 2)
   3280  1.48.4.1     skrll 				ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
   3281  1.48.4.1     skrll 		} else
   3282  1.48.4.1     skrll 			ic->ic_flags_ext &=
   3283  1.48.4.1     skrll 			    ~(IEEE80211_FEXT_AMSDU_TX|IEEE80211_FEXT_AMSDU_RX);
   3284  1.48.4.1     skrll 		/* NB: reset only if we're operating on an 11n channel */
   3285  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3286  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
   3287  1.48.4.1     skrll 			error = ENETRESET;
   3288  1.48.4.1     skrll 		break;
   3289  1.48.4.1     skrll 	case IEEE80211_IOC_AMSDU_LIMIT:
   3290  1.48.4.1     skrll 		/* XXX validate */
   3291  1.48.4.1     skrll 		ic->ic_amsdu_limit = ireq->i_val;	/* XXX truncation? */
   3292  1.48.4.1     skrll 		break;
   3293  1.48.4.1     skrll 	case IEEE80211_IOC_PUREN:
   3294  1.48.4.1     skrll 		if (ireq->i_val) {
   3295  1.48.4.1     skrll 			if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
   3296  1.48.4.1     skrll 				return EINVAL;
   3297  1.48.4.1     skrll 			ic->ic_flags_ext |= IEEE80211_FEXT_PUREN;
   3298  1.48.4.1     skrll 		} else
   3299  1.48.4.1     skrll 			ic->ic_flags_ext &= ~IEEE80211_FEXT_PUREN;
   3300  1.48.4.1     skrll 		/* NB: reset only if we're operating on an 11n channel */
   3301  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3302  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
   3303  1.48.4.1     skrll 			error = ENETRESET;
   3304  1.48.4.1     skrll 		break;
   3305  1.48.4.1     skrll 	case IEEE80211_IOC_DOTH:
   3306  1.48.4.1     skrll 		if (ireq->i_val) {
   3307  1.48.4.1     skrll #if 0
   3308  1.48.4.1     skrll 			/* XXX no capability */
   3309  1.48.4.1     skrll 			if ((ic->ic_caps & IEEE80211_C_DOTH) == 0)
   3310  1.48.4.1     skrll 				return EINVAL;
   3311  1.48.4.1     skrll #endif
   3312  1.48.4.1     skrll 			ic->ic_flags |= IEEE80211_F_DOTH;
   3313  1.48.4.1     skrll 		} else
   3314  1.48.4.1     skrll 			ic->ic_flags &= ~IEEE80211_F_DOTH;
   3315  1.48.4.1     skrll 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
   3316  1.48.4.1     skrll 		break;
   3317  1.48.4.1     skrll 	case IEEE80211_IOC_HTCOMPAT:
   3318  1.48.4.1     skrll 		if (ireq->i_val) {
   3319  1.48.4.1     skrll 			if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
   3320  1.48.4.1     skrll 				return EINVAL;
   3321  1.48.4.1     skrll 			ic->ic_flags_ext |= IEEE80211_FEXT_HTCOMPAT;
   3322  1.48.4.1     skrll 		} else
   3323  1.48.4.1     skrll 			ic->ic_flags_ext &= ~IEEE80211_FEXT_HTCOMPAT;
   3324  1.48.4.1     skrll 		/* NB: reset only if we're operating on an 11n channel */
   3325  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3326  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
   3327  1.48.4.1     skrll 			error = ENETRESET;
   3328  1.48.4.1     skrll 		break;
   3329  1.48.4.1     skrll 	case IEEE80211_IOC_INACTIVITY:
   3330  1.48.4.1     skrll 		if (ireq->i_val)
   3331  1.48.4.1     skrll 			ic->ic_flags_ext |= IEEE80211_FEXT_INACT;
   3332  1.48.4.1     skrll 		else
   3333  1.48.4.1     skrll 			ic->ic_flags_ext &= ~IEEE80211_FEXT_INACT;
   3334  1.48.4.1     skrll 		break;
   3335  1.48.4.1     skrll 	case IEEE80211_IOC_HTPROTMODE:
   3336  1.48.4.1     skrll 		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
   3337  1.48.4.1     skrll 			return EINVAL;
   3338  1.48.4.1     skrll 		ic->ic_htprotmode = ireq->i_val ?
   3339  1.48.4.1     skrll 		    IEEE80211_PROT_RTSCTS : IEEE80211_PROT_NONE;
   3340  1.48.4.1     skrll 		/* NB: if not operating in 11n this can wait */
   3341  1.48.4.1     skrll 		if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
   3342  1.48.4.1     skrll 		    IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
   3343  1.48.4.1     skrll 			error = ERESTART;
   3344  1.48.4.1     skrll 		break;
   3345  1.48.4.1     skrll 	case IEEE80211_IOC_HTCONF:
   3346  1.48.4.1     skrll 		if (ireq->i_val & 1)
   3347  1.48.4.1     skrll 			ic->ic_flags_ext |= IEEE80211_FEXT_HT;
   3348  1.48.4.1     skrll 		else
   3349  1.48.4.1     skrll 			ic->ic_flags_ext &= ~IEEE80211_FEXT_HT;
   3350  1.48.4.1     skrll 		if (ireq->i_val & 2)
   3351  1.48.4.1     skrll 			ic->ic_flags_ext |= IEEE80211_FEXT_USEHT40;
   3352  1.48.4.1     skrll 		else
   3353  1.48.4.1     skrll 			ic->ic_flags_ext &= ~IEEE80211_FEXT_USEHT40;
   3354  1.48.4.1     skrll 		error = ENETRESET;
   3355  1.48.4.1     skrll 		break;
   3356      1.19    dyoung 	default:
   3357      1.19    dyoung 		error = EINVAL;
   3358      1.19    dyoung 		break;
   3359      1.19    dyoung 	}
   3360  1.48.4.1     skrll 	if (error == ENETRESET)
   3361  1.48.4.1     skrll 		error = IS_UP_AUTO(ic) ? ieee80211_init(ic, 0) : 0;
   3362      1.19    dyoung 	return error;
   3363      1.19    dyoung }
   3364      1.19    dyoung 
   3365      1.19    dyoung #ifdef __FreeBSD__
   3366      1.19    dyoung int
   3367      1.45  christos ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
   3368      1.19    dyoung {
   3369      1.19    dyoung 	struct ifnet *ifp = ic->ic_ifp;
   3370      1.19    dyoung 	int error = 0;
   3371      1.19    dyoung 	struct ifreq *ifr;
   3372      1.19    dyoung 	struct ifaddr *ifa;			/* XXX */
   3373      1.19    dyoung 
   3374      1.19    dyoung 	switch (cmd) {
   3375      1.19    dyoung 	case SIOCSIFMEDIA:
   3376      1.19    dyoung 	case SIOCGIFMEDIA:
   3377      1.19    dyoung 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
   3378      1.19    dyoung 				&ic->ic_media, cmd);
   3379      1.19    dyoung 		break;
   3380      1.19    dyoung 	case SIOCG80211:
   3381      1.19    dyoung 		error = ieee80211_ioctl_get80211(ic, cmd,
   3382      1.19    dyoung 				(struct ieee80211req *) data);
   3383      1.19    dyoung 		break;
   3384      1.19    dyoung 	case SIOCS80211:
   3385  1.48.4.1     skrll 		error = priv_check(curthread, PRIV_NET80211_MANAGE);
   3386      1.19    dyoung 		if (error == 0)
   3387      1.19    dyoung 			error = ieee80211_ioctl_set80211(ic, cmd,
   3388      1.19    dyoung 					(struct ieee80211req *) data);
   3389       1.1    dyoung 		break;
   3390      1.19    dyoung 	case SIOCG80211STATS:
   3391      1.19    dyoung 		ifr = (struct ifreq *)data;
   3392      1.19    dyoung 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
   3393      1.19    dyoung 		break;
   3394      1.19    dyoung 	case SIOCSIFMTU:
   3395      1.19    dyoung 		ifr = (struct ifreq *)data;
   3396      1.19    dyoung 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
   3397      1.19    dyoung 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
   3398      1.19    dyoung 			error = EINVAL;
   3399      1.19    dyoung 		else
   3400      1.19    dyoung 			ifp->if_mtu = ifr->ifr_mtu;
   3401      1.19    dyoung 		break;
   3402      1.19    dyoung 	case SIOCSIFADDR:
   3403      1.19    dyoung 		/*
   3404      1.19    dyoung 		 * XXX Handle this directly so we can supress if_init calls.
   3405      1.19    dyoung 		 * XXX This should be done in ether_ioctl but for the moment
   3406      1.19    dyoung 		 * XXX there are too many other parts of the system that
   3407      1.19    dyoung 		 * XXX set IFF_UP and so supress if_init being called when
   3408      1.19    dyoung 		 * XXX it should be.
   3409      1.19    dyoung 		 */
   3410      1.19    dyoung 		ifa = (struct ifaddr *) data;
   3411      1.19    dyoung 		switch (ifa->ifa_addr->sa_family) {
   3412      1.19    dyoung #ifdef INET
   3413      1.19    dyoung 		case AF_INET:
   3414      1.19    dyoung 			if ((ifp->if_flags & IFF_UP) == 0) {
   3415      1.19    dyoung 				ifp->if_flags |= IFF_UP;
   3416      1.19    dyoung 				ifp->if_init(ifp->if_softc);
   3417      1.19    dyoung 			}
   3418      1.19    dyoung 			arp_ifinit(ifp, ifa);
   3419      1.19    dyoung 			break;
   3420      1.19    dyoung #endif
   3421      1.19    dyoung #ifdef IPX
   3422      1.19    dyoung 		/*
   3423      1.19    dyoung 		 * XXX - This code is probably wrong,
   3424      1.19    dyoung 		 *	 but has been copied many times.
   3425      1.19    dyoung 		 */
   3426      1.19    dyoung 		case AF_IPX: {
   3427      1.19    dyoung 			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
   3428      1.19    dyoung 
   3429      1.19    dyoung 			if (ipx_nullhost(*ina))
   3430      1.21    dyoung 				ina->x_host = *(union ipx_host *)
   3431  1.48.4.1     skrll 				    IF_LLADDR(ifp);
   3432      1.19    dyoung 			else
   3433      1.45  christos 				bcopy((void *) ina->x_host.c_host,
   3434      1.45  christos 				      (void *) IFP2ENADDR(ifp),
   3435      1.21    dyoung 				      ETHER_ADDR_LEN);
   3436      1.19    dyoung 			/* fall thru... */
   3437      1.19    dyoung 		}
   3438      1.19    dyoung #endif
   3439      1.19    dyoung 		default:
   3440      1.19    dyoung 			if ((ifp->if_flags & IFF_UP) == 0) {
   3441      1.19    dyoung 				ifp->if_flags |= IFF_UP;
   3442      1.19    dyoung 				ifp->if_init(ifp->if_softc);
   3443      1.19    dyoung 			}
   3444      1.19    dyoung 			break;
   3445      1.19    dyoung 		}
   3446       1.1    dyoung 		break;
   3447       1.1    dyoung 	default:
   3448       1.1    dyoung 		error = ether_ioctl(ifp, cmd, data);
   3449       1.1    dyoung 		break;
   3450       1.1    dyoung 	}
   3451       1.1    dyoung 	return error;
   3452       1.1    dyoung }
   3453       1.2    dyoung #endif /* __FreeBSD__ */
   3454       1.2    dyoung 
   3455      1.22    dyoung #ifdef COMPAT_20
   3456      1.22    dyoung static void
   3457      1.22    dyoung ieee80211_get_ostats(struct ieee80211_ostats *ostats,
   3458      1.22    dyoung     struct ieee80211_stats *stats)
   3459      1.22    dyoung {
   3460      1.22    dyoung #define	COPYSTATS1(__ostats, __nstats, __dstmemb, __srcmemb, __lastmemb)\
   3461      1.22    dyoung 	(void)memcpy(&(__ostats)->__dstmemb, &(__nstats)->__srcmemb,	\
   3462      1.22    dyoung 	    offsetof(struct ieee80211_stats, __lastmemb) -		\
   3463      1.22    dyoung 	    offsetof(struct ieee80211_stats, __srcmemb))
   3464      1.22    dyoung #define	COPYSTATS(__ostats, __nstats, __dstmemb, __lastmemb)		\
   3465      1.22    dyoung 	COPYSTATS1(__ostats, __nstats, __dstmemb, __dstmemb, __lastmemb)
   3466      1.22    dyoung 
   3467      1.22    dyoung 	COPYSTATS(ostats, stats, is_rx_badversion, is_rx_unencrypted);
   3468      1.22    dyoung 	COPYSTATS(ostats, stats, is_rx_wepfail, is_rx_beacon);
   3469      1.22    dyoung 	COPYSTATS(ostats, stats, is_rx_rstoobig, is_rx_auth_countermeasures);
   3470      1.22    dyoung 	COPYSTATS(ostats, stats, is_rx_assoc_bss, is_rx_assoc_badwpaie);
   3471      1.22    dyoung 	COPYSTATS(ostats, stats, is_rx_deauth, is_rx_unauth);
   3472      1.22    dyoung 	COPYSTATS1(ostats, stats, is_tx_nombuf, is_tx_nobuf, is_tx_badcipher);
   3473      1.22    dyoung 	COPYSTATS(ostats, stats, is_scan_active, is_crypto_tkip);
   3474      1.22    dyoung }
   3475      1.22    dyoung #endif /* COMPAT_20 */
   3476      1.22    dyoung 
   3477       1.2    dyoung #ifdef __NetBSD__
   3478       1.2    dyoung int
   3479      1.45  christos ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
   3480       1.2    dyoung {
   3481      1.19    dyoung 	struct ifnet *ifp = ic->ic_ifp;
   3482       1.2    dyoung 	struct ifreq *ifr = (struct ifreq *)data;
   3483      1.19    dyoung 	int i, error = 0, kid, klen, s;
   3484      1.19    dyoung 	struct ieee80211_key *k;
   3485       1.2    dyoung 	struct ieee80211_nwid nwid;
   3486       1.2    dyoung 	struct ieee80211_nwkey *nwkey;
   3487       1.2    dyoung 	struct ieee80211_power *power;
   3488       1.2    dyoung 	struct ieee80211_bssid *bssid;
   3489       1.2    dyoung 	struct ieee80211chanreq *chanreq;
   3490       1.2    dyoung 	struct ieee80211_channel *chan;
   3491      1.19    dyoung 	uint32_t oflags;
   3492      1.22    dyoung #ifdef COMPAT_20
   3493      1.22    dyoung 	struct ieee80211_ostats ostats;
   3494      1.22    dyoung #endif /* COMPAT_20 */
   3495      1.29    dyoung 	static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
   3496      1.19    dyoung 	u_int8_t tmpkey[IEEE80211_WEP_NKID][IEEE80211_KEYBUF_SIZE];
   3497       1.2    dyoung 
   3498       1.2    dyoung 	switch (cmd) {
   3499      1.46  christos #ifdef OSIOCSIFMEDIA
   3500      1.46  christos 	case OSIOCSIFMEDIA:
   3501      1.46  christos #endif
   3502       1.2    dyoung 	case SIOCSIFMEDIA:
   3503       1.2    dyoung 	case SIOCGIFMEDIA:
   3504       1.2    dyoung 		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
   3505       1.2    dyoung 		break;
   3506      1.19    dyoung 	case SIOCG80211:
   3507      1.19    dyoung 		error = ieee80211_ioctl_get80211(ic, cmd,
   3508      1.19    dyoung 				(struct ieee80211req *) data);
   3509      1.19    dyoung 		break;
   3510      1.19    dyoung 	case SIOCS80211:
   3511      1.41      elad 		if ((error = kauth_authorize_network(curlwp->l_cred,
   3512      1.41      elad 		    KAUTH_NETWORK_INTERFACE,
   3513      1.41      elad 		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
   3514      1.41      elad 		    NULL) != 0))
   3515      1.19    dyoung 			break;
   3516      1.19    dyoung 		error = ieee80211_ioctl_set80211(ic, cmd,
   3517      1.19    dyoung 				(struct ieee80211req *) data);
   3518      1.19    dyoung 		break;
   3519       1.2    dyoung 	case SIOCS80211NWID:
   3520       1.2    dyoung 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
   3521       1.2    dyoung 			break;
   3522       1.2    dyoung 		if (nwid.i_len > IEEE80211_NWID_LEN) {
   3523       1.2    dyoung 			error = EINVAL;
   3524       1.2    dyoung 			break;
   3525       1.2    dyoung 		}
   3526  1.48.4.1     skrll 		memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
   3527  1.48.4.1     skrll 		ic->ic_des_ssid[0].len = nwid.i_len;
   3528  1.48.4.1     skrll 		memcpy(ic->ic_des_ssid[0].ssid, nwid.i_nwid, nwid.i_len);
   3529       1.2    dyoung 		error = ENETRESET;
   3530       1.2    dyoung 		break;
   3531       1.2    dyoung 	case SIOCG80211NWID:
   3532       1.2    dyoung 		memset(&nwid, 0, sizeof(nwid));
   3533       1.2    dyoung 		switch (ic->ic_state) {
   3534       1.2    dyoung 		case IEEE80211_S_INIT:
   3535       1.2    dyoung 		case IEEE80211_S_SCAN:
   3536  1.48.4.1     skrll 			nwid.i_len = ic->ic_des_ssid[0].len;
   3537  1.48.4.1     skrll 			memcpy(nwid.i_nwid, ic->ic_des_ssid[0].ssid, nwid.i_len);
   3538       1.2    dyoung 			break;
   3539       1.2    dyoung 		default:
   3540       1.2    dyoung 			nwid.i_len = ic->ic_bss->ni_esslen;
   3541       1.2    dyoung 			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
   3542       1.2    dyoung 			break;
   3543       1.2    dyoung 		}
   3544       1.2    dyoung 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
   3545       1.2    dyoung 		break;
   3546       1.2    dyoung 	case SIOCS80211NWKEY:
   3547       1.2    dyoung 		nwkey = (struct ieee80211_nwkey *)data;
   3548      1.19    dyoung 		/* transmit key index out of range? */
   3549      1.19    dyoung 		kid = nwkey->i_defkid - 1;
   3550      1.19    dyoung 		if (kid < 0 || kid >= IEEE80211_WEP_NKID) {
   3551       1.2    dyoung 			error = EINVAL;
   3552       1.2    dyoung 			break;
   3553       1.2    dyoung 		}
   3554      1.19    dyoung 		/* no such transmit key is set? */
   3555      1.19    dyoung 		if (nwkey->i_key[kid].i_keylen == 0 ||
   3556      1.19    dyoung 		    (nwkey->i_key[kid].i_keylen == -1 &&
   3557      1.19    dyoung 		     ic->ic_nw_keys[kid].wk_keylen == 0)) {
   3558      1.19    dyoung 			if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
   3559      1.19    dyoung 				error = EINVAL;
   3560      1.19    dyoung 				break;
   3561      1.19    dyoung 			}
   3562      1.19    dyoung 		}
   3563      1.19    dyoung 		/* check key lengths */
   3564      1.19    dyoung 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
   3565      1.19    dyoung 			klen = nwkey->i_key[kid].i_keylen;
   3566      1.19    dyoung 			if ((klen > 0 &&
   3567      1.19    dyoung 			    klen < IEEE80211_WEP_KEYLEN) ||
   3568      1.19    dyoung 			    klen > sizeof(ic->ic_nw_keys[kid].wk_key)) {
   3569       1.2    dyoung 				error = EINVAL;
   3570       1.2    dyoung 				break;
   3571       1.2    dyoung 			}
   3572      1.19    dyoung 		}
   3573      1.19    dyoung 
   3574      1.19    dyoung 		if (error)
   3575      1.19    dyoung 			break;
   3576      1.19    dyoung 
   3577      1.19    dyoung 		/* copy in keys */
   3578      1.19    dyoung 		(void)memset(tmpkey, 0, sizeof(tmpkey));
   3579      1.19    dyoung 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
   3580      1.19    dyoung 			klen = nwkey->i_key[kid].i_keylen;
   3581      1.19    dyoung 			if (klen <= 0)
   3582       1.2    dyoung 				continue;
   3583      1.19    dyoung 			if ((error = copyin(nwkey->i_key[kid].i_keydat,
   3584      1.19    dyoung 			    tmpkey[kid], klen)) != 0)
   3585       1.2    dyoung 				break;
   3586       1.2    dyoung 		}
   3587      1.19    dyoung 
   3588       1.2    dyoung 		if (error)
   3589       1.2    dyoung 			break;
   3590      1.19    dyoung 
   3591      1.19    dyoung 		/* set keys */
   3592      1.19    dyoung 		ieee80211_key_update_begin(ic);
   3593      1.19    dyoung 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
   3594      1.19    dyoung 			klen = nwkey->i_key[kid].i_keylen;
   3595      1.19    dyoung 			if (klen <= 0)
   3596      1.19    dyoung 				continue;
   3597      1.19    dyoung 			k = &ic->ic_nw_keys[kid];
   3598      1.19    dyoung 			k->wk_keyix = kid;
   3599      1.19    dyoung 			if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
   3600      1.19    dyoung 			    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
   3601       1.2    dyoung 				error = EINVAL;
   3602      1.19    dyoung 				continue;
   3603       1.2    dyoung 			}
   3604      1.19    dyoung 			k->wk_keylen = nwkey->i_key[kid].i_keylen;
   3605      1.19    dyoung 			(void)memcpy(k->wk_key, tmpkey[kid],
   3606      1.19    dyoung 			    sizeof(tmpkey[kid]));
   3607      1.19    dyoung 			if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
   3608      1.19    dyoung 				error = EINVAL;
   3609      1.19    dyoung 		}
   3610      1.19    dyoung 		ieee80211_key_update_end(ic);
   3611      1.19    dyoung 
   3612      1.19    dyoung 		if (error)
   3613      1.19    dyoung 			break;
   3614      1.19    dyoung 
   3615      1.19    dyoung 		/* delete keys */
   3616      1.19    dyoung 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
   3617      1.19    dyoung 			klen = nwkey->i_key[kid].i_keylen;
   3618      1.19    dyoung 			k = &ic->ic_nw_keys[kid];
   3619      1.19    dyoung 			if (klen <= 0)
   3620      1.19    dyoung 				(void)ieee80211_crypto_delkey(ic, k);
   3621      1.19    dyoung 		}
   3622      1.19    dyoung 
   3623      1.19    dyoung 		/* set transmit key */
   3624      1.19    dyoung 		kid = nwkey->i_defkid - 1;
   3625      1.19    dyoung 		if (ic->ic_def_txkey != kid) {
   3626      1.19    dyoung 			ic->ic_def_txkey = kid;
   3627      1.19    dyoung 			error = ENETRESET;
   3628      1.19    dyoung 		}
   3629      1.19    dyoung 		oflags = ic->ic_flags;
   3630      1.19    dyoung 		if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
   3631      1.16   mycroft 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
   3632      1.19    dyoung 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
   3633      1.19    dyoung 		} else {
   3634      1.16   mycroft 			ic->ic_flags |= IEEE80211_F_PRIVACY;
   3635      1.19    dyoung 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
   3636       1.2    dyoung 		}
   3637      1.19    dyoung 		if (oflags != ic->ic_flags)
   3638      1.19    dyoung 			error = ENETRESET;
   3639       1.2    dyoung 		break;
   3640       1.2    dyoung 	case SIOCG80211NWKEY:
   3641       1.2    dyoung 		nwkey = (struct ieee80211_nwkey *)data;
   3642      1.16   mycroft 		if (ic->ic_flags & IEEE80211_F_PRIVACY)
   3643       1.2    dyoung 			nwkey->i_wepon = IEEE80211_NWKEY_WEP;
   3644       1.2    dyoung 		else
   3645       1.2    dyoung 			nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
   3646      1.19    dyoung 		nwkey->i_defkid = ic->ic_def_txkey + 1;
   3647       1.2    dyoung 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   3648       1.2    dyoung 			if (nwkey->i_key[i].i_keydat == NULL)
   3649       1.2    dyoung 				continue;
   3650       1.2    dyoung 			/* do not show any keys to non-root user */
   3651      1.41      elad 			if ((error = kauth_authorize_network(curlwp->l_cred,
   3652      1.41      elad 			    KAUTH_NETWORK_INTERFACE,
   3653      1.41      elad 			    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp,
   3654      1.41      elad 			    (void *)cmd, NULL)) != 0)
   3655       1.2    dyoung 				break;
   3656      1.19    dyoung 			nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_keylen;
   3657       1.2    dyoung 			if ((error = copyout(ic->ic_nw_keys[i].wk_key,
   3658       1.2    dyoung 			    nwkey->i_key[i].i_keydat,
   3659      1.19    dyoung 			    ic->ic_nw_keys[i].wk_keylen)) != 0)
   3660       1.2    dyoung 				break;
   3661       1.2    dyoung 		}
   3662       1.2    dyoung 		break;
   3663       1.2    dyoung 	case SIOCS80211POWER:
   3664       1.2    dyoung 		power = (struct ieee80211_power *)data;
   3665       1.2    dyoung 		ic->ic_lintval = power->i_maxsleep;
   3666       1.2    dyoung 		if (power->i_enabled != 0) {
   3667       1.5    dyoung 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
   3668       1.2    dyoung 				error = EINVAL;
   3669       1.2    dyoung 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
   3670       1.2    dyoung 				ic->ic_flags |= IEEE80211_F_PMGTON;
   3671       1.2    dyoung 				error = ENETRESET;
   3672       1.2    dyoung 			}
   3673       1.2    dyoung 		} else {
   3674       1.2    dyoung 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
   3675       1.2    dyoung 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
   3676       1.2    dyoung 				error = ENETRESET;
   3677       1.2    dyoung 			}
   3678       1.2    dyoung 		}
   3679       1.2    dyoung 		break;
   3680       1.2    dyoung 	case SIOCG80211POWER:
   3681       1.2    dyoung 		power = (struct ieee80211_power *)data;
   3682       1.2    dyoung 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
   3683       1.2    dyoung 		power->i_maxsleep = ic->ic_lintval;
   3684       1.2    dyoung 		break;
   3685       1.2    dyoung 	case SIOCS80211BSSID:
   3686       1.2    dyoung 		bssid = (struct ieee80211_bssid *)data;
   3687      1.29    dyoung 		IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
   3688      1.29    dyoung 		if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
   3689       1.2    dyoung 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
   3690      1.29    dyoung 		else
   3691       1.2    dyoung 			ic->ic_flags |= IEEE80211_F_DESBSSID;
   3692      1.29    dyoung 		error = ENETRESET;
   3693       1.2    dyoung 		break;
   3694       1.2    dyoung 	case SIOCG80211BSSID:
   3695       1.2    dyoung 		bssid = (struct ieee80211_bssid *)data;
   3696       1.2    dyoung 		switch (ic->ic_state) {
   3697       1.2    dyoung 		case IEEE80211_S_INIT:
   3698       1.2    dyoung 		case IEEE80211_S_SCAN:
   3699       1.2    dyoung 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
   3700       1.2    dyoung 				IEEE80211_ADDR_COPY(bssid->i_bssid,
   3701       1.2    dyoung 				    ic->ic_myaddr);
   3702       1.2    dyoung 			else if (ic->ic_flags & IEEE80211_F_DESBSSID)
   3703       1.2    dyoung 				IEEE80211_ADDR_COPY(bssid->i_bssid,
   3704       1.2    dyoung 				    ic->ic_des_bssid);
   3705       1.2    dyoung 			else
   3706       1.2    dyoung 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
   3707       1.2    dyoung 			break;
   3708       1.2    dyoung 		default:
   3709       1.2    dyoung 			IEEE80211_ADDR_COPY(bssid->i_bssid,
   3710       1.2    dyoung 			    ic->ic_bss->ni_bssid);
   3711       1.2    dyoung 			break;
   3712       1.2    dyoung 		}
   3713       1.2    dyoung 		break;
   3714       1.2    dyoung 	case SIOCS80211CHANNEL:
   3715       1.2    dyoung 		chanreq = (struct ieee80211chanreq *)data;
   3716       1.2    dyoung 		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
   3717       1.2    dyoung 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
   3718       1.2    dyoung 		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
   3719       1.2    dyoung 		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
   3720       1.2    dyoung 			error = EINVAL;
   3721       1.2    dyoung 			break;
   3722       1.2    dyoung 		} else
   3723  1.48.4.1     skrll 			ic->ic_bsschan = ic->ic_des_chan =
   3724       1.4    dyoung 			    &ic->ic_channels[chanreq->i_channel];
   3725       1.2    dyoung 		switch (ic->ic_state) {
   3726       1.2    dyoung 		case IEEE80211_S_INIT:
   3727       1.2    dyoung 		case IEEE80211_S_SCAN:
   3728       1.2    dyoung 			error = ENETRESET;
   3729       1.2    dyoung 			break;
   3730       1.2    dyoung 		default:
   3731       1.2    dyoung 			if (ic->ic_opmode == IEEE80211_M_STA) {
   3732       1.2    dyoung 				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
   3733       1.2    dyoung 				    ic->ic_bss->ni_chan != ic->ic_des_chan)
   3734       1.2    dyoung 					error = ENETRESET;
   3735       1.2    dyoung 			} else {
   3736  1.48.4.1     skrll 				if (ic->ic_bss->ni_chan != ic->ic_bsschan)
   3737       1.2    dyoung 					error = ENETRESET;
   3738       1.2    dyoung 			}
   3739       1.2    dyoung 			break;
   3740       1.2    dyoung 		}
   3741       1.2    dyoung 		break;
   3742       1.2    dyoung 	case SIOCG80211CHANNEL:
   3743       1.2    dyoung 		chanreq = (struct ieee80211chanreq *)data;
   3744       1.2    dyoung 		switch (ic->ic_state) {
   3745       1.2    dyoung 		case IEEE80211_S_INIT:
   3746       1.2    dyoung 		case IEEE80211_S_SCAN:
   3747       1.2    dyoung 			if (ic->ic_opmode == IEEE80211_M_STA)
   3748       1.2    dyoung 				chan = ic->ic_des_chan;
   3749       1.2    dyoung 			else
   3750  1.48.4.1     skrll 				chan = ic->ic_bsschan;
   3751       1.2    dyoung 			break;
   3752       1.2    dyoung 		default:
   3753      1.39  christos 			chan = ic->ic_curchan;
   3754       1.2    dyoung 			break;
   3755       1.2    dyoung 		}
   3756       1.2    dyoung 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
   3757       1.2    dyoung 		break;
   3758       1.2    dyoung 	case SIOCGIFGENERIC:
   3759      1.19    dyoung 		error = ieee80211_cfgget(ic, cmd, data);
   3760       1.2    dyoung 		break;
   3761       1.2    dyoung 	case SIOCSIFGENERIC:
   3762      1.41      elad 		error = kauth_authorize_network(curlwp->l_cred,
   3763      1.41      elad 		    KAUTH_NETWORK_INTERFACE,
   3764      1.41      elad 		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
   3765      1.41      elad 		    NULL);
   3766       1.2    dyoung 		if (error)
   3767       1.2    dyoung 			break;
   3768      1.19    dyoung 		error = ieee80211_cfgset(ic, cmd, data);
   3769       1.7    dyoung 		break;
   3770      1.22    dyoung #ifdef COMPAT_20
   3771      1.22    dyoung 	case OSIOCG80211STATS:
   3772      1.22    dyoung 	case OSIOCG80211ZSTATS:
   3773      1.22    dyoung 		ifr = (struct ifreq *)data;
   3774      1.22    dyoung 		s = splnet();
   3775      1.22    dyoung 		ieee80211_get_ostats(&ostats, &ic->ic_stats);
   3776      1.22    dyoung 		error = copyout(&ostats, ifr->ifr_data, sizeof(ostats));
   3777      1.22    dyoung 		if (error == 0 && cmd == OSIOCG80211ZSTATS)
   3778      1.22    dyoung 			(void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
   3779      1.22    dyoung 		splx(s);
   3780      1.22    dyoung 		break;
   3781      1.22    dyoung #endif /* COMPAT_20 */
   3782      1.17    dyoung 	case SIOCG80211ZSTATS:
   3783       1.7    dyoung 	case SIOCG80211STATS:
   3784       1.7    dyoung 		ifr = (struct ifreq *)data;
   3785      1.17    dyoung 		s = splnet();
   3786      1.22    dyoung 		error = copyout(&ic->ic_stats, ifr->ifr_buf,
   3787      1.22    dyoung 		    MIN(sizeof(ic->ic_stats), ifr->ifr_buflen));
   3788      1.22    dyoung 		if (error == 0 && cmd == SIOCG80211ZSTATS)
   3789      1.17    dyoung 			(void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
   3790      1.17    dyoung 		splx(s);
   3791       1.2    dyoung 		break;
   3792      1.10    dyoung 	case SIOCSIFMTU:
   3793      1.10    dyoung 		ifr = (struct ifreq *)data;
   3794      1.48    dyoung 		if (ifr->ifr_mtu < IEEE80211_MTU_MIN &&
   3795      1.48    dyoung 		    ifr->ifr_mtu > IEEE80211_MTU_MAX)
   3796      1.10    dyoung 			error = EINVAL;
   3797      1.48    dyoung 		else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
   3798      1.48    dyoung 			error = 0;
   3799      1.10    dyoung 		break;
   3800       1.2    dyoung 	default:
   3801       1.2    dyoung 		error = ether_ioctl(ifp, cmd, data);
   3802       1.2    dyoung 		break;
   3803       1.2    dyoung 	}
   3804       1.2    dyoung 	return error;
   3805       1.2    dyoung }
   3806       1.2    dyoung #endif /* __NetBSD__ */
   3807