Home | History | Annotate | Line # | Download | only in net80211
ieee80211_ioctl.c revision 1.1.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.9 2003/11/13 05:23:58 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 #include <net/ethernet.h>
     51 
     52 #include <net80211/ieee80211_var.h>
     53 #include <net80211/ieee80211_ioctl.h>
     54 
     55 #include <dev/wi/if_wavelan_ieee.h>
     56 
     57 /*
     58  * XXX
     59  * Wireless LAN specific configuration interface, which is compatible
     60  * with wicontrol(8).
     61  */
     62 
     63 int
     64 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
     65 {
     66 	struct ieee80211com *ic = (void *)ifp;
     67 	int i, j, error;
     68 	struct ifreq *ifr = (struct ifreq *)data;
     69 	struct wi_req wreq;
     70 	struct wi_ltv_keys *keys;
     71 	struct wi_apinfo *ap;
     72 	struct ieee80211_node *ni;
     73 	struct ieee80211_rateset *rs;
     74 	struct wi_sigcache wsc;
     75 	struct wi_scan_p2_hdr *p2;
     76 	struct wi_scan_res *res;
     77 
     78 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
     79 	if (error)
     80 		return error;
     81 	wreq.wi_len = 0;
     82 	switch (wreq.wi_type) {
     83 	case WI_RID_SERIALNO:
     84 		/* nothing appropriate */
     85 		break;
     86 	case WI_RID_NODENAME:
     87 		strcpy((char *)&wreq.wi_val[1], hostname);
     88 		wreq.wi_val[0] = htole16(strlen(hostname));
     89 		wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
     90 		break;
     91 	case WI_RID_CURRENT_SSID:
     92 		if (ic->ic_state != IEEE80211_S_RUN) {
     93 			wreq.wi_val[0] = 0;
     94 			wreq.wi_len = 1;
     95 			break;
     96 		}
     97 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
     98 		memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
     99 		    ic->ic_bss->ni_esslen);
    100 		wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
    101 		break;
    102 	case WI_RID_OWN_SSID:
    103 	case WI_RID_DESIRED_SSID:
    104 		wreq.wi_val[0] = htole16(ic->ic_des_esslen);
    105 		memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
    106 		wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
    107 		break;
    108 	case WI_RID_CURRENT_BSSID:
    109 		if (ic->ic_state == IEEE80211_S_RUN)
    110 			IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
    111 		else
    112 			memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
    113 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
    114 		break;
    115 	case WI_RID_CHANNEL_LIST:
    116 		memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
    117 		/*
    118 		 * Since channel 0 is not available for DS, channel 1
    119 		 * is assigned to LSB on WaveLAN.
    120 		 */
    121 		if (ic->ic_phytype == IEEE80211_T_DS)
    122 			i = 1;
    123 		else
    124 			i = 0;
    125 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
    126 			if (isset(ic->ic_chan_active, i)) {
    127 				setbit((u_int8_t *)wreq.wi_val, j);
    128 				wreq.wi_len = j / 16 + 1;
    129 			}
    130 		break;
    131 	case WI_RID_OWN_CHNL:
    132 		wreq.wi_val[0] = htole16(
    133 			ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
    134 		wreq.wi_len = 1;
    135 		break;
    136 	case WI_RID_CURRENT_CHAN:
    137 		wreq.wi_val[0] = htole16(
    138 			ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
    139 		wreq.wi_len = 1;
    140 		break;
    141 	case WI_RID_COMMS_QUALITY:
    142 		wreq.wi_val[0] = 0;				/* quality */
    143 		wreq.wi_val[1] =
    144 			htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
    145 		wreq.wi_val[2] = 0;				/* noise */
    146 		wreq.wi_len = 3;
    147 		break;
    148 	case WI_RID_PROMISC:
    149 		wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
    150 		wreq.wi_len = 1;
    151 		break;
    152 	case WI_RID_PORTTYPE:
    153 		wreq.wi_val[0] = htole16(ic->ic_opmode);
    154 		wreq.wi_len = 1;
    155 		break;
    156 	case WI_RID_MAC_NODE:
    157 		IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
    158 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
    159 		break;
    160 	case WI_RID_TX_RATE:
    161 		if (ic->ic_fixed_rate == -1)
    162 			wreq.wi_val[0] = 0;	/* auto */
    163 		else
    164 			wreq.wi_val[0] = htole16(
    165 			    (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
    166 			    IEEE80211_RATE_VAL) / 2);
    167 		wreq.wi_len = 1;
    168 		break;
    169 	case WI_RID_CUR_TX_RATE:
    170 		wreq.wi_val[0] = htole16(
    171 		    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
    172 		    IEEE80211_RATE_VAL) / 2);
    173 		wreq.wi_len = 1;
    174 		break;
    175 	case WI_RID_RTS_THRESH:
    176 		wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
    177 		wreq.wi_len = 1;
    178 		break;
    179 	case WI_RID_CREATE_IBSS:
    180 		wreq.wi_val[0] =
    181 		    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
    182 		wreq.wi_len = 1;
    183 		break;
    184 	case WI_RID_MICROWAVE_OVEN:
    185 		wreq.wi_val[0] = 0;	/* no ... not supported */
    186 		wreq.wi_len = 1;
    187 		break;
    188 	case WI_RID_ROAMING_MODE:
    189 		wreq.wi_val[0] = htole16(1);	/* enabled ... not supported */
    190 		wreq.wi_len = 1;
    191 		break;
    192 	case WI_RID_SYSTEM_SCALE:
    193 		wreq.wi_val[0] = htole16(1);	/* low density ... not supp */
    194 		wreq.wi_len = 1;
    195 		break;
    196 	case WI_RID_PM_ENABLED:
    197 		wreq.wi_val[0] =
    198 		    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
    199 		wreq.wi_len = 1;
    200 		break;
    201 	case WI_RID_MAX_SLEEP:
    202 		wreq.wi_val[0] = htole16(ic->ic_lintval);
    203 		wreq.wi_len = 1;
    204 		break;
    205 	case WI_RID_CUR_BEACON_INT:
    206 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
    207 		wreq.wi_len = 1;
    208 		break;
    209 	case WI_RID_WEP_AVAIL:
    210 		wreq.wi_val[0] =
    211 		    htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
    212 		wreq.wi_len = 1;
    213 		break;
    214 	case WI_RID_CNFAUTHMODE:
    215 		wreq.wi_val[0] = htole16(1);	/* TODO: open system only */
    216 		wreq.wi_len = 1;
    217 		break;
    218 	case WI_RID_ENCRYPTION:
    219 		wreq.wi_val[0] =
    220 		    htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
    221 		wreq.wi_len = 1;
    222 		break;
    223 	case WI_RID_TX_CRYPT_KEY:
    224 		wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
    225 		wreq.wi_len = 1;
    226 		break;
    227 	case WI_RID_DEFLT_CRYPT_KEYS:
    228 		keys = (struct wi_ltv_keys *)&wreq;
    229 		/* do not show keys to non-root user */
    230 		error = suser(curthread);
    231 		if (error) {
    232 			memset(keys, 0, sizeof(*keys));
    233 			error = 0;
    234 			break;
    235 		}
    236 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    237 			keys->wi_keys[i].wi_keylen =
    238 			    htole16(ic->ic_nw_keys[i].wk_len);
    239 			memcpy(keys->wi_keys[i].wi_keydat,
    240 			    ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
    241 		}
    242 		wreq.wi_len = sizeof(*keys) / 2;
    243 		break;
    244 	case WI_RID_MAX_DATALEN:
    245 		wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);	/* TODO: frag */
    246 		wreq.wi_len = 1;
    247 		break;
    248 	case WI_RID_IFACE_STATS:
    249 		/* XXX: should be implemented in lower drivers */
    250 		break;
    251 	case WI_RID_READ_APS:
    252 		if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
    253 			/*
    254 			 * Don't return results until active scan completes.
    255 			 */
    256 			if (ic->ic_state == IEEE80211_S_SCAN &&
    257 			    (ic->ic_flags & IEEE80211_F_ASCAN)) {
    258 				error = EINPROGRESS;
    259 				break;
    260 			}
    261 		}
    262 		i = 0;
    263 		ap = (void *)((char *)wreq.wi_val + sizeof(i));
    264 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    265 			if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
    266 				break;
    267 			memset(ap, 0, sizeof(*ap));
    268 			if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
    269 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
    270 				ap->namelen = ic->ic_des_esslen;
    271 				if (ic->ic_des_esslen)
    272 					memcpy(ap->name, ic->ic_des_essid,
    273 					    ic->ic_des_esslen);
    274 			} else {
    275 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
    276 				ap->namelen = ni->ni_esslen;
    277 				if (ni->ni_esslen)
    278 					memcpy(ap->name, ni->ni_essid,
    279 					    ni->ni_esslen);
    280 			}
    281 			ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
    282 			ap->signal = (*ic->ic_node_getrssi)(ic, ni);
    283 			ap->capinfo = ni->ni_capinfo;
    284 			ap->interval = ni->ni_intval;
    285 			rs = &ni->ni_rates;
    286 			for (j = 0; j < rs->rs_nrates; j++) {
    287 				if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
    288 					ap->rate = (rs->rs_rates[j] &
    289 					    IEEE80211_RATE_VAL) * 5; /* XXX */
    290 				}
    291 			}
    292 			i++;
    293 			ap++;
    294 		}
    295 		memcpy(wreq.wi_val, &i, sizeof(i));
    296 		wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
    297 		break;
    298 	case WI_RID_PRISM2:
    299 		wreq.wi_val[0] = 1;	/* XXX lie so SCAN_RES can give rates */
    300 		wreq.wi_len = sizeof(u_int16_t) / 2;
    301 		break;
    302 	case WI_RID_SCAN_RES:			/* compatibility interface */
    303 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
    304 		    ic->ic_state == IEEE80211_S_SCAN) {
    305 			error = EINPROGRESS;
    306 			break;
    307 		}
    308 		/* NB: we use the Prism2 format so we can return rate info */
    309 		p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
    310 		res = (void *)&p2[1];
    311 		i = 0;
    312 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    313 			if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
    314 				break;
    315 			res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
    316 			res->wi_noise = 0;
    317 			res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
    318 			IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
    319 			res->wi_interval = ni->ni_intval;
    320 			res->wi_capinfo = ni->ni_capinfo;
    321 			res->wi_ssid_len = ni->ni_esslen;
    322 			memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
    323 			/* NB: assumes wi_srates holds <= ni->ni_rates */
    324 			memcpy(res->wi_srates, ni->ni_rates.rs_rates,
    325 				sizeof(res->wi_srates));
    326 			if (ni->ni_rates.rs_nrates < 10)
    327 				res->wi_srates[ni->ni_rates.rs_nrates] = 0;
    328 			res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
    329 			res->wi_rsvd = 0;
    330 			res++, i++;
    331 		}
    332 		p2->wi_rsvd = 0;
    333 		p2->wi_reason = i;
    334 		wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
    335 		break;
    336 	case WI_RID_READ_CACHE:
    337 		i = 0;
    338 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    339 			if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
    340 				break;
    341 			IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
    342 			memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
    343 			wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
    344 			wsc.noise = 0;
    345 			wsc.quality = 0;
    346 			memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
    347 			    &wsc, sizeof(wsc));
    348 			i++;
    349 		}
    350 		wreq.wi_len = sizeof(wsc) * i / 2;
    351 		break;
    352 	case WI_RID_SCAN_APS:
    353 		error = EINVAL;
    354 		break;
    355 	default:
    356 		error = EINVAL;
    357 		break;
    358 	}
    359 	if (error == 0) {
    360 		wreq.wi_len++;
    361 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
    362 	}
    363 	return error;
    364 }
    365 
    366 static int
    367 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    368 {
    369 #define	IEEERATE(_ic,_m,_i) \
    370 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
    371 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
    372 	for (i = 0; i < nrates; i++)
    373 		if (IEEERATE(ic, mode, i) == rate)
    374 			return i;
    375 	return -1;
    376 #undef IEEERATE
    377 }
    378 
    379 /*
    380  * Prepare to do a user-initiated scan for AP's.  If no
    381  * current/default channel is setup or the current channel
    382  * is invalid then pick the first available channel from
    383  * the active list as the place to start the scan.
    384  */
    385 static int
    386 ieee80211_setupscan(struct ieee80211com *ic)
    387 {
    388 	u_char *chanlist = ic->ic_chan_active;
    389 	int i;
    390 
    391 	if (ic->ic_ibss_chan == NULL ||
    392 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
    393 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
    394 			if (isset(chanlist, i)) {
    395 				ic->ic_ibss_chan = &ic->ic_channels[i];
    396 				goto found;
    397 			}
    398 		return EINVAL;			/* no active channels */
    399 found:
    400 		;
    401 	}
    402 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
    403 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
    404 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
    405 	/*
    406 	 * XXX don't permit a scan to be started unless we
    407 	 * know the device is ready.  For the moment this means
    408 	 * the device is marked up as this is the required to
    409 	 * initialize the hardware.  It would be better to permit
    410 	 * scanning prior to being up but that'll require some
    411 	 * changes to the infrastructure.
    412 	 */
    413 	return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
    414 }
    415 
    416 int
    417 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
    418 {
    419 	struct ieee80211com *ic = (void *)ifp;
    420 	int i, j, len, error, rate;
    421 	struct ifreq *ifr = (struct ifreq *)data;
    422 	struct wi_ltv_keys *keys;
    423 	struct wi_req wreq;
    424 	u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
    425 
    426 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
    427 	if (error)
    428 		return error;
    429 	len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
    430 	switch (wreq.wi_type) {
    431 	case WI_RID_SERIALNO:
    432 	case WI_RID_NODENAME:
    433 		return EPERM;
    434 	case WI_RID_CURRENT_SSID:
    435 		return EPERM;
    436 	case WI_RID_OWN_SSID:
    437 	case WI_RID_DESIRED_SSID:
    438 		if (le16toh(wreq.wi_val[0]) * 2 > len ||
    439 		    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
    440 			error = ENOSPC;
    441 			break;
    442 		}
    443 		memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
    444 		ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
    445 		memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
    446 		error = ENETRESET;
    447 		break;
    448 	case WI_RID_CURRENT_BSSID:
    449 		return EPERM;
    450 	case WI_RID_OWN_CHNL:
    451 		if (len != 2)
    452 			return EINVAL;
    453 		i = le16toh(wreq.wi_val[0]);
    454 		if (i < 0 ||
    455 		    i > IEEE80211_CHAN_MAX ||
    456 		    isclr(ic->ic_chan_active, i))
    457 			return EINVAL;
    458 		ic->ic_ibss_chan = &ic->ic_channels[i];
    459 		if (ic->ic_flags & IEEE80211_F_SIBSS)
    460 			error = ENETRESET;
    461 		break;
    462 	case WI_RID_CURRENT_CHAN:
    463 		return EPERM;
    464 	case WI_RID_COMMS_QUALITY:
    465 		return EPERM;
    466 	case WI_RID_PROMISC:
    467 		if (len != 2)
    468 			return EINVAL;
    469 		if (ifp->if_flags & IFF_PROMISC) {
    470 			if (wreq.wi_val[0] == 0) {
    471 				ifp->if_flags &= ~IFF_PROMISC;
    472 				error = ENETRESET;
    473 			}
    474 		} else {
    475 			if (wreq.wi_val[0] != 0) {
    476 				ifp->if_flags |= IFF_PROMISC;
    477 				error = ENETRESET;
    478 			}
    479 		}
    480 		break;
    481 	case WI_RID_PORTTYPE:
    482 		if (len != 2)
    483 			return EINVAL;
    484 		switch (le16toh(wreq.wi_val[0])) {
    485 		case IEEE80211_M_STA:
    486 			break;
    487 		case IEEE80211_M_IBSS:
    488 			if (!(ic->ic_caps & IEEE80211_C_IBSS))
    489 				return EINVAL;
    490 			break;
    491 		case IEEE80211_M_AHDEMO:
    492 			if (ic->ic_phytype != IEEE80211_T_DS ||
    493 			    !(ic->ic_caps & IEEE80211_C_AHDEMO))
    494 				return EINVAL;
    495 			break;
    496 		case IEEE80211_M_HOSTAP:
    497 			if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
    498 				return EINVAL;
    499 			break;
    500 		default:
    501 			return EINVAL;
    502 		}
    503 		if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
    504 			ic->ic_opmode = le16toh(wreq.wi_val[0]);
    505 			error = ENETRESET;
    506 		}
    507 		break;
    508 #if 0
    509 	case WI_RID_MAC_NODE:
    510 		if (len != IEEE80211_ADDR_LEN)
    511 			return EINVAL;
    512 		IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
    513 		/* if_init will copy lladdr into ic_myaddr */
    514 		error = ENETRESET;
    515 		break;
    516 #endif
    517 	case WI_RID_TX_RATE:
    518 		if (len != 2)
    519 			return EINVAL;
    520 		if (wreq.wi_val[0] == 0) {
    521 			/* auto */
    522 			ic->ic_fixed_rate = -1;
    523 			break;
    524 		}
    525 		rate = 2 * le16toh(wreq.wi_val[0]);
    526 		if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
    527 			/*
    528 			 * In autoselect mode search for the rate.  We take
    529 			 * the first instance which may not be right, but we
    530 			 * are limited by the interface.  Note that we also
    531 			 * lock the mode to insure the rate is meaningful
    532 			 * when it is used.
    533 			 */
    534 			for (j = IEEE80211_MODE_11A;
    535 			     j < IEEE80211_MODE_MAX; j++) {
    536 				if ((ic->ic_modecaps & (1<<j)) == 0)
    537 					continue;
    538 				i = findrate(ic, j, rate);
    539 				if (i != -1) {
    540 					/* lock mode too */
    541 					ic->ic_curmode = j;
    542 					goto setrate;
    543 				}
    544 			}
    545 		} else {
    546 			i = findrate(ic, ic->ic_curmode, rate);
    547 			if (i != -1)
    548 				goto setrate;
    549 		}
    550 		return EINVAL;
    551 	setrate:
    552 		ic->ic_fixed_rate = i;
    553 		error = ENETRESET;
    554 		break;
    555 	case WI_RID_CUR_TX_RATE:
    556 		return EPERM;
    557 	case WI_RID_RTS_THRESH:
    558 		if (len != 2)
    559 			return EINVAL;
    560 		if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
    561 			return EINVAL;		/* TODO: RTS */
    562 		break;
    563 	case WI_RID_CREATE_IBSS:
    564 		if (len != 2)
    565 			return EINVAL;
    566 		if (wreq.wi_val[0] != 0) {
    567 			if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
    568 				return EINVAL;
    569 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
    570 				ic->ic_flags |= IEEE80211_F_IBSSON;
    571 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
    572 				    ic->ic_state == IEEE80211_S_SCAN)
    573 					error = ENETRESET;
    574 			}
    575 		} else {
    576 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
    577 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
    578 				if (ic->ic_flags & IEEE80211_F_SIBSS) {
    579 					ic->ic_flags &= ~IEEE80211_F_SIBSS;
    580 					error = ENETRESET;
    581 				}
    582 			}
    583 		}
    584 		break;
    585 	case WI_RID_MICROWAVE_OVEN:
    586 		if (len != 2)
    587 			return EINVAL;
    588 		if (wreq.wi_val[0] != 0)
    589 			return EINVAL;		/* not supported */
    590 		break;
    591 	case WI_RID_ROAMING_MODE:
    592 		if (len != 2)
    593 			return EINVAL;
    594 		if (le16toh(wreq.wi_val[0]) != 1)
    595 			return EINVAL;		/* not supported */
    596 		break;
    597 	case WI_RID_SYSTEM_SCALE:
    598 		if (len != 2)
    599 			return EINVAL;
    600 		if (le16toh(wreq.wi_val[0]) != 1)
    601 			return EINVAL;		/* not supported */
    602 		break;
    603 	case WI_RID_PM_ENABLED:
    604 		if (len != 2)
    605 			return EINVAL;
    606 		if (wreq.wi_val[0] != 0) {
    607 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    608 				return EINVAL;
    609 			if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
    610 				ic->ic_flags |= IEEE80211_F_PMGTON;
    611 				error = ENETRESET;
    612 			}
    613 		} else {
    614 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
    615 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
    616 				error = ENETRESET;
    617 			}
    618 		}
    619 		break;
    620 	case WI_RID_MAX_SLEEP:
    621 		if (len != 2)
    622 			return EINVAL;
    623 		ic->ic_lintval = le16toh(wreq.wi_val[0]);
    624 		if (ic->ic_flags & IEEE80211_F_PMGTON)
    625 			error = ENETRESET;
    626 		break;
    627 	case WI_RID_CUR_BEACON_INT:
    628 		return EPERM;
    629 	case WI_RID_WEP_AVAIL:
    630 		return EPERM;
    631 	case WI_RID_CNFAUTHMODE:
    632 		if (len != 2)
    633 			return EINVAL;
    634 		if (le16toh(wreq.wi_val[0]) != 1)
    635 			return EINVAL;		/* TODO: shared key auth */
    636 		break;
    637 	case WI_RID_ENCRYPTION:
    638 		if (len != 2)
    639 			return EINVAL;
    640 		if (wreq.wi_val[0] != 0) {
    641 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    642 				return EINVAL;
    643 			if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
    644 				ic->ic_flags |= IEEE80211_F_WEPON;
    645 				error = ENETRESET;
    646 			}
    647 		} else {
    648 			if (ic->ic_flags & IEEE80211_F_WEPON) {
    649 				ic->ic_flags &= ~IEEE80211_F_WEPON;
    650 				error = ENETRESET;
    651 			}
    652 		}
    653 		break;
    654 	case WI_RID_TX_CRYPT_KEY:
    655 		if (len != 2)
    656 			return EINVAL;
    657 		i = le16toh(wreq.wi_val[0]);
    658 		if (i >= IEEE80211_WEP_NKID)
    659 			return EINVAL;
    660 		ic->ic_wep_txkey = i;
    661 		break;
    662 	case WI_RID_DEFLT_CRYPT_KEYS:
    663 		if (len != sizeof(struct wi_ltv_keys))
    664 			return EINVAL;
    665 		keys = (struct wi_ltv_keys *)&wreq;
    666 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    667 			len = le16toh(keys->wi_keys[i].wi_keylen);
    668 			if (len != 0 && len < IEEE80211_WEP_KEYLEN)
    669 				return EINVAL;
    670 			if (len > sizeof(ic->ic_nw_keys[i].wk_key))
    671 				return EINVAL;
    672 		}
    673 		memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
    674 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    675 			len = le16toh(keys->wi_keys[i].wi_keylen);
    676 			ic->ic_nw_keys[i].wk_len = len;
    677 			memcpy(ic->ic_nw_keys[i].wk_key,
    678 			    keys->wi_keys[i].wi_keydat, len);
    679 		}
    680 		error = ENETRESET;
    681 		break;
    682 	case WI_RID_MAX_DATALEN:
    683 		if (len != 2)
    684 			return EINVAL;
    685 		len = le16toh(wreq.wi_val[0]);
    686 		if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
    687 			return EINVAL;
    688 		if (len != IEEE80211_MAX_LEN)
    689 			return EINVAL;		/* TODO: fragment */
    690 		ic->ic_fragthreshold = len;
    691 		error = ENETRESET;
    692 		break;
    693 	case WI_RID_IFACE_STATS:
    694 		error = EPERM;
    695 		break;
    696 	case WI_RID_SCAN_REQ:			/* XXX wicontrol */
    697 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    698 			break;
    699 		error = ieee80211_setupscan(ic);
    700 		if (error == 0)
    701 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    702 		break;
    703 	case WI_RID_SCAN_APS:
    704 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    705 			break;
    706 		len--;			/* XXX: tx rate? */
    707 		/* FALLTHRU */
    708 	case WI_RID_CHANNEL_LIST:
    709 		memset(chanlist, 0, sizeof(chanlist));
    710 		/*
    711 		 * Since channel 0 is not available for DS, channel 1
    712 		 * is assigned to LSB on WaveLAN.
    713 		 */
    714 		if (ic->ic_phytype == IEEE80211_T_DS)
    715 			i = 1;
    716 		else
    717 			i = 0;
    718 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
    719 			if ((j / 8) >= len)
    720 				break;
    721 			if (isclr((u_int8_t *)wreq.wi_val, j))
    722 				continue;
    723 			if (isclr(ic->ic_chan_active, i)) {
    724 				if (wreq.wi_type != WI_RID_CHANNEL_LIST)
    725 					continue;
    726 				if (isclr(ic->ic_chan_avail, i))
    727 					return EPERM;
    728 			}
    729 			setbit(chanlist, i);
    730 		}
    731 		memcpy(ic->ic_chan_active, chanlist,
    732 		    sizeof(ic->ic_chan_active));
    733 		error = ieee80211_setupscan(ic);
    734 		if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
    735 			/* NB: ignore error from ieee80211_setupscan */
    736 			error = ENETRESET;
    737 		} else if (error == 0)
    738 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    739 		break;
    740 	default:
    741 		error = EINVAL;
    742 		break;
    743 	}
    744 	return error;
    745 }
    746 
    747 int
    748 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    749 {
    750 	struct ieee80211com *ic = (void *)ifp;
    751 	int error = 0;
    752 	u_int kid, len;
    753 	struct ieee80211req *ireq;
    754 	struct ifreq *ifr;
    755 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
    756 	char tmpssid[IEEE80211_NWID_LEN];
    757 	struct ieee80211_channel *chan;
    758 
    759 	switch (cmd) {
    760 	case SIOCSIFMEDIA:
    761 	case SIOCGIFMEDIA:
    762 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
    763 				&ic->ic_media, cmd);
    764 		break;
    765 	case SIOCG80211:
    766 		ireq = (struct ieee80211req *) data;
    767 		switch (ireq->i_type) {
    768 		case IEEE80211_IOC_SSID:
    769 			switch (ic->ic_state) {
    770 			case IEEE80211_S_INIT:
    771 			case IEEE80211_S_SCAN:
    772 				ireq->i_len = ic->ic_des_esslen;
    773 				memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
    774 				break;
    775 			default:
    776 				ireq->i_len = ic->ic_bss->ni_esslen;
    777 				memcpy(tmpssid, ic->ic_bss->ni_essid,
    778 					ireq->i_len);
    779 				break;
    780 			}
    781 			error = copyout(tmpssid, ireq->i_data, ireq->i_len);
    782 			break;
    783 		case IEEE80211_IOC_NUMSSIDS:
    784 			ireq->i_val = 1;
    785 			break;
    786 		case IEEE80211_IOC_WEP:
    787 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    788 				ireq->i_val = IEEE80211_WEP_NOSUP;
    789 			} else {
    790 				if (ic->ic_flags & IEEE80211_F_WEPON) {
    791 					ireq->i_val =
    792 					    IEEE80211_WEP_MIXED;
    793 				} else {
    794 					ireq->i_val =
    795 					    IEEE80211_WEP_OFF;
    796 				}
    797 			}
    798 			break;
    799 		case IEEE80211_IOC_WEPKEY:
    800 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    801 				error = EINVAL;
    802 				break;
    803 			}
    804 			kid = (u_int) ireq->i_val;
    805 			if (kid >= IEEE80211_WEP_NKID) {
    806 				error = EINVAL;
    807 				break;
    808 			}
    809 			len = (u_int) ic->ic_nw_keys[kid].wk_len;
    810 			/* NB: only root can read WEP keys */
    811 			if (suser(curthread) == 0) {
    812 				bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
    813 			} else {
    814 				bzero(tmpkey, len);
    815 			}
    816 			ireq->i_len = len;
    817 			error = copyout(tmpkey, ireq->i_data, len);
    818 			break;
    819 		case IEEE80211_IOC_NUMWEPKEYS:
    820 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    821 				error = EINVAL;
    822 			else
    823 				ireq->i_val = IEEE80211_WEP_NKID;
    824 			break;
    825 		case IEEE80211_IOC_WEPTXKEY:
    826 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    827 				error = EINVAL;
    828 			else
    829 				ireq->i_val = ic->ic_wep_txkey;
    830 			break;
    831 		case IEEE80211_IOC_AUTHMODE:
    832 			ireq->i_val = IEEE80211_AUTH_OPEN;
    833 			break;
    834 		case IEEE80211_IOC_CHANNEL:
    835 			switch (ic->ic_state) {
    836 			case IEEE80211_S_INIT:
    837 			case IEEE80211_S_SCAN:
    838 				if (ic->ic_opmode == IEEE80211_M_STA)
    839 					chan = ic->ic_des_chan;
    840 				else
    841 					chan = ic->ic_ibss_chan;
    842 				break;
    843 			default:
    844 				chan = ic->ic_bss->ni_chan;
    845 				break;
    846 			}
    847 			ireq->i_val = ieee80211_chan2ieee(ic, chan);
    848 			break;
    849 		case IEEE80211_IOC_POWERSAVE:
    850 			if (ic->ic_flags & IEEE80211_F_PMGTON)
    851 				ireq->i_val = IEEE80211_POWERSAVE_ON;
    852 			else
    853 				ireq->i_val = IEEE80211_POWERSAVE_OFF;
    854 			break;
    855 		case IEEE80211_IOC_POWERSAVESLEEP:
    856 			ireq->i_val = ic->ic_lintval;
    857 			break;
    858 		case IEEE80211_IOC_RTSTHRESHOLD:
    859 			ireq->i_val = ic->ic_rtsthreshold;
    860 			break;
    861 		default:
    862 			error = EINVAL;
    863 		}
    864 		break;
    865 	case SIOCS80211:
    866 		error = suser(curthread);
    867 		if (error)
    868 			break;
    869 		ireq = (struct ieee80211req *) data;
    870 		switch (ireq->i_type) {
    871 		case IEEE80211_IOC_SSID:
    872 			if (ireq->i_val != 0 ||
    873 			    ireq->i_len > IEEE80211_NWID_LEN) {
    874 				error = EINVAL;
    875 				break;
    876 			}
    877 			error = copyin(ireq->i_data, tmpssid, ireq->i_len);
    878 			if (error)
    879 				break;
    880 			memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
    881 			ic->ic_des_esslen = ireq->i_len;
    882 			memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
    883 			error = ENETRESET;
    884 			break;
    885 		case IEEE80211_IOC_WEP:
    886 			/*
    887 			 * These cards only support one mode so
    888 			 * we just turn wep on if what ever is
    889 			 * passed in is not OFF.
    890 			 */
    891 			if (ireq->i_val == IEEE80211_WEP_OFF) {
    892 				ic->ic_flags &= ~IEEE80211_F_WEPON;
    893 			} else {
    894 				ic->ic_flags |= IEEE80211_F_WEPON;
    895 			}
    896 			error = ENETRESET;
    897 			break;
    898 		case IEEE80211_IOC_WEPKEY:
    899 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    900 				error = EINVAL;
    901 				break;
    902 			}
    903 			kid = (u_int) ireq->i_val;
    904 			if (kid >= IEEE80211_WEP_NKID) {
    905 				error = EINVAL;
    906 				break;
    907 			}
    908 			if (ireq->i_len > sizeof(tmpkey)) {
    909 				error = EINVAL;
    910 				break;
    911 			}
    912 			memset(tmpkey, 0, sizeof(tmpkey));
    913 			error = copyin(ireq->i_data, tmpkey, ireq->i_len);
    914 			if (error)
    915 				break;
    916 			memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
    917 				sizeof(tmpkey));
    918 			ic->ic_nw_keys[kid].wk_len = ireq->i_len;
    919 			error = ENETRESET;
    920 			break;
    921 		case IEEE80211_IOC_WEPTXKEY:
    922 			kid = (u_int) ireq->i_val;
    923 			if (kid >= IEEE80211_WEP_NKID) {
    924 				error = EINVAL;
    925 				break;
    926 			}
    927 			ic->ic_wep_txkey = kid;
    928 			error = ENETRESET;
    929 			break;
    930 #if 0
    931 		case IEEE80211_IOC_AUTHMODE:
    932 			sc->wi_authmode = ireq->i_val;
    933 			break;
    934 #endif
    935 		case IEEE80211_IOC_CHANNEL:
    936 			/* XXX 0xffff overflows 16-bit signed */
    937 			if (ireq->i_val == 0 ||
    938 			    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
    939 				ic->ic_des_chan = IEEE80211_CHAN_ANYC;
    940 			else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
    941 			    isclr(ic->ic_chan_active, ireq->i_val)) {
    942 				error = EINVAL;
    943 				break;
    944 			} else
    945 				ic->ic_ibss_chan = ic->ic_des_chan =
    946 					&ic->ic_channels[ireq->i_val];
    947 			switch (ic->ic_state) {
    948 			case IEEE80211_S_INIT:
    949 			case IEEE80211_S_SCAN:
    950 				error = ENETRESET;
    951 				break;
    952 			default:
    953 				if (ic->ic_opmode == IEEE80211_M_STA) {
    954 					if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
    955 					    ic->ic_bss->ni_chan != ic->ic_des_chan)
    956 						error = ENETRESET;
    957 				} else {
    958 					if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
    959 						error = ENETRESET;
    960 				}
    961 				break;
    962 			}
    963 			break;
    964 		case IEEE80211_IOC_POWERSAVE:
    965 			switch (ireq->i_val) {
    966 			case IEEE80211_POWERSAVE_OFF:
    967 				if (ic->ic_flags & IEEE80211_F_PMGTON) {
    968 					ic->ic_flags &= ~IEEE80211_F_PMGTON;
    969 					error = ENETRESET;
    970 				}
    971 				break;
    972 			case IEEE80211_POWERSAVE_ON:
    973 				if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    974 					error = EINVAL;
    975 				else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
    976 					ic->ic_flags |= IEEE80211_F_PMGTON;
    977 					error = ENETRESET;
    978 				}
    979 				break;
    980 			default:
    981 				error = EINVAL;
    982 				break;
    983 			}
    984 			break;
    985 		case IEEE80211_IOC_POWERSAVESLEEP:
    986 			if (ireq->i_val < 0) {
    987 				error = EINVAL;
    988 				break;
    989 			}
    990 			ic->ic_lintval = ireq->i_val;
    991 			error = ENETRESET;
    992 			break;
    993 		case IEEE80211_IOC_RTSTHRESHOLD:
    994 			if (!(IEEE80211_RTS_MIN < ireq->i_val &&
    995 			      ireq->i_val < IEEE80211_RTS_MAX)) {
    996 				error = EINVAL;
    997 				break;
    998 			}
    999 			ic->ic_rtsthreshold = ireq->i_val;
   1000 			error = ENETRESET;
   1001 			break;
   1002 		default:
   1003 			error = EINVAL;
   1004 			break;
   1005 		}
   1006 		break;
   1007 	case SIOCGIFGENERIC:
   1008 		error = ieee80211_cfgget(ifp, cmd, data);
   1009 		break;
   1010 	case SIOCSIFGENERIC:
   1011 		error = suser(curthread);
   1012 		if (error)
   1013 			break;
   1014 		error = ieee80211_cfgset(ifp, cmd, data);
   1015 		break;
   1016 	case SIOCG80211STATS:
   1017 		ifr = (struct ifreq *)data;
   1018 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
   1019 		break;
   1020 	default:
   1021 		error = ether_ioctl(ifp, cmd, data);
   1022 		break;
   1023 	}
   1024 	return error;
   1025 }
   1026