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