Home | History | Annotate | Line # | Download | only in net80211
ieee80211_ioctl.c revision 1.2
      1 /*-
      2  * Copyright (c) 2001 Atsushi Onoe
      3  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * Alternatively, this software may be distributed under the terms of the
     18  * GNU General Public License ("GPL") version 2 as published by the Free
     19  * Software Foundation.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.4 2003/07/20 21:36:08 sam Exp $");
     35 
     36 /*
     37  * IEEE 802.11 ioctl support (FreeBSD-specific)
     38  */
     39 
     40 #include <sys/endian.h>
     41 #include <sys/param.h>
     42 #include <sys/kernel.h>
     43 #include <sys/socket.h>
     44 #include <sys/sockio.h>
     45 #include <sys/systm.h>
     46 
     47 #include <net/if.h>
     48 #include <net/if_arp.h>
     49 #include <net/if_media.h>
     50 #ifdef __FreeBSD__
     51 #include <net/ethernet.h>
     52 #endif
     53 
     54 #include <net80211/ieee80211_var.h>
     55 #include <net80211/ieee80211_ioctl.h>
     56 
     57 #include <dev/wi/if_wavelan_ieee.h>
     58 
     59 /*
     60  * XXX
     61  * Wireless LAN specific configuration interface, which is compatible
     62  * with wicontrol(8).
     63  */
     64 
     65 int
     66 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
     67 {
     68 	struct ieee80211com *ic = (void *)ifp;
     69 	int i, j, error;
     70 	struct ifreq *ifr = (struct ifreq *)data;
     71 	struct wi_req wreq;
     72 	struct wi_ltv_keys *keys;
     73 	struct wi_apinfo *ap;
     74 	struct ieee80211_node *ni;
     75 	struct ieee80211_rateset *rs;
     76 	struct wi_sigcache wsc;
     77 	struct wi_scan_p2_hdr *p2;
     78 	struct wi_scan_res *res;
     79 
     80 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
     81 	if (error)
     82 		return error;
     83 	wreq.wi_len = 0;
     84 	switch (wreq.wi_type) {
     85 	case WI_RID_SERIALNO:
     86 		/* nothing appropriate */
     87 		break;
     88 	case WI_RID_NODENAME:
     89 		strcpy((char *)&wreq.wi_val[1], hostname);
     90 		wreq.wi_val[0] = htole16(strlen(hostname));
     91 		wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
     92 		break;
     93 	case WI_RID_CURRENT_SSID:
     94 		if (ic->ic_state != IEEE80211_S_RUN) {
     95 			wreq.wi_val[0] = 0;
     96 			wreq.wi_len = 1;
     97 			break;
     98 		}
     99 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
    100 		memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
    101 		    ic->ic_bss->ni_esslen);
    102 		wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
    103 		break;
    104 	case WI_RID_OWN_SSID:
    105 	case WI_RID_DESIRED_SSID:
    106 		wreq.wi_val[0] = htole16(ic->ic_des_esslen);
    107 		memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
    108 		wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
    109 		break;
    110 	case WI_RID_CURRENT_BSSID:
    111 		if (ic->ic_state == IEEE80211_S_RUN)
    112 			IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
    113 		else
    114 			memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
    115 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
    116 		break;
    117 	case WI_RID_CHANNEL_LIST:
    118 		memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
    119 		/*
    120 		 * Since channel 0 is not available for DS, channel 1
    121 		 * is assigned to LSB on WaveLAN.
    122 		 */
    123 		if (ic->ic_phytype == IEEE80211_T_DS)
    124 			i = 1;
    125 		else
    126 			i = 0;
    127 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
    128 			if (isset(ic->ic_chan_active, i)) {
    129 				setbit((u_int8_t *)wreq.wi_val, j);
    130 				wreq.wi_len = j / 16 + 1;
    131 			}
    132 		break;
    133 	case WI_RID_OWN_CHNL:
    134 		wreq.wi_val[0] = htole16(
    135 			ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
    136 		wreq.wi_len = 1;
    137 		break;
    138 	case WI_RID_CURRENT_CHAN:
    139 		wreq.wi_val[0] = htole16(
    140 			ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
    141 		wreq.wi_len = 1;
    142 		break;
    143 	case WI_RID_COMMS_QUALITY:
    144 		wreq.wi_val[0] = 0;				/* quality */
    145 		wreq.wi_val[1] = htole16(ic->ic_bss->ni_rssi);	/* signal */
    146 		wreq.wi_val[2] = 0;				/* noise */
    147 		wreq.wi_len = 3;
    148 		break;
    149 	case WI_RID_PROMISC:
    150 		wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
    151 		wreq.wi_len = 1;
    152 		break;
    153 	case WI_RID_PORTTYPE:
    154 		wreq.wi_val[0] = htole16(ic->ic_opmode);
    155 		wreq.wi_len = 1;
    156 		break;
    157 	case WI_RID_MAC_NODE:
    158 		IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
    159 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
    160 		break;
    161 	case WI_RID_TX_RATE:
    162 		if (ic->ic_fixed_rate == -1)
    163 			wreq.wi_val[0] = 0;	/* auto */
    164 		else
    165 			wreq.wi_val[0] = htole16(
    166 			    (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
    167 			    IEEE80211_RATE_VAL) / 2);
    168 		wreq.wi_len = 1;
    169 		break;
    170 	case WI_RID_CUR_TX_RATE:
    171 		wreq.wi_val[0] = htole16(
    172 		    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
    173 		    IEEE80211_RATE_VAL) / 2);
    174 		wreq.wi_len = 1;
    175 		break;
    176 	case WI_RID_RTS_THRESH:
    177 		wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
    178 		wreq.wi_len = 1;
    179 		break;
    180 	case WI_RID_CREATE_IBSS:
    181 		wreq.wi_val[0] =
    182 		    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
    183 		wreq.wi_len = 1;
    184 		break;
    185 	case WI_RID_MICROWAVE_OVEN:
    186 		wreq.wi_val[0] = 0;	/* no ... not supported */
    187 		wreq.wi_len = 1;
    188 		break;
    189 	case WI_RID_ROAMING_MODE:
    190 		wreq.wi_val[0] = htole16(1);	/* enabled ... not supported */
    191 		wreq.wi_len = 1;
    192 		break;
    193 	case WI_RID_SYSTEM_SCALE:
    194 		wreq.wi_val[0] = htole16(1);	/* low density ... not supp */
    195 		wreq.wi_len = 1;
    196 		break;
    197 	case WI_RID_PM_ENABLED:
    198 		wreq.wi_val[0] =
    199 		    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
    200 		wreq.wi_len = 1;
    201 		break;
    202 	case WI_RID_MAX_SLEEP:
    203 		wreq.wi_val[0] = htole16(ic->ic_lintval);
    204 		wreq.wi_len = 1;
    205 		break;
    206 	case WI_RID_CUR_BEACON_INT:
    207 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
    208 		wreq.wi_len = 1;
    209 		break;
    210 	case WI_RID_WEP_AVAIL:
    211 		wreq.wi_val[0] =
    212 		    htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
    213 		wreq.wi_len = 1;
    214 		break;
    215 	case WI_RID_CNFAUTHMODE:
    216 		wreq.wi_val[0] = htole16(1);	/* TODO: open system only */
    217 		wreq.wi_len = 1;
    218 		break;
    219 	case WI_RID_ENCRYPTION:
    220 		wreq.wi_val[0] =
    221 		    htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
    222 		wreq.wi_len = 1;
    223 		break;
    224 	case WI_RID_TX_CRYPT_KEY:
    225 		wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
    226 		wreq.wi_len = 1;
    227 		break;
    228 	case WI_RID_DEFLT_CRYPT_KEYS:
    229 		keys = (struct wi_ltv_keys *)&wreq;
    230 		/* do not show keys to non-root user */
    231 		error = suser(curthread);
    232 		if (error) {
    233 			memset(keys, 0, sizeof(*keys));
    234 			error = 0;
    235 			break;
    236 		}
    237 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    238 			keys->wi_keys[i].wi_keylen =
    239 			    htole16(ic->ic_nw_keys[i].wk_len);
    240 			memcpy(keys->wi_keys[i].wi_keydat,
    241 			    ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
    242 		}
    243 		wreq.wi_len = sizeof(*keys) / 2;
    244 		break;
    245 	case WI_RID_MAX_DATALEN:
    246 		wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);	/* TODO: frag */
    247 		wreq.wi_len = 1;
    248 		break;
    249 	case WI_RID_IFACE_STATS:
    250 		/* XXX: should be implemented in lower drivers */
    251 		break;
    252 	case WI_RID_READ_APS:
    253 		if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
    254 			/*
    255 			 * Don't return results until active scan completes.
    256 			 */
    257 			if (ic->ic_state == IEEE80211_S_SCAN &&
    258 			    (ic->ic_flags & IEEE80211_F_ASCAN)) {
    259 				error = EINPROGRESS;
    260 				break;
    261 			}
    262 		}
    263 		i = 0;
    264 		ap = (void *)((char *)wreq.wi_val + sizeof(i));
    265 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    266 			if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
    267 				break;
    268 			memset(ap, 0, sizeof(*ap));
    269 			if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
    270 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
    271 				ap->namelen = ic->ic_des_esslen;
    272 				if (ic->ic_des_esslen)
    273 					memcpy(ap->name, ic->ic_des_essid,
    274 					    ic->ic_des_esslen);
    275 			} else {
    276 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
    277 				ap->namelen = ni->ni_esslen;
    278 				if (ni->ni_esslen)
    279 					memcpy(ap->name, ni->ni_essid,
    280 					    ni->ni_esslen);
    281 			}
    282 			ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
    283 			ap->signal = ni->ni_rssi;
    284 			ap->capinfo = ni->ni_capinfo;
    285 			ap->interval = ni->ni_intval;
    286 			rs = &ni->ni_rates;
    287 			for (j = 0; j < rs->rs_nrates; j++) {
    288 				if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
    289 					ap->rate = (rs->rs_rates[j] &
    290 					    IEEE80211_RATE_VAL) * 5; /* XXX */
    291 				}
    292 			}
    293 			i++;
    294 			ap++;
    295 		}
    296 		memcpy(wreq.wi_val, &i, sizeof(i));
    297 		wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
    298 		break;
    299 	case WI_RID_PRISM2:
    300 		wreq.wi_val[0] = 1;	/* XXX lie so SCAN_RES can give rates */
    301 		wreq.wi_len = sizeof(u_int16_t) / 2;
    302 		break;
    303 	case WI_RID_SCAN_RES:			/* compatibility interface */
    304 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
    305 		    ic->ic_state == IEEE80211_S_SCAN) {
    306 			error = EINPROGRESS;
    307 			break;
    308 		}
    309 		/* NB: we use the Prism2 format so we can return rate info */
    310 		p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
    311 		res = (void *)&p2[1];
    312 		i = 0;
    313 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    314 			if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
    315 				break;
    316 			res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
    317 			res->wi_noise = 0;
    318 			res->wi_signal = ni->ni_rssi;
    319 			IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
    320 			res->wi_interval = ni->ni_intval;
    321 			res->wi_capinfo = ni->ni_capinfo;
    322 			res->wi_ssid_len = ni->ni_esslen;
    323 			memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
    324 			/* NB: assumes wi_srates holds <= ni->ni_rates */
    325 			memcpy(res->wi_srates, ni->ni_rates.rs_rates,
    326 				sizeof(res->wi_srates));
    327 			if (ni->ni_rates.rs_nrates < 10)
    328 				res->wi_srates[ni->ni_rates.rs_nrates] = 0;
    329 			res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
    330 			res->wi_rsvd = 0;
    331 			res++, i++;
    332 		}
    333 		p2->wi_rsvd = 0;
    334 		p2->wi_reason = i;
    335 		wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
    336 		break;
    337 	case WI_RID_READ_CACHE:
    338 		i = 0;
    339 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    340 			if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
    341 				break;
    342 			IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
    343 			memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
    344 			wsc.signal = ni->ni_rssi;
    345 			wsc.noise = 0;
    346 			wsc.quality = 0;
    347 			memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
    348 			    &wsc, sizeof(wsc));
    349 			i++;
    350 		}
    351 		wreq.wi_len = sizeof(wsc) * i / 2;
    352 		break;
    353 	case WI_RID_SCAN_APS:
    354 		error = EINVAL;
    355 		break;
    356 	default:
    357 		error = EINVAL;
    358 		break;
    359 	}
    360 	if (error == 0) {
    361 		wreq.wi_len++;
    362 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
    363 	}
    364 	return error;
    365 }
    366 
    367 static int
    368 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    369 {
    370 #define	IEEERATE(_ic,_m,_i) \
    371 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
    372 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
    373 	for (i = 0; i < nrates; i++)
    374 		if (IEEERATE(ic, mode, i) == rate)
    375 			return i;
    376 	return -1;
    377 #undef IEEERATE
    378 }
    379 
    380 int
    381 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
    382 {
    383 	struct ieee80211com *ic = (void *)ifp;
    384 	int i, j, len, error, rate;
    385 	struct ifreq *ifr = (struct ifreq *)data;
    386 	struct wi_ltv_keys *keys;
    387 	struct wi_req wreq;
    388 	u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
    389 
    390 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
    391 	if (error)
    392 		return error;
    393 	len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
    394 	switch (wreq.wi_type) {
    395 	case WI_RID_SERIALNO:
    396 	case WI_RID_NODENAME:
    397 		return EPERM;
    398 	case WI_RID_CURRENT_SSID:
    399 		return EPERM;
    400 	case WI_RID_OWN_SSID:
    401 	case WI_RID_DESIRED_SSID:
    402 		if (le16toh(wreq.wi_val[0]) * 2 > len ||
    403 		    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
    404 			error = ENOSPC;
    405 			break;
    406 		}
    407 		memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
    408 		ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
    409 		memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
    410 		error = ENETRESET;
    411 		break;
    412 	case WI_RID_CURRENT_BSSID:
    413 		return EPERM;
    414 	case WI_RID_OWN_CHNL:
    415 		if (len != 2)
    416 			return EINVAL;
    417 		i = le16toh(wreq.wi_val[0]);
    418 		if (i < 0 ||
    419 		    i > IEEE80211_CHAN_MAX ||
    420 		    isclr(ic->ic_chan_active, i))
    421 			return EINVAL;
    422 		ic->ic_ibss_chan = &ic->ic_channels[i];
    423 		if (ic->ic_flags & IEEE80211_F_SIBSS)
    424 			error = ENETRESET;
    425 		break;
    426 	case WI_RID_CURRENT_CHAN:
    427 		return EPERM;
    428 	case WI_RID_COMMS_QUALITY:
    429 		return EPERM;
    430 	case WI_RID_PROMISC:
    431 		if (len != 2)
    432 			return EINVAL;
    433 		if (ifp->if_flags & IFF_PROMISC) {
    434 			if (wreq.wi_val[0] == 0) {
    435 				ifp->if_flags &= ~IFF_PROMISC;
    436 				error = ENETRESET;
    437 			}
    438 		} else {
    439 			if (wreq.wi_val[0] != 0) {
    440 				ifp->if_flags |= IFF_PROMISC;
    441 				error = ENETRESET;
    442 			}
    443 		}
    444 		break;
    445 	case WI_RID_PORTTYPE:
    446 		if (len != 2)
    447 			return EINVAL;
    448 		switch (le16toh(wreq.wi_val[0])) {
    449 		case IEEE80211_M_STA:
    450 			break;
    451 		case IEEE80211_M_IBSS:
    452 			if (!(ic->ic_caps & IEEE80211_C_IBSS))
    453 				return EINVAL;
    454 			break;
    455 		case IEEE80211_M_AHDEMO:
    456 			if (ic->ic_phytype != IEEE80211_T_DS ||
    457 			    !(ic->ic_caps & IEEE80211_C_AHDEMO))
    458 				return EINVAL;
    459 			break;
    460 		case IEEE80211_M_HOSTAP:
    461 			if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
    462 				return EINVAL;
    463 			break;
    464 		default:
    465 			return EINVAL;
    466 		}
    467 		if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
    468 			ic->ic_opmode = le16toh(wreq.wi_val[0]);
    469 			error = ENETRESET;
    470 		}
    471 		break;
    472 #if 0
    473 	case WI_RID_MAC_NODE:
    474 		if (len != IEEE80211_ADDR_LEN)
    475 			return EINVAL;
    476 		IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
    477 		/* if_init will copy lladdr into ic_myaddr */
    478 		error = ENETRESET;
    479 		break;
    480 #endif
    481 	case WI_RID_TX_RATE:
    482 		if (len != 2)
    483 			return EINVAL;
    484 		if (wreq.wi_val[0] == 0) {
    485 			/* auto */
    486 			ic->ic_fixed_rate = -1;
    487 			break;
    488 		}
    489 		rate = 2 * le16toh(wreq.wi_val[0]);
    490 		if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
    491 			/*
    492 			 * In autoselect mode search for the rate.  We take
    493 			 * the first instance which may not be right, but we
    494 			 * are limited by the interface.  Note that we also
    495 			 * lock the mode to insure the rate is meaningful
    496 			 * when it is used.
    497 			 */
    498 			for (j = IEEE80211_MODE_11A;
    499 			     j < IEEE80211_MODE_MAX; j++) {
    500 				if ((ic->ic_modecaps & (1<<j)) == 0)
    501 					continue;
    502 				i = findrate(ic, j, rate);
    503 				if (i != -1) {
    504 					/* lock mode too */
    505 					ic->ic_curmode = j;
    506 					goto setrate;
    507 				}
    508 			}
    509 		} else {
    510 			i = findrate(ic, ic->ic_curmode, rate);
    511 			if (i != -1)
    512 				goto setrate;
    513 		}
    514 		return EINVAL;
    515 	setrate:
    516 		ic->ic_fixed_rate = i;
    517 		error = ENETRESET;
    518 		break;
    519 	case WI_RID_CUR_TX_RATE:
    520 		return EPERM;
    521 	case WI_RID_RTS_THRESH:
    522 		if (len != 2)
    523 			return EINVAL;
    524 		if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
    525 			return EINVAL;		/* TODO: RTS */
    526 		break;
    527 	case WI_RID_CREATE_IBSS:
    528 		if (len != 2)
    529 			return EINVAL;
    530 		if (wreq.wi_val[0] != 0) {
    531 			if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
    532 				return EINVAL;
    533 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
    534 				ic->ic_flags |= IEEE80211_F_IBSSON;
    535 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
    536 				    ic->ic_state == IEEE80211_S_SCAN)
    537 					error = ENETRESET;
    538 			}
    539 		} else {
    540 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
    541 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
    542 				if (ic->ic_flags & IEEE80211_F_SIBSS) {
    543 					ic->ic_flags &= ~IEEE80211_F_SIBSS;
    544 					error = ENETRESET;
    545 				}
    546 			}
    547 		}
    548 		break;
    549 	case WI_RID_MICROWAVE_OVEN:
    550 		if (len != 2)
    551 			return EINVAL;
    552 		if (wreq.wi_val[0] != 0)
    553 			return EINVAL;		/* not supported */
    554 		break;
    555 	case WI_RID_ROAMING_MODE:
    556 		if (len != 2)
    557 			return EINVAL;
    558 		if (le16toh(wreq.wi_val[0]) != 1)
    559 			return EINVAL;		/* not supported */
    560 		break;
    561 	case WI_RID_SYSTEM_SCALE:
    562 		if (len != 2)
    563 			return EINVAL;
    564 		if (le16toh(wreq.wi_val[0]) != 1)
    565 			return EINVAL;		/* not supported */
    566 		break;
    567 	case WI_RID_PM_ENABLED:
    568 		if (len != 2)
    569 			return EINVAL;
    570 		if (wreq.wi_val[0] != 0) {
    571 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    572 				return EINVAL;
    573 			if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
    574 				ic->ic_flags |= IEEE80211_F_PMGTON;
    575 				error = ENETRESET;
    576 			}
    577 		} else {
    578 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
    579 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
    580 				error = ENETRESET;
    581 			}
    582 		}
    583 		break;
    584 	case WI_RID_MAX_SLEEP:
    585 		if (len != 2)
    586 			return EINVAL;
    587 		ic->ic_lintval = le16toh(wreq.wi_val[0]);
    588 		if (ic->ic_flags & IEEE80211_F_PMGTON)
    589 			error = ENETRESET;
    590 		break;
    591 	case WI_RID_CUR_BEACON_INT:
    592 		return EPERM;
    593 	case WI_RID_WEP_AVAIL:
    594 		return EPERM;
    595 	case WI_RID_CNFAUTHMODE:
    596 		if (len != 2)
    597 			return EINVAL;
    598 		if (le16toh(wreq.wi_val[0]) != 1)
    599 			return EINVAL;		/* TODO: shared key auth */
    600 		break;
    601 	case WI_RID_ENCRYPTION:
    602 		if (len != 2)
    603 			return EINVAL;
    604 		if (wreq.wi_val[0] != 0) {
    605 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    606 				return EINVAL;
    607 			if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
    608 				ic->ic_flags |= IEEE80211_F_WEPON;
    609 				error = ENETRESET;
    610 			}
    611 		} else {
    612 			if (ic->ic_flags & IEEE80211_F_WEPON) {
    613 				ic->ic_flags &= ~IEEE80211_F_WEPON;
    614 				error = ENETRESET;
    615 			}
    616 		}
    617 		break;
    618 	case WI_RID_TX_CRYPT_KEY:
    619 		if (len != 2)
    620 			return EINVAL;
    621 		i = le16toh(wreq.wi_val[0]);
    622 		if (i >= IEEE80211_WEP_NKID)
    623 			return EINVAL;
    624 		ic->ic_wep_txkey = i;
    625 		break;
    626 	case WI_RID_DEFLT_CRYPT_KEYS:
    627 		if (len != sizeof(struct wi_ltv_keys))
    628 			return EINVAL;
    629 		keys = (struct wi_ltv_keys *)&wreq;
    630 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    631 			len = le16toh(keys->wi_keys[i].wi_keylen);
    632 			if (len != 0 && len < IEEE80211_WEP_KEYLEN)
    633 				return EINVAL;
    634 			if (len > sizeof(ic->ic_nw_keys[i].wk_key))
    635 				return EINVAL;
    636 		}
    637 		memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
    638 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    639 			len = le16toh(keys->wi_keys[i].wi_keylen);
    640 			ic->ic_nw_keys[i].wk_len = len;
    641 			memcpy(ic->ic_nw_keys[i].wk_key,
    642 			    keys->wi_keys[i].wi_keydat, len);
    643 		}
    644 		error = ENETRESET;
    645 		break;
    646 	case WI_RID_MAX_DATALEN:
    647 		if (len != 2)
    648 			return EINVAL;
    649 		len = le16toh(wreq.wi_val[0]);
    650 		if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
    651 			return EINVAL;
    652 		if (len != IEEE80211_MAX_LEN)
    653 			return EINVAL;		/* TODO: fragment */
    654 		ic->ic_fragthreshold = len;
    655 		error = ENETRESET;
    656 		break;
    657 	case WI_RID_IFACE_STATS:
    658 		error = EPERM;
    659 		break;
    660 	case WI_RID_SCAN_REQ:			/* XXX wicontrol */
    661 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    662 			break;
    663 		/* NB: ignore channel list and tx rate parameters */
    664 		error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    665 		break;
    666 	case WI_RID_SCAN_APS:
    667 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    668 			break;
    669 		len--;			/* XXX: tx rate? */
    670 		/* FALLTHRU */
    671 	case WI_RID_CHANNEL_LIST:
    672 		memset(chanlist, 0, sizeof(chanlist));
    673 		/*
    674 		 * Since channel 0 is not available for DS, channel 1
    675 		 * is assigned to LSB on WaveLAN.
    676 		 */
    677 		if (ic->ic_phytype == IEEE80211_T_DS)
    678 			i = 1;
    679 		else
    680 			i = 0;
    681 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
    682 			if ((j / 8) >= len)
    683 				break;
    684 			if (isclr((u_int8_t *)wreq.wi_val, j))
    685 				continue;
    686 			if (isclr(ic->ic_chan_active, i)) {
    687 				if (wreq.wi_type != WI_RID_CHANNEL_LIST)
    688 					continue;
    689 				if (isclr(ic->ic_chan_avail, i))
    690 					return EPERM;
    691 			}
    692 			setbit(chanlist, i);
    693 		}
    694 		memcpy(ic->ic_chan_active, chanlist,
    695 		    sizeof(ic->ic_chan_active));
    696 		if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
    697 			for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
    698 				if (isset(chanlist, i)) {
    699 					ic->ic_ibss_chan = &ic->ic_channels[i];
    700 					break;
    701 				}
    702 		}
    703 		if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
    704 			ic->ic_bss->ni_chan = ic->ic_ibss_chan;
    705 		if (wreq.wi_type == WI_RID_CHANNEL_LIST)
    706 			error = ENETRESET;
    707 		else
    708 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    709 		break;
    710 	default:
    711 		error = EINVAL;
    712 		break;
    713 	}
    714 	return error;
    715 }
    716 
    717 #ifdef __FreeBSD__
    718 int
    719 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    720 {
    721 	struct ieee80211com *ic = (void *)ifp;
    722 	int error = 0;
    723 	u_int kid, len;
    724 	struct ieee80211req *ireq;
    725 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
    726 	char tmpssid[IEEE80211_NWID_LEN];
    727 	struct ieee80211_channel *chan;
    728 
    729 	switch (cmd) {
    730 	case SIOCSIFMEDIA:
    731 	case SIOCGIFMEDIA:
    732 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
    733 				&ic->ic_media, cmd);
    734 		break;
    735 	case SIOCG80211:
    736 		ireq = (struct ieee80211req *) data;
    737 		switch (ireq->i_type) {
    738 		case IEEE80211_IOC_SSID:
    739 			switch (ic->ic_state) {
    740 			case IEEE80211_S_INIT:
    741 			case IEEE80211_S_SCAN:
    742 				ireq->i_len = ic->ic_des_esslen;
    743 				memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
    744 				break;
    745 			default:
    746 				ireq->i_len = ic->ic_bss->ni_esslen;
    747 				memcpy(tmpssid, ic->ic_bss->ni_essid,
    748 					ireq->i_len);
    749 				break;
    750 			}
    751 			error = copyout(tmpssid, ireq->i_data, ireq->i_len);
    752 			break;
    753 		case IEEE80211_IOC_NUMSSIDS:
    754 			ireq->i_val = 1;
    755 			break;
    756 		case IEEE80211_IOC_WEP:
    757 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    758 				ireq->i_val = IEEE80211_WEP_NOSUP;
    759 			} else {
    760 				if (ic->ic_flags & IEEE80211_F_WEPON) {
    761 					ireq->i_val =
    762 					    IEEE80211_WEP_MIXED;
    763 				} else {
    764 					ireq->i_val =
    765 					    IEEE80211_WEP_OFF;
    766 				}
    767 			}
    768 			break;
    769 		case IEEE80211_IOC_WEPKEY:
    770 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    771 				error = EINVAL;
    772 				break;
    773 			}
    774 			kid = (u_int) ireq->i_val;
    775 			if (kid >= IEEE80211_WEP_NKID) {
    776 				error = EINVAL;
    777 				break;
    778 			}
    779 			len = (u_int) ic->ic_nw_keys[kid].wk_len;
    780 			/* NB: only root can read WEP keys */
    781 			if (suser(curthread)) {
    782 				bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
    783 			} else {
    784 				bzero(tmpkey, len);
    785 			}
    786 			ireq->i_len = len;
    787 			error = copyout(tmpkey, ireq->i_data, len);
    788 			break;
    789 		case IEEE80211_IOC_NUMWEPKEYS:
    790 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    791 				error = EINVAL;
    792 			else
    793 				ireq->i_val = IEEE80211_WEP_NKID;
    794 			break;
    795 		case IEEE80211_IOC_WEPTXKEY:
    796 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    797 				error = EINVAL;
    798 			else
    799 				ireq->i_val = ic->ic_wep_txkey;
    800 			break;
    801 		case IEEE80211_IOC_AUTHMODE:
    802 			ireq->i_val = IEEE80211_AUTH_OPEN;
    803 			break;
    804 		case IEEE80211_IOC_CHANNEL:
    805 			switch (ic->ic_state) {
    806 			case IEEE80211_S_INIT:
    807 			case IEEE80211_S_SCAN:
    808 				if (ic->ic_opmode == IEEE80211_M_STA)
    809 					chan = ic->ic_des_chan;
    810 				else
    811 					chan = ic->ic_ibss_chan;
    812 				break;
    813 			default:
    814 				chan = ic->ic_bss->ni_chan;
    815 				break;
    816 			}
    817 			ireq->i_val = ieee80211_chan2ieee(ic, chan);
    818 			break;
    819 		case IEEE80211_IOC_POWERSAVE:
    820 			if (ic->ic_flags & IEEE80211_F_PMGTON)
    821 				ireq->i_val = IEEE80211_POWERSAVE_ON;
    822 			else
    823 				ireq->i_val = IEEE80211_POWERSAVE_OFF;
    824 			break;
    825 		case IEEE80211_IOC_POWERSAVESLEEP:
    826 			ireq->i_val = ic->ic_lintval;
    827 			break;
    828 		case IEEE80211_IOCT_RTSTHRESHOLD:
    829 			ireq->i_val = ic->ic_rtsthreshold;
    830 			break;
    831 		default:
    832 			error = EINVAL;
    833 		}
    834 		break;
    835 	case SIOCS80211:
    836 		error = suser(curthread);
    837 		if (error)
    838 			break;
    839 		ireq = (struct ieee80211req *) data;
    840 		switch (ireq->i_type) {
    841 		case IEEE80211_IOC_SSID:
    842 			if (ireq->i_val != 0 ||
    843 			    ireq->i_len > IEEE80211_NWID_LEN) {
    844 				error = EINVAL;
    845 				break;
    846 			}
    847 			error = copyin(ireq->i_data, tmpssid, ireq->i_len);
    848 			if (error)
    849 				break;
    850 			memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
    851 			ic->ic_des_esslen = ireq->i_len;
    852 			memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
    853 			error = ENETRESET;
    854 			break;
    855 		case IEEE80211_IOC_WEP:
    856 			/*
    857 			 * These cards only support one mode so
    858 			 * we just turn wep on if what ever is
    859 			 * passed in is not OFF.
    860 			 */
    861 			if (ireq->i_val == IEEE80211_WEP_OFF) {
    862 				ic->ic_flags &= ~IEEE80211_F_WEPON;
    863 			} else {
    864 				ic->ic_flags |= IEEE80211_F_WEPON;
    865 			}
    866 			error = ENETRESET;
    867 			break;
    868 		case IEEE80211_IOC_WEPKEY:
    869 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    870 				error = EINVAL;
    871 				break;
    872 			}
    873 			kid = (u_int) ireq->i_val;
    874 			if (kid >= IEEE80211_WEP_NKID) {
    875 				error = EINVAL;
    876 				break;
    877 			}
    878 			if (ireq->i_len > sizeof(tmpkey)) {
    879 				error = EINVAL;
    880 				break;
    881 			}
    882 			memset(tmpkey, 0, sizeof(tmpkey));
    883 			error = copyin(ireq->i_data, tmpkey, ireq->i_len);
    884 			if (error)
    885 				break;
    886 			memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
    887 				sizeof(tmpkey));
    888 			ic->ic_nw_keys[kid].wk_len = ireq->i_len;
    889 			error = ENETRESET;
    890 			break;
    891 		case IEEE80211_IOC_WEPTXKEY:
    892 			kid = (u_int) ireq->i_val;
    893 			if (kid >= IEEE80211_WEP_NKID) {
    894 				error = EINVAL;
    895 				break;
    896 			}
    897 			ic->ic_wep_txkey = kid;
    898 			error = ENETRESET;
    899 			break;
    900 #if 0
    901 		case IEEE80211_IOC_AUTHMODE:
    902 			sc->wi_authmode = ireq->i_val;
    903 			break;
    904 #endif
    905 		case IEEE80211_IOC_CHANNEL:
    906 			/* XXX 0xffff overflows 16-bit signed */
    907 			if (ireq->i_val == 0 ||
    908 			    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
    909 				ic->ic_des_chan = IEEE80211_CHAN_ANYC;
    910 			else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
    911 			    isclr(ic->ic_chan_active, ireq->i_val)) {
    912 				error = EINVAL;
    913 				break;
    914 			} else
    915 				ic->ic_ibss_chan = ic->ic_des_chan =
    916 					&ic->ic_channels[ireq->i_val];
    917 			switch (ic->ic_state) {
    918 			case IEEE80211_S_INIT:
    919 			case IEEE80211_S_SCAN:
    920 				error = ENETRESET;
    921 				break;
    922 			default:
    923 				if (ic->ic_opmode == IEEE80211_M_STA) {
    924 					if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
    925 					    ic->ic_bss->ni_chan != ic->ic_des_chan)
    926 						error = ENETRESET;
    927 				} else {
    928 					if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
    929 						error = ENETRESET;
    930 				}
    931 				break;
    932 			}
    933 			break;
    934 		case IEEE80211_IOC_POWERSAVE:
    935 			switch (ireq->i_val) {
    936 			case IEEE80211_POWERSAVE_OFF:
    937 				if (ic->ic_flags & IEEE80211_F_PMGTON) {
    938 					ic->ic_flags &= ~IEEE80211_F_PMGTON;
    939 					error = ENETRESET;
    940 				}
    941 				break;
    942 			case IEEE80211_POWERSAVE_ON:
    943 				if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    944 					error = EINVAL;
    945 				else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
    946 					ic->ic_flags |= IEEE80211_F_PMGTON;
    947 					error = ENETRESET;
    948 				}
    949 				break;
    950 			default:
    951 				error = EINVAL;
    952 				break;
    953 			}
    954 			break;
    955 		case IEEE80211_IOC_POWERSAVESLEEP:
    956 			if (ireq->i_val < 0) {
    957 				error = EINVAL;
    958 				break;
    959 			}
    960 			ic->ic_lintval = ireq->i_val;
    961 			error = ENETRESET;
    962 			break;
    963 		case IEEE80211_IOCT_RTSTHRESHOLD:
    964 			if (!(IEEE80211_RTS_MIN < ireq->i_val &&
    965 			      ireq->i_val <= IEEE80211_RTS_MAX + 1)) {
    966 				error = EINVAL;
    967 				break;
    968 			}
    969 			ic->ic_rtsthreshold = ireq->i_val;
    970 			error = ENETRESET;
    971 			break;
    972 		default:
    973 			error = EINVAL;
    974 			break;
    975 		}
    976 		break;
    977 	case SIOCGIFGENERIC:
    978 		error = ieee80211_cfgget(ifp, cmd, data);
    979 		break;
    980 	case SIOCSIFGENERIC:
    981 		error = suser(curthread);
    982 		if (error)
    983 			break;
    984 		error = ieee80211_cfgset(ifp, cmd, data);
    985 		break;
    986 	default:
    987 		error = ether_ioctl(ifp, cmd, data);
    988 		break;
    989 	}
    990 	return error;
    991 }
    992 #endif /* __FreeBSD__ */
    993 
    994 #ifdef __NetBSD__
    995 int
    996 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    997 {
    998 	struct ieee80211com *ic = (void *)ifp;
    999 	struct ifreq *ifr = (struct ifreq *)data;
   1000 	int i, error = 0;
   1001 	struct ieee80211_nwid nwid;
   1002 	struct ieee80211_nwkey *nwkey;
   1003 	struct ieee80211_power *power;
   1004 	struct ieee80211_bssid *bssid;
   1005 	struct ieee80211chanreq *chanreq;
   1006 	struct ieee80211_channel *chan;
   1007 	struct ieee80211_wepkey keys[IEEE80211_WEP_NKID];
   1008 	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
   1009 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
   1010 	};
   1011 
   1012 	switch (cmd) {
   1013 	case SIOCSIFMEDIA:
   1014 	case SIOCGIFMEDIA:
   1015 		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
   1016 		break;
   1017 	case SIOCS80211NWID:
   1018 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
   1019 			break;
   1020 		if (nwid.i_len > IEEE80211_NWID_LEN) {
   1021 			error = EINVAL;
   1022 			break;
   1023 		}
   1024 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
   1025 		ic->ic_des_esslen = nwid.i_len;
   1026 		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
   1027 		error = ENETRESET;
   1028 		break;
   1029 	case SIOCG80211NWID:
   1030 		memset(&nwid, 0, sizeof(nwid));
   1031 		switch (ic->ic_state) {
   1032 		case IEEE80211_S_INIT:
   1033 		case IEEE80211_S_SCAN:
   1034 			nwid.i_len = ic->ic_des_esslen;
   1035 			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
   1036 			break;
   1037 		default:
   1038 			nwid.i_len = ic->ic_bss->ni_esslen;
   1039 			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
   1040 			break;
   1041 		}
   1042 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
   1043 		break;
   1044 	case SIOCS80211NWKEY:
   1045 		nwkey = (struct ieee80211_nwkey *)data;
   1046 		if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0 &&
   1047 		    nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
   1048 			error = EINVAL;
   1049 			break;
   1050 		}
   1051 		/* check and copy keys */
   1052 		memset(keys, 0, sizeof(keys));
   1053 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   1054 			keys[i].wk_len = nwkey->i_key[i].i_keylen;
   1055 			if ((keys[i].wk_len > 0 &&
   1056 			    keys[i].wk_len < IEEE80211_WEP_KEYLEN) ||
   1057 			    keys[i].wk_len > sizeof(keys[i].wk_key)) {
   1058 				error = EINVAL;
   1059 				break;
   1060 			}
   1061 			if (keys[i].wk_len <= 0)
   1062 				continue;
   1063 			if ((error = copyin(nwkey->i_key[i].i_keydat,
   1064 			    keys[i].wk_key, keys[i].wk_len)) != 0)
   1065 				break;
   1066 		}
   1067 		if (error)
   1068 			break;
   1069 		i = nwkey->i_defkid - 1;
   1070 		if (i < 0 || i >= IEEE80211_WEP_NKID ||
   1071 		    keys[i].wk_len == 0 ||
   1072 		    (keys[i].wk_len == -1 && ic->ic_nw_keys[i].wk_len == 0)) {
   1073 			if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
   1074 				error = EINVAL;
   1075 				break;
   1076 			}
   1077 		} else
   1078 			ic->ic_wep_txkey = i;
   1079 		/* save the key */
   1080 		if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN)
   1081 			ic->ic_flags &= ~IEEE80211_F_WEPON;
   1082 		else
   1083 			ic->ic_flags |= IEEE80211_F_WEPON;
   1084 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   1085 			if (keys[i].wk_len < 0)
   1086 				continue;
   1087 			ic->ic_nw_keys[i].wk_len = keys[i].wk_len;
   1088 			memcpy(ic->ic_nw_keys[i].wk_key, keys[i].wk_key,
   1089 			    sizeof(keys[i].wk_key));
   1090 		}
   1091 		error = ENETRESET;
   1092 		break;
   1093 	case SIOCG80211NWKEY:
   1094 		nwkey = (struct ieee80211_nwkey *)data;
   1095 		if (ic->ic_flags & IEEE80211_F_WEPON)
   1096 			nwkey->i_wepon = IEEE80211_NWKEY_WEP;
   1097 		else
   1098 			nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
   1099 		nwkey->i_defkid = ic->ic_wep_txkey + 1;
   1100 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   1101 			if (nwkey->i_key[i].i_keydat == NULL)
   1102 				continue;
   1103 			/* do not show any keys to non-root user */
   1104 			if ((error = suser(curproc->p_ucred,
   1105 			    &curproc->p_acflag)) != 0)
   1106 				break;
   1107 			nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_len;
   1108 			if ((error = copyout(ic->ic_nw_keys[i].wk_key,
   1109 			    nwkey->i_key[i].i_keydat,
   1110 			    ic->ic_nw_keys[i].wk_len)) != 0)
   1111 				break;
   1112 		}
   1113 		break;
   1114 	case SIOCS80211POWER:
   1115 		power = (struct ieee80211_power *)data;
   1116 		ic->ic_lintval = power->i_maxsleep;
   1117 		if (power->i_enabled != 0) {
   1118 			if ((ic->ic_flags & IEEE80211_F_HASPMGT) == 0)
   1119 				error = EINVAL;
   1120 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
   1121 				ic->ic_flags |= IEEE80211_F_PMGTON;
   1122 				error = ENETRESET;
   1123 			}
   1124 		} else {
   1125 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
   1126 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
   1127 				error = ENETRESET;
   1128 			}
   1129 		}
   1130 		break;
   1131 	case SIOCG80211POWER:
   1132 		power = (struct ieee80211_power *)data;
   1133 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
   1134 		power->i_maxsleep = ic->ic_lintval;
   1135 		break;
   1136 	case SIOCS80211BSSID:
   1137 		bssid = (struct ieee80211_bssid *)data;
   1138 		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
   1139 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
   1140 		else {
   1141 			ic->ic_flags |= IEEE80211_F_DESBSSID;
   1142 			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
   1143 		}
   1144 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
   1145 			break;
   1146 		switch (ic->ic_state) {
   1147 		case IEEE80211_S_INIT:
   1148 		case IEEE80211_S_SCAN:
   1149 			error = ENETRESET;
   1150 			break;
   1151 		default:
   1152 			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
   1153 			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
   1154 			    ic->ic_bss->ni_bssid))
   1155 				error = ENETRESET;
   1156 			break;
   1157 		}
   1158 		break;
   1159 	case SIOCG80211BSSID:
   1160 		bssid = (struct ieee80211_bssid *)data;
   1161 		switch (ic->ic_state) {
   1162 		case IEEE80211_S_INIT:
   1163 		case IEEE80211_S_SCAN:
   1164 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
   1165 				IEEE80211_ADDR_COPY(bssid->i_bssid,
   1166 				    ic->ic_myaddr);
   1167 			else if (ic->ic_flags & IEEE80211_F_DESBSSID)
   1168 				IEEE80211_ADDR_COPY(bssid->i_bssid,
   1169 				    ic->ic_des_bssid);
   1170 			else
   1171 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
   1172 			break;
   1173 		default:
   1174 			IEEE80211_ADDR_COPY(bssid->i_bssid,
   1175 			    ic->ic_bss->ni_bssid);
   1176 			break;
   1177 		}
   1178 		break;
   1179 	case SIOCS80211CHANNEL:
   1180 		chanreq = (struct ieee80211chanreq *)data;
   1181 		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
   1182 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
   1183 		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
   1184 		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
   1185 			error = EINVAL;
   1186 			break;
   1187 		} else
   1188 			ic->ic_ibss_chan = ic->ic_des_chan = chanreq->i_channel;
   1189 		switch (ic->ic_state) {
   1190 		case IEEE80211_S_INIT:
   1191 		case IEEE80211_S_SCAN:
   1192 			error = ENETRESET;
   1193 			break;
   1194 		default:
   1195 			if (ic->ic_opmode == IEEE80211_M_STA) {
   1196 				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
   1197 				    ic->ic_bss->ni_chan != ic->ic_des_chan)
   1198 					error = ENETRESET;
   1199 			} else {
   1200 				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
   1201 					error = ENETRESET;
   1202 			}
   1203 			break;
   1204 		}
   1205 		break;
   1206 	case SIOCG80211CHANNEL:
   1207 		chanreq = (struct ieee80211chanreq *)data;
   1208 		switch (ic->ic_state) {
   1209 		case IEEE80211_S_INIT:
   1210 		case IEEE80211_S_SCAN:
   1211 			if (ic->ic_opmode == IEEE80211_M_STA)
   1212 				chan = ic->ic_des_chan;
   1213 			else
   1214 				chan = ic->ic_ibss_chan;
   1215 			break;
   1216 		default:
   1217 			chan = ic->ic_bss->ni_chan;
   1218 			break;
   1219 		}
   1220 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
   1221 		break;
   1222 	case SIOCGIFGENERIC:
   1223 		error = ieee80211_cfgget(ifp, cmd, data);
   1224 		break;
   1225 	case SIOCSIFGENERIC:
   1226 		error = suser(curproc->p_ucred, &curproc->p_acflag);
   1227 		if (error)
   1228 			break;
   1229 		error = ieee80211_cfgset(ifp, cmd, data);
   1230 		break;
   1231 	default:
   1232 		error = ether_ioctl(ifp, cmd, data);
   1233 		break;
   1234 	}
   1235 	return error;
   1236 }
   1237 #endif /* __NetBSD__ */
   1238