xref: /netbsd-src/sys/net80211/ieee80211_ioctl.c (revision 5b84b3983f71fd20a534cfa5d1556623a8aaa717)
1 /*	$NetBSD: ieee80211_ioctl.c,v 1.25 2005/07/27 20:31:24 dyoung Exp $	*/
2 /*-
3  * Copyright (c) 2001 Atsushi Onoe
4  * Copyright (c) 2002-2005 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.25 2005/07/06 15:38:27 sam Exp $");
37 #endif
38 #ifdef __NetBSD__
39 __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.25 2005/07/27 20:31:24 dyoung Exp $");
40 #endif
41 
42 /*
43  * IEEE 802.11 ioctl support (FreeBSD-specific)
44  */
45 
46 #include "opt_inet.h"
47 
48 #include <sys/endian.h>
49 #include <sys/param.h>
50 #include <sys/kernel.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/systm.h>
54 #include <sys/proc.h>
55 
56 #include <net/if.h>
57 #include <net/if_arp.h>
58 #include <net/if_media.h>
59 #include <net/if_ether.h>
60 
61 #ifdef INET
62 #include <netinet/in.h>
63 #include <netinet/if_inarp.h>
64 #endif
65 
66 #include <net80211/ieee80211_var.h>
67 #include <net80211/ieee80211_ioctl.h>
68 
69 #include <dev/ic/wi_ieee.h>
70 
71 #define	IS_UP(_ic) \
72 	(((_ic)->ic_ifp->if_flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
73 #define	IS_UP_AUTO(_ic) \
74 	(IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
75 
76 /*
77  * XXX
78  * Wireless LAN specific configuration interface, which is compatible
79  * with wicontrol(8).
80  */
81 
82 struct wi_read_ap_args {
83 	int	i;		/* result count */
84 	struct wi_apinfo *ap;	/* current entry in result buffer */
85 	caddr_t	max;		/* result buffer bound */
86 };
87 
88 static void
89 wi_read_ap_result(void *arg, struct ieee80211_node *ni)
90 {
91 	struct ieee80211com *ic = ni->ni_ic;
92 	struct wi_read_ap_args *sa = arg;
93 	struct wi_apinfo *ap = sa->ap;
94 	struct ieee80211_rateset *rs;
95 	int j;
96 
97 	if ((caddr_t)(ap + 1) > sa->max)
98 		return;
99 	memset(ap, 0, sizeof(struct wi_apinfo));
100 	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
101 		IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
102 		ap->namelen = ic->ic_des_esslen;
103 		if (ic->ic_des_esslen)
104 			memcpy(ap->name, ic->ic_des_essid,
105 			    ic->ic_des_esslen);
106 	} else {
107 		IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
108 		ap->namelen = ni->ni_esslen;
109 		if (ni->ni_esslen)
110 			memcpy(ap->name, ni->ni_essid,
111 			    ni->ni_esslen);
112 	}
113 	ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
114 	ap->signal = ic->ic_node_getrssi(ni);
115 	ap->capinfo = ni->ni_capinfo;
116 	ap->interval = ni->ni_intval;
117 	rs = &ni->ni_rates;
118 	for (j = 0; j < rs->rs_nrates; j++) {
119 		if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
120 			ap->rate = (rs->rs_rates[j] &
121 			    IEEE80211_RATE_VAL) * 5; /* XXX */
122 		}
123 	}
124 	sa->i++;
125 	sa->ap++;
126 }
127 
128 struct wi_read_prism2_args {
129 	int	i;		/* result count */
130 	struct wi_scan_res *res;/* current entry in result buffer */
131 	caddr_t	max;		/* result buffer bound */
132 };
133 
134 #if 0
135 static void
136 wi_read_prism2_result(void *arg, struct ieee80211_node *ni)
137 {
138 	struct ieee80211com *ic = ni->ni_ic;
139 	struct wi_read_prism2_args *sa = arg;
140 	struct wi_scan_res *res = sa->res;
141 
142 	if ((caddr_t)(res + 1) > sa->max)
143 		return;
144 	res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
145 	res->wi_noise = 0;
146 	res->wi_signal = ic->ic_node_getrssi(ni);
147 	IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
148 	res->wi_interval = ni->ni_intval;
149 	res->wi_capinfo = ni->ni_capinfo;
150 	res->wi_ssid_len = ni->ni_esslen;
151 	memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
152 	/* NB: assumes wi_srates holds <= ni->ni_rates */
153 	memcpy(res->wi_srates, ni->ni_rates.rs_rates,
154 		sizeof(res->wi_srates));
155 	if (ni->ni_rates.rs_nrates < 10)
156 		res->wi_srates[ni->ni_rates.rs_nrates] = 0;
157 	res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
158 	res->wi_rsvd = 0;
159 
160 	sa->i++;
161 	sa->res++;
162 }
163 
164 struct wi_read_sigcache_args {
165 	int	i;		/* result count */
166 	struct wi_sigcache *wsc;/* current entry in result buffer */
167 	caddr_t	max;		/* result buffer bound */
168 };
169 
170 static void
171 wi_read_sigcache(void *arg, struct ieee80211_node *ni)
172 {
173 	struct ieee80211com *ic = ni->ni_ic;
174 	struct wi_read_sigcache_args *sa = arg;
175 	struct wi_sigcache *wsc = sa->wsc;
176 
177 	if ((caddr_t)(wsc + 1) > sa->max)
178 		return;
179 	memset(wsc, 0, sizeof(struct wi_sigcache));
180 	IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr);
181 	wsc->signal = ic->ic_node_getrssi(ni);
182 
183 	sa->wsc++;
184 	sa->i++;
185 }
186 #endif
187 
188 int
189 ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, caddr_t data)
190 {
191 	struct ifnet *ifp = ic->ic_ifp;
192 	int i, j, error;
193 	struct ifreq *ifr = (struct ifreq *)data;
194 	struct wi_req wreq;
195 	struct wi_ltv_keys *keys;
196 
197 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
198 	if (error)
199 		return error;
200 	wreq.wi_len = 0;
201 	switch (wreq.wi_type) {
202 	case WI_RID_SERIALNO:
203 	case WI_RID_STA_IDENTITY:
204 		/* nothing appropriate */
205 		break;
206 	case WI_RID_NODENAME:
207 		strlcpy((char *)&wreq.wi_val[1], hostname,
208 		    sizeof(wreq.wi_val) - sizeof(wreq.wi_val[0]));
209 		wreq.wi_val[0] = htole16(strlen(hostname));
210 		wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
211 		break;
212 	case WI_RID_CURRENT_SSID:
213 		if (ic->ic_state != IEEE80211_S_RUN) {
214 			wreq.wi_val[0] = 0;
215 			wreq.wi_len = 1;
216 			break;
217 		}
218 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
219 		memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
220 		    ic->ic_bss->ni_esslen);
221 		wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
222 		break;
223 	case WI_RID_OWN_SSID:
224 	case WI_RID_DESIRED_SSID:
225 		wreq.wi_val[0] = htole16(ic->ic_des_esslen);
226 		memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
227 		wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
228 		break;
229 	case WI_RID_CURRENT_BSSID:
230 		if (ic->ic_state == IEEE80211_S_RUN)
231 			IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
232 		else
233 			memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
234 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
235 		break;
236 	case WI_RID_CHANNEL_LIST:
237 		memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
238 		/*
239 		 * Since channel 0 is not available for DS, channel 1
240 		 * is assigned to LSB on WaveLAN.
241 		 */
242 		if (ic->ic_phytype == IEEE80211_T_DS)
243 			i = 1;
244 		else
245 			i = 0;
246 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
247 			if (isset(ic->ic_chan_active, i)) {
248 				setbit((u_int8_t *)wreq.wi_val, j);
249 				wreq.wi_len = j / 16 + 1;
250 			}
251 		break;
252 	case WI_RID_OWN_CHNL:
253 		wreq.wi_val[0] = htole16(
254 			ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
255 		wreq.wi_len = 1;
256 		break;
257 	case WI_RID_CURRENT_CHAN:
258 		wreq.wi_val[0] = htole16(
259 			ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
260 		wreq.wi_len = 1;
261 		break;
262 	case WI_RID_COMMS_QUALITY:
263 		wreq.wi_val[0] = 0;				/* quality */
264 		wreq.wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss));
265 		wreq.wi_val[2] = 0;				/* noise */
266 		wreq.wi_len = 3;
267 		break;
268 	case WI_RID_PROMISC:
269 		wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
270 		wreq.wi_len = 1;
271 		break;
272 	case WI_RID_PORTTYPE:
273 		wreq.wi_val[0] = htole16(ic->ic_opmode);
274 		wreq.wi_len = 1;
275 		break;
276 	case WI_RID_MAC_NODE:
277 		IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
278 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
279 		break;
280 	case WI_RID_TX_RATE:
281 		if (ic->ic_fixed_rate == -1)
282 			wreq.wi_val[0] = 0;	/* auto */
283 		else
284 			wreq.wi_val[0] = htole16(
285 			    (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
286 			    IEEE80211_RATE_VAL) / 2);
287 		wreq.wi_len = 1;
288 		break;
289 	case WI_RID_CUR_TX_RATE:
290 		wreq.wi_val[0] = htole16(
291 		    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
292 		    IEEE80211_RATE_VAL) / 2);
293 		wreq.wi_len = 1;
294 		break;
295 	case WI_RID_FRAG_THRESH:
296 		wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
297 		wreq.wi_len = 1;
298 		break;
299 	case WI_RID_RTS_THRESH:
300 		wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
301 		wreq.wi_len = 1;
302 		break;
303 	case WI_RID_CREATE_IBSS:
304 		wreq.wi_val[0] =
305 		    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
306 		wreq.wi_len = 1;
307 		break;
308 	case WI_RID_MICROWAVE_OVEN:
309 		wreq.wi_val[0] = 0;	/* no ... not supported */
310 		wreq.wi_len = 1;
311 		break;
312 	case WI_RID_ROAMING_MODE:
313 		wreq.wi_val[0] = htole16(ic->ic_roaming);	/* XXX map */
314 		wreq.wi_len = 1;
315 		break;
316 	case WI_RID_SYSTEM_SCALE:
317 		wreq.wi_val[0] = htole16(1);	/* low density ... not supp */
318 		wreq.wi_len = 1;
319 		break;
320 	case WI_RID_PM_ENABLED:
321 		wreq.wi_val[0] =
322 		    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
323 		wreq.wi_len = 1;
324 		break;
325 	case WI_RID_MAX_SLEEP:
326 		wreq.wi_val[0] = htole16(ic->ic_lintval);
327 		wreq.wi_len = 1;
328 		break;
329 	case WI_RID_CUR_BEACON_INT:
330 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
331 		wreq.wi_len = 1;
332 		break;
333 	case WI_RID_WEP_AVAIL:
334 		wreq.wi_val[0] = htole16(1);	/* always available */
335 		wreq.wi_len = 1;
336 		break;
337 	case WI_RID_CNFAUTHMODE:
338 		wreq.wi_val[0] = htole16(1);	/* TODO: open system only */
339 		wreq.wi_len = 1;
340 		break;
341 	case WI_RID_ENCRYPTION:
342 		wreq.wi_val[0] =
343 		    htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
344 		wreq.wi_len = 1;
345 		break;
346 	case WI_RID_TX_CRYPT_KEY:
347 		wreq.wi_val[0] = htole16(ic->ic_def_txkey);
348 		wreq.wi_len = 1;
349 		break;
350 	case WI_RID_DEFLT_CRYPT_KEYS:
351 		keys = (struct wi_ltv_keys *)&wreq;
352 		/* do not show keys to non-root user */
353 		error = suser(curproc->p_ucred, &curproc->p_acflag);
354 		if (error) {
355 			memset(keys, 0, sizeof(*keys));
356 			error = 0;
357 			break;
358 		}
359 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
360 			keys->wi_keys[i].wi_keylen =
361 			    htole16(ic->ic_nw_keys[i].wk_keylen);
362 			memcpy(keys->wi_keys[i].wi_keydat,
363 			    ic->ic_nw_keys[i].wk_key,
364 			    ic->ic_nw_keys[i].wk_keylen);
365 		}
366 		wreq.wi_len = sizeof(*keys) / 2;
367 		break;
368 	case WI_RID_MAX_DATALEN:
369 		wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
370 		wreq.wi_len = 1;
371 		break;
372 	case WI_RID_DBM_ADJUST:
373 		/* not supported, we just pass rssi value from driver. */
374 		break;
375 	case WI_RID_IFACE_STATS:
376 		/* XXX: should be implemented in lower drivers */
377 		break;
378 	case WI_RID_READ_APS:
379 		/*
380 		 * Don't return results until active scan completes.
381 		 */
382 		if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
383 			struct wi_read_ap_args args;
384 
385 			args.i = 0;
386 			args.ap = (void *)((char *)wreq.wi_val + sizeof(i));
387 			args.max = (void *)(&wreq + 1);
388 			ieee80211_iterate_nodes(&ic->ic_scan,
389 				wi_read_ap_result, &args);
390 			memcpy(wreq.wi_val, &args.i, sizeof(args.i));
391 			wreq.wi_len = (sizeof(int) +
392 				sizeof(struct wi_apinfo) * args.i) / 2;
393 		} else
394 			error = EINPROGRESS;
395 		break;
396 #if 0
397 	case WI_RID_SCAN_RES:			/* compatibility interface */
398 		if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
399 			struct wi_read_prism2_args args;
400 			struct wi_scan_p2_hdr *p2;
401 
402 			/* NB: use Prism2 format so we can include rate info */
403 			p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
404 			args.i = 0;
405 			args.res = (void *)&p2[1];
406 			args.max = (void *)(&wreq + 1);
407 			ieee80211_iterate_nodes(&ic->ic_scan,
408 				wi_read_prism2_result, &args);
409 			p2->wi_rsvd = 0;
410 			p2->wi_reason = args.i;
411 			wreq.wi_len = (sizeof(*p2) +
412 				sizeof(struct wi_scan_res) * args.i) / 2;
413 		} else
414 			error = EINPROGRESS;
415 		break;
416 	case WI_RID_READ_CACHE: {
417 		struct wi_read_sigcache_args args;
418 		args.i = 0;
419 		args.wsc = (struct wi_sigcache *) wreq.wi_val;
420 		args.max = (void *)(&wreq + 1);
421 		ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args);
422 		wreq.wi_len = sizeof(struct wi_sigcache) * args.i / 2;
423 		break;
424 	}
425 #endif
426 	default:
427 		error = EINVAL;
428 		break;
429 	}
430 	if (error == 0) {
431 		wreq.wi_len++;
432 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
433 	}
434 	return error;
435 }
436 
437 static int
438 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
439 {
440 #define	IEEERATE(_ic,_m,_i) \
441 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
442 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
443 	for (i = 0; i < nrates; i++)
444 		if (IEEERATE(ic, mode, i) == rate)
445 			return i;
446 	return -1;
447 #undef IEEERATE
448 }
449 
450 /*
451  * Prepare to do a user-initiated scan for AP's.  If no
452  * current/default channel is setup or the current channel
453  * is invalid then pick the first available channel from
454  * the active list as the place to start the scan.
455  */
456 static int
457 ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
458 {
459 	int i;
460 
461 	/*
462 	 * XXX don't permit a scan to be started unless we
463 	 * know the device is ready.  For the moment this means
464 	 * the device is marked up as this is the required to
465 	 * initialize the hardware.  It would be better to permit
466 	 * scanning prior to being up but that'll require some
467 	 * changes to the infrastructure.
468 	 */
469 	if (!IS_UP(ic))
470 		return EINVAL;
471 	if (ic->ic_ibss_chan == NULL ||
472 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
473 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
474 			if (isset(chanlist, i)) {
475 				ic->ic_ibss_chan = &ic->ic_channels[i];
476 				goto found;
477 			}
478 		return EINVAL;			/* no active channels */
479 found:
480 		;
481 	}
482 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
483 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
484 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
485 	memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
486 	/*
487 	 * We force the state to INIT before calling ieee80211_new_state
488 	 * to get ieee80211_begin_scan called.  We really want to scan w/o
489 	 * altering the current state but that's not possible right now.
490 	 */
491 	/* XXX handle proberequest case */
492 	ic->ic_state = IEEE80211_S_INIT;	/* XXX bypass state machine */
493 	return 0;
494 }
495 
496 int
497 ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data)
498 {
499 	struct ifnet *ifp = ic->ic_ifp;
500 	int i, j, len, error, rate;
501 	struct ifreq *ifr = (struct ifreq *)data;
502 	struct wi_ltv_keys *keys;
503 	struct wi_req wreq;
504 	u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
505 
506 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
507 	if (error)
508 		return error;
509 	len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
510 	switch (wreq.wi_type) {
511 	case WI_RID_SERIALNO:
512 	case WI_RID_NODENAME:
513 		return EPERM;
514 	case WI_RID_CURRENT_SSID:
515 		return EPERM;
516 	case WI_RID_OWN_SSID:
517 	case WI_RID_DESIRED_SSID:
518 		if (le16toh(wreq.wi_val[0]) * 2 > len ||
519 		    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
520 			error = ENOSPC;
521 			break;
522 		}
523 		memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
524 		ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
525 		memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
526 		error = ENETRESET;
527 		break;
528 	case WI_RID_CURRENT_BSSID:
529 		return EPERM;
530 	case WI_RID_OWN_CHNL:
531 		if (len != 2)
532 			return EINVAL;
533 		i = le16toh(wreq.wi_val[0]);
534 		if (i < 0 ||
535 		    i > IEEE80211_CHAN_MAX ||
536 		    isclr(ic->ic_chan_active, i))
537 			return EINVAL;
538 		ic->ic_ibss_chan = &ic->ic_channels[i];
539 		if (ic->ic_opmode == IEEE80211_M_MONITOR)
540 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
541 		else
542 			error = ENETRESET;
543 		break;
544 	case WI_RID_CURRENT_CHAN:
545 		return EPERM;
546 	case WI_RID_COMMS_QUALITY:
547 		return EPERM;
548 	case WI_RID_PROMISC:
549 		if (len != 2)
550 			return EINVAL;
551 		if (ifp->if_flags & IFF_PROMISC) {
552 			if (wreq.wi_val[0] == 0) {
553 				ifp->if_flags &= ~IFF_PROMISC;
554 				error = ENETRESET;
555 			}
556 		} else {
557 			if (wreq.wi_val[0] != 0) {
558 				ifp->if_flags |= IFF_PROMISC;
559 				error = ENETRESET;
560 			}
561 		}
562 		break;
563 	case WI_RID_PORTTYPE:
564 		if (len != 2)
565 			return EINVAL;
566 		switch (le16toh(wreq.wi_val[0])) {
567 		case IEEE80211_M_STA:
568 			break;
569 		case IEEE80211_M_IBSS:
570 			if (!(ic->ic_caps & IEEE80211_C_IBSS))
571 				return EINVAL;
572 			break;
573 		case IEEE80211_M_AHDEMO:
574 			if (ic->ic_phytype != IEEE80211_T_DS ||
575 			    !(ic->ic_caps & IEEE80211_C_AHDEMO))
576 				return EINVAL;
577 			break;
578 		case IEEE80211_M_HOSTAP:
579 			if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
580 				return EINVAL;
581 			break;
582 		default:
583 			return EINVAL;
584 		}
585 		if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
586 			ic->ic_opmode = le16toh(wreq.wi_val[0]);
587 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
588 		}
589 		break;
590 #if 0
591 	case WI_RID_MAC_NODE:
592 		if (len != IEEE80211_ADDR_LEN)
593 			return EINVAL;
594 		IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
595 		/* if_init will copy lladdr into ic_myaddr */
596 		error = ENETRESET;
597 		break;
598 #endif
599 	case WI_RID_TX_RATE:
600 		if (len != 2)
601 			return EINVAL;
602 		if (wreq.wi_val[0] == 0) {
603 			/* auto */
604 			ic->ic_fixed_rate = -1;
605 			break;
606 		}
607 		rate = 2 * le16toh(wreq.wi_val[0]);
608 		if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
609 			/*
610 			 * In autoselect mode search for the rate.  We take
611 			 * the first instance which may not be right, but we
612 			 * are limited by the interface.  Note that we also
613 			 * lock the mode to insure the rate is meaningful
614 			 * when it is used.
615 			 */
616 			for (j = IEEE80211_MODE_11A;
617 			     j < IEEE80211_MODE_MAX; j++) {
618 				if ((ic->ic_modecaps & (1<<j)) == 0)
619 					continue;
620 				i = findrate(ic, j, rate);
621 				if (i != -1) {
622 					/* lock mode too */
623 					ic->ic_curmode = j;
624 					goto setrate;
625 				}
626 			}
627 		} else {
628 			i = findrate(ic, ic->ic_curmode, rate);
629 			if (i != -1)
630 				goto setrate;
631 		}
632 		return EINVAL;
633 	setrate:
634 		ic->ic_fixed_rate = i;
635 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
636 		break;
637 	case WI_RID_CUR_TX_RATE:
638 		return EPERM;
639 	case WI_RID_FRAG_THRESH:
640 		if (len != 2)
641 			return EINVAL;
642 		ic->ic_fragthreshold = le16toh(wreq.wi_val[0]);
643 		error = ENETRESET;
644 		break;
645 	case WI_RID_RTS_THRESH:
646 		if (len != 2)
647 			return EINVAL;
648 		ic->ic_rtsthreshold = le16toh(wreq.wi_val[0]);
649 		error = ENETRESET;
650 		break;
651 	case WI_RID_CREATE_IBSS:
652 		if (len != 2)
653 			return EINVAL;
654 		if (wreq.wi_val[0] != 0) {
655 			if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
656 				return EINVAL;
657 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
658 				ic->ic_flags |= IEEE80211_F_IBSSON;
659 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
660 				    ic->ic_state == IEEE80211_S_SCAN)
661 					error = IS_UP_AUTO(ic) ? ENETRESET : 0;
662 			}
663 		} else {
664 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
665 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
666 				if (ic->ic_flags & IEEE80211_F_SIBSS) {
667 					ic->ic_flags &= ~IEEE80211_F_SIBSS;
668 					error = IS_UP_AUTO(ic) ? ENETRESET : 0;
669 				}
670 			}
671 		}
672 		break;
673 	case WI_RID_MICROWAVE_OVEN:
674 		if (len != 2)
675 			return EINVAL;
676 		if (wreq.wi_val[0] != 0)
677 			return EINVAL;		/* not supported */
678 		break;
679 	case WI_RID_ROAMING_MODE:
680 		if (len != 2)
681 			return EINVAL;
682 		i = le16toh(wreq.wi_val[0]);
683 		if (i > IEEE80211_ROAMING_MANUAL)
684 			return EINVAL;		/* not supported */
685 		ic->ic_roaming = i;
686 		break;
687 	case WI_RID_SYSTEM_SCALE:
688 		if (len != 2)
689 			return EINVAL;
690 		if (le16toh(wreq.wi_val[0]) != 1)
691 			return EINVAL;		/* not supported */
692 		break;
693 	case WI_RID_PM_ENABLED:
694 		if (len != 2)
695 			return EINVAL;
696 		if (wreq.wi_val[0] != 0) {
697 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
698 				return EINVAL;
699 			if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
700 				ic->ic_flags |= IEEE80211_F_PMGTON;
701 				error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
702 			}
703 		} else {
704 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
705 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
706 				error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
707 			}
708 		}
709 		break;
710 	case WI_RID_MAX_SLEEP:
711 		if (len != 2)
712 			return EINVAL;
713 		ic->ic_lintval = le16toh(wreq.wi_val[0]);
714 		if (ic->ic_flags & IEEE80211_F_PMGTON)
715 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
716 		break;
717 	case WI_RID_CUR_BEACON_INT:
718 		return EPERM;
719 	case WI_RID_WEP_AVAIL:
720 		return EPERM;
721 	case WI_RID_CNFAUTHMODE:
722 		if (len != 2)
723 			return EINVAL;
724 		i = le16toh(wreq.wi_val[0]);
725 		if (i > IEEE80211_AUTH_WPA)
726 			return EINVAL;
727 		ic->ic_bss->ni_authmode = i;		/* XXX ENETRESET? */
728 		error = ENETRESET;
729 		break;
730 	case WI_RID_ENCRYPTION:
731 		if (len != 2)
732 			return EINVAL;
733 		if (wreq.wi_val[0] != 0) {
734 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
735 				return EINVAL;
736 			if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
737 				ic->ic_flags |= IEEE80211_F_PRIVACY;
738 				error = ENETRESET;
739 			}
740 		} else {
741 			if (ic->ic_flags & IEEE80211_F_PRIVACY) {
742 				ic->ic_flags &= ~IEEE80211_F_PRIVACY;
743 				error = ENETRESET;
744 			}
745 		}
746 		break;
747 	case WI_RID_TX_CRYPT_KEY:
748 		if (len != 2)
749 			return EINVAL;
750 		i = le16toh(wreq.wi_val[0]);
751 		if (i >= IEEE80211_WEP_NKID)
752 			return EINVAL;
753 		ic->ic_def_txkey = i;
754 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
755 		break;
756 	case WI_RID_DEFLT_CRYPT_KEYS:
757 		if (len != sizeof(struct wi_ltv_keys))
758 			return EINVAL;
759 		keys = (struct wi_ltv_keys *)&wreq;
760 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
761 			len = le16toh(keys->wi_keys[i].wi_keylen);
762 			if (len != 0 && len < IEEE80211_WEP_KEYLEN)
763 				return EINVAL;
764 			if (len > IEEE80211_KEYBUF_SIZE)
765 				return EINVAL;
766 		}
767 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
768 			struct ieee80211_key *k = &ic->ic_nw_keys[i];
769 
770 			len = le16toh(keys->wi_keys[i].wi_keylen);
771 			k->wk_keylen = len;
772 			k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
773 			memset(k->wk_key, 0, sizeof(k->wk_key));
774 			memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len);
775 #if 0
776 			k->wk_type = IEEE80211_CIPHER_WEP;
777 #endif
778 		}
779 		error = ENETRESET;
780 		break;
781 	case WI_RID_MAX_DATALEN:
782 		if (len != 2)
783 			return EINVAL;
784 		len = le16toh(wreq.wi_val[0]);
785 		if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
786 			return EINVAL;
787 		ic->ic_fragthreshold = len;
788 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
789 		break;
790 	case WI_RID_IFACE_STATS:
791 		error = EPERM;
792 		break;
793 	case WI_RID_SCAN_REQ:			/* XXX wicontrol */
794 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
795 			break;
796 		error = ieee80211_setupscan(ic, ic->ic_chan_avail);
797 		if (error == 0)
798 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
799 		break;
800 	case WI_RID_SCAN_APS:
801 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
802 			break;
803 		len--;			/* XXX: tx rate? */
804 		/* FALLTHRU */
805 	case WI_RID_CHANNEL_LIST:
806 		memset(chanlist, 0, sizeof(chanlist));
807 		/*
808 		 * Since channel 0 is not available for DS, channel 1
809 		 * is assigned to LSB on WaveLAN.
810 		 */
811 		if (ic->ic_phytype == IEEE80211_T_DS)
812 			i = 1;
813 		else
814 			i = 0;
815 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
816 			if ((j / 8) >= len)
817 				break;
818 			if (isclr((u_int8_t *)wreq.wi_val, j))
819 				continue;
820 			if (isclr(ic->ic_chan_active, i)) {
821 				if (wreq.wi_type != WI_RID_CHANNEL_LIST)
822 					continue;
823 				if (isclr(ic->ic_chan_avail, i))
824 					return EPERM;
825 			}
826 			setbit(chanlist, i);
827 		}
828 		error = ieee80211_setupscan(ic, chanlist);
829 		if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
830 			/* NB: ignore error from ieee80211_setupscan */
831 			error = ENETRESET;
832 		} else if (error == 0)
833 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
834 		break;
835 	default:
836 		error = EINVAL;
837 		break;
838 	}
839 	if (error == ENETRESET && !IS_UP_AUTO(ic))
840 		error = 0;
841 	return error;
842 }
843 
844 #ifdef __FreeBSD__
845 static struct ieee80211_channel *
846 getcurchan(struct ieee80211com *ic)
847 {
848 	switch (ic->ic_state) {
849 	case IEEE80211_S_INIT:
850 	case IEEE80211_S_SCAN:
851 		return ic->ic_des_chan;
852 	default:
853 		return ic->ic_ibss_chan;
854 	}
855 }
856 #endif /* __FreeBSD__ */
857 
858 static int
859 cap2cipher(int flag)
860 {
861 	switch (flag) {
862 	case IEEE80211_C_WEP:		return IEEE80211_CIPHER_WEP;
863 	case IEEE80211_C_AES:		return IEEE80211_CIPHER_AES_OCB;
864 	case IEEE80211_C_AES_CCM:	return IEEE80211_CIPHER_AES_CCM;
865 	case IEEE80211_C_CKIP:		return IEEE80211_CIPHER_CKIP;
866 	case IEEE80211_C_TKIP:		return IEEE80211_CIPHER_TKIP;
867 	}
868 	return -1;
869 }
870 
871 static int
872 ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
873 {
874 	struct ieee80211_node *ni;
875 	struct ieee80211req_key ik;
876 	struct ieee80211_key *wk;
877 	const struct ieee80211_cipher *cip;
878 	u_int kid;
879 	int error;
880 
881 	if (ireq->i_len != sizeof(ik))
882 		return EINVAL;
883 	error = copyin(ireq->i_data, &ik, sizeof(ik));
884 	if (error)
885 		return error;
886 	kid = ik.ik_keyix;
887 	if (kid == IEEE80211_KEYIX_NONE) {
888 		ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
889 		if (ni == NULL)
890 			return EINVAL;		/* XXX */
891 		wk = &ni->ni_ucastkey;
892 	} else {
893 		if (kid >= IEEE80211_WEP_NKID)
894 			return EINVAL;
895 		wk = &ic->ic_nw_keys[kid];
896 		IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
897 		ni = NULL;
898 	}
899 	cip = wk->wk_cipher;
900 	ik.ik_type = cip->ic_cipher;
901 	ik.ik_keylen = wk->wk_keylen;
902 	ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
903 	if (wk->wk_keyix == ic->ic_def_txkey)
904 		ik.ik_flags |= IEEE80211_KEY_DEFAULT;
905 	if (suser(curproc->p_ucred, &curproc->p_acflag) == 0) {
906 		/* NB: only root can read key data */
907 		ik.ik_keyrsc = wk->wk_keyrsc;
908 		ik.ik_keytsc = wk->wk_keytsc;
909 		memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
910 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
911 			memcpy(ik.ik_keydata+wk->wk_keylen,
912 				wk->wk_key + IEEE80211_KEYBUF_SIZE,
913 				IEEE80211_MICBUF_SIZE);
914 			ik.ik_keylen += IEEE80211_MICBUF_SIZE;
915 		}
916 	} else {
917 		ik.ik_keyrsc = 0;
918 		ik.ik_keytsc = 0;
919 		memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
920 	}
921 	if (ni != NULL)
922 		ieee80211_free_node(ni);
923 	return copyout(&ik, ireq->i_data, sizeof(ik));
924 }
925 
926 static int
927 ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
928 {
929 
930 	if (sizeof(ic->ic_chan_active) > ireq->i_len)
931 		ireq->i_len = sizeof(ic->ic_chan_active);
932 	return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
933 }
934 
935 static int
936 ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
937 {
938 	struct ieee80211req_chaninfo chans;	/* XXX off stack? */
939 	int i, space;
940 
941 	/*
942 	 * Since channel 0 is not available for DS, channel 1
943 	 * is assigned to LSB on WaveLAN.
944 	 */
945 	if (ic->ic_phytype == IEEE80211_T_DS)
946 		i = 1;
947 	else
948 		i = 0;
949 	memset(&chans, 0, sizeof(chans));
950 	for (; i <= IEEE80211_CHAN_MAX; i++)
951 		if (isset(ic->ic_chan_avail, i)) {
952 			struct ieee80211_channel *c = &ic->ic_channels[i];
953 			chans.ic_chans[chans.ic_nchans].ic_freq = c->ic_freq;
954 			chans.ic_chans[chans.ic_nchans].ic_flags = c->ic_flags;
955 			chans.ic_nchans++;
956 		}
957 	space = __offsetof(struct ieee80211req_chaninfo,
958 			ic_chans[chans.ic_nchans]);
959 	if (space > ireq->i_len)
960 		space = ireq->i_len;
961 	return copyout(&chans, ireq->i_data, space);
962 }
963 
964 static int
965 ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
966 {
967 	struct ieee80211_node *ni;
968 	struct ieee80211req_wpaie wpaie;
969 	int error;
970 
971 	if (ireq->i_len < IEEE80211_ADDR_LEN)
972 		return EINVAL;
973 	error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
974 	if (error != 0)
975 		return error;
976 	ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
977 	if (ni == NULL)
978 		return EINVAL;		/* XXX */
979 	memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
980 	if (ni->ni_wpa_ie != NULL) {
981 		int ielen = ni->ni_wpa_ie[1] + 2;
982 		if (ielen > sizeof(wpaie.wpa_ie))
983 			ielen = sizeof(wpaie.wpa_ie);
984 		memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
985 	}
986 	ieee80211_free_node(ni);
987 	if (ireq->i_len > sizeof(wpaie))
988 		ireq->i_len = sizeof(wpaie);
989 	return copyout(&wpaie, ireq->i_data, ireq->i_len);
990 }
991 
992 static int
993 ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
994 {
995 	struct ieee80211_node *ni;
996 	u_int8_t macaddr[IEEE80211_ADDR_LEN];
997 	const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
998 	int error;
999 
1000 	if (ireq->i_len < off)
1001 		return EINVAL;
1002 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1003 	if (error != 0)
1004 		return error;
1005 	ni = ieee80211_find_node(&ic->ic_sta, macaddr);
1006 	if (ni == NULL)
1007 		return EINVAL;		/* XXX */
1008 	if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
1009 		ireq->i_len = sizeof(struct ieee80211req_sta_stats);
1010 	/* NB: copy out only the statistics */
1011 	error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off,
1012 			ireq->i_len - off);
1013 	ieee80211_free_node(ni);
1014 	return error;
1015 }
1016 
1017 static void
1018 get_scan_result(struct ieee80211req_scan_result *sr,
1019 	const struct ieee80211_node *ni)
1020 {
1021 	struct ieee80211com *ic = ni->ni_ic;
1022 
1023 	memset(sr, 0, sizeof(*sr));
1024 	sr->isr_ssid_len = ni->ni_esslen;
1025 	if (ni->ni_wpa_ie != NULL)
1026 		sr->isr_ie_len += 2+ni->ni_wpa_ie[1];
1027 	if (ni->ni_wme_ie != NULL)
1028 		sr->isr_ie_len += 2+ni->ni_wme_ie[1];
1029 	sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len;
1030 	sr->isr_len = roundup(sr->isr_len, sizeof(u_int32_t));
1031 	if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
1032 		sr->isr_freq = ni->ni_chan->ic_freq;
1033 		sr->isr_flags = ni->ni_chan->ic_flags;
1034 	}
1035 	sr->isr_rssi = ic->ic_node_getrssi(ni);
1036 	sr->isr_intval = ni->ni_intval;
1037 	sr->isr_capinfo = ni->ni_capinfo;
1038 	sr->isr_erp = ni->ni_erp;
1039 	IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid);
1040 	sr->isr_nrates = ni->ni_rates.rs_nrates;
1041 	if (sr->isr_nrates > 15)
1042 		sr->isr_nrates = 15;
1043 	memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates);
1044 }
1045 
1046 static int
1047 ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
1048 {
1049 	union {
1050 		struct ieee80211req_scan_result res;
1051 		char data[512];		/* XXX shrink? */
1052 	} u;
1053 	struct ieee80211req_scan_result *sr = &u.res;
1054 	struct ieee80211_node_table *nt;
1055 	struct ieee80211_node *ni;
1056 	int error, space;
1057 	u_int8_t *p, *cp;
1058 
1059 	p = ireq->i_data;
1060 	space = ireq->i_len;
1061 	error = 0;
1062 	/* XXX locking */
1063 	nt =  &ic->ic_scan;
1064 	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1065 		/* NB: skip pre-scan node state */
1066 		if (ni->ni_chan == IEEE80211_CHAN_ANYC)
1067 			continue;
1068 		get_scan_result(sr, ni);
1069 		if (sr->isr_len > sizeof(u))
1070 			continue;		/* XXX */
1071 		if (space < sr->isr_len)
1072 			break;
1073 		cp = (u_int8_t *)(sr+1);
1074 		memcpy(cp, ni->ni_essid, ni->ni_esslen);
1075 		cp += ni->ni_esslen;
1076 		if (ni->ni_wpa_ie != NULL) {
1077 			memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
1078 			cp += 2+ni->ni_wpa_ie[1];
1079 		}
1080 		if (ni->ni_wme_ie != NULL) {
1081 			memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
1082 			cp += 2+ni->ni_wme_ie[1];
1083 		}
1084 		error = copyout(sr, p, sr->isr_len);
1085 		if (error)
1086 			break;
1087 		p += sr->isr_len;
1088 		space -= sr->isr_len;
1089 	}
1090 	ireq->i_len -= space;
1091 	return error;
1092 }
1093 
1094 static void
1095 get_sta_info(struct ieee80211req_sta_info *si, const struct ieee80211_node *ni)
1096 {
1097 	struct ieee80211com *ic = ni->ni_ic;
1098 
1099 	si->isi_ie_len = 0;
1100 	if (ni->ni_wpa_ie != NULL)
1101 		si->isi_ie_len += 2+ni->ni_wpa_ie[1];
1102 	if (ni->ni_wme_ie != NULL)
1103 		si->isi_ie_len += 2+ni->ni_wme_ie[1];
1104 	si->isi_len = sizeof(*si) + si->isi_ie_len, sizeof(u_int32_t);
1105 	si->isi_len = roundup(si->isi_len, sizeof(u_int32_t));
1106 	si->isi_freq = ni->ni_chan->ic_freq;
1107 	si->isi_flags = ni->ni_chan->ic_flags;
1108 	si->isi_state = ni->ni_flags;
1109 	si->isi_authmode = ni->ni_authmode;
1110 	si->isi_rssi = ic->ic_node_getrssi(ni);
1111 	si->isi_capinfo = ni->ni_capinfo;
1112 	si->isi_erp = ni->ni_erp;
1113 	IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
1114 	si->isi_nrates = ni->ni_rates.rs_nrates;
1115 	if (si->isi_nrates > 15)
1116 		si->isi_nrates = 15;
1117 	memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
1118 	si->isi_txrate = ni->ni_txrate;
1119 	si->isi_associd = ni->ni_associd;
1120 	si->isi_txpower = ni->ni_txpower;
1121 	si->isi_vlan = ni->ni_vlan;
1122 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
1123 		memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
1124 		memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
1125 	} else {
1126 		si->isi_txseqs[0] = ni->ni_txseqs[0];
1127 		si->isi_rxseqs[0] = ni->ni_rxseqs[0];
1128 	}
1129 	if (ic->ic_opmode == IEEE80211_M_IBSS || ni->ni_associd != 0)
1130 		si->isi_inact = ic->ic_inact_run;
1131 	else if (ieee80211_node_is_authorized(ni))
1132 		si->isi_inact = ic->ic_inact_auth;
1133 	else
1134 		si->isi_inact = ic->ic_inact_init;
1135 	si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
1136 }
1137 
1138 static int
1139 ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
1140 {
1141 	union {
1142 		struct ieee80211req_sta_info info;
1143 		char data[512];		/* XXX shrink? */
1144 	} u;
1145 	struct ieee80211req_sta_info *si = &u.info;
1146 	struct ieee80211_node_table *nt;
1147 	struct ieee80211_node *ni;
1148 	int error, space;
1149 	u_int8_t *p, *cp;
1150 
1151 	nt = &ic->ic_sta;
1152 	p = ireq->i_data;
1153 	space = ireq->i_len;
1154 	error = 0;
1155 	/* XXX locking */
1156 	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1157 		get_sta_info(si, ni);
1158 		if (si->isi_len > sizeof(u))
1159 			continue;		/* XXX */
1160 		if (space < si->isi_len)
1161 			break;
1162 		cp = (u_int8_t *)(si+1);
1163 		if (ni->ni_wpa_ie != NULL) {
1164 			memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
1165 			cp += 2+ni->ni_wpa_ie[1];
1166 		}
1167 		if (ni->ni_wme_ie != NULL) {
1168 			memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
1169 			cp += 2+ni->ni_wme_ie[1];
1170 		}
1171 		error = copyout(si, p, si->isi_len);
1172 		if (error)
1173 			break;
1174 		p += si->isi_len;
1175 		space -= si->isi_len;
1176 	}
1177 	ireq->i_len -= space;
1178 	return error;
1179 }
1180 
1181 static int
1182 ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1183 {
1184 	struct ieee80211_node *ni;
1185 	struct ieee80211req_sta_txpow txpow;
1186 	int error;
1187 
1188 	if (ireq->i_len != sizeof(txpow))
1189 		return EINVAL;
1190 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1191 	if (error != 0)
1192 		return error;
1193 	ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1194 	if (ni == NULL)
1195 		return EINVAL;		/* XXX */
1196 	txpow.it_txpow = ni->ni_txpower;
1197 	error = copyout(&txpow, ireq->i_data, sizeof(txpow));
1198 	ieee80211_free_node(ni);
1199 	return error;
1200 }
1201 
1202 static int
1203 ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1204 {
1205 	struct ieee80211_wme_state *wme = &ic->ic_wme;
1206 	struct wmeParams *wmep;
1207 	int ac;
1208 
1209 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1210 		return EINVAL;
1211 
1212 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1213 	if (ac >= WME_NUM_AC)
1214 		ac = WME_AC_BE;
1215 	if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
1216 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1217 	else
1218 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1219 	switch (ireq->i_type) {
1220 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1221 		ireq->i_val = wmep->wmep_logcwmin;
1222 		break;
1223 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
1224 		ireq->i_val = wmep->wmep_logcwmax;
1225 		break;
1226 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1227 		ireq->i_val = wmep->wmep_aifsn;
1228 		break;
1229 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1230 		ireq->i_val = wmep->wmep_txopLimit;
1231 		break;
1232 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1233 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1234 		ireq->i_val = wmep->wmep_acm;
1235 		break;
1236 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
1237 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1238 		ireq->i_val = !wmep->wmep_noackPolicy;
1239 		break;
1240 	}
1241 	return 0;
1242 }
1243 
1244 /*
1245  * When building the kernel with -O2 on the i386 architecture, gcc
1246  * seems to want to inline this function into ieee80211_ioctl()
1247  * (which is the only routine that calls it). When this happens,
1248  * ieee80211_ioctl() ends up consuming an additional 2K of stack
1249  * space. (Exactly why it needs so much is unclear.) The problem
1250  * is that it's possible for ieee80211_ioctl() to invoke other
1251  * routines (including driver init functions) which could then find
1252  * themselves perilously close to exhausting the stack.
1253  *
1254  * To avoid this, we deliberately prevent gcc from inlining this
1255  * routine. Another way to avoid this is to use less agressive
1256  * optimization when compiling this file (i.e. -O instead of -O2)
1257  * but special-casing the compilation of this one module in the
1258  * build system would be awkward.
1259  */
1260 #ifdef __GNUC__
1261 __attribute__ ((noinline))
1262 #endif
1263 static int
1264 ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1265 {
1266 	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1267 	int error = 0;
1268 #ifdef __FreeBSD__
1269 	u_int kid, len;
1270 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1271 	char tmpssid[IEEE80211_NWID_LEN];
1272 #endif /* __FreeBSD__ */
1273 	u_int m;
1274 
1275 	switch (ireq->i_type) {
1276 #ifdef __FreeBSD__
1277 	case IEEE80211_IOC_SSID:
1278 		switch (ic->ic_state) {
1279 		case IEEE80211_S_INIT:
1280 		case IEEE80211_S_SCAN:
1281 			ireq->i_len = ic->ic_des_esslen;
1282 			memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
1283 			break;
1284 		default:
1285 			ireq->i_len = ic->ic_bss->ni_esslen;
1286 			memcpy(tmpssid, ic->ic_bss->ni_essid,
1287 				ireq->i_len);
1288 			break;
1289 		}
1290 		error = copyout(tmpssid, ireq->i_data, ireq->i_len);
1291 		break;
1292 	case IEEE80211_IOC_NUMSSIDS:
1293 		ireq->i_val = 1;
1294 		break;
1295 	case IEEE80211_IOC_WEP:
1296 		if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
1297 			ireq->i_val = IEEE80211_WEP_OFF;
1298 		else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
1299 			ireq->i_val = IEEE80211_WEP_ON;
1300 		else
1301 			ireq->i_val = IEEE80211_WEP_MIXED;
1302 		break;
1303 	case IEEE80211_IOC_WEPKEY:
1304 		kid = (u_int) ireq->i_val;
1305 		if (kid >= IEEE80211_WEP_NKID)
1306 			return EINVAL;
1307 		len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
1308 		/* NB: only root can read WEP keys */
1309 		if (suser(curproc->p_ucred, &curproc->p_acflag) == 0) {
1310 			bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
1311 		} else {
1312 			bzero(tmpkey, len);
1313 		}
1314 		ireq->i_len = len;
1315 		error = copyout(tmpkey, ireq->i_data, len);
1316 		break;
1317 	case IEEE80211_IOC_NUMWEPKEYS:
1318 		ireq->i_val = IEEE80211_WEP_NKID;
1319 		break;
1320 	case IEEE80211_IOC_WEPTXKEY:
1321 		ireq->i_val = ic->ic_def_txkey;
1322 		break;
1323 #endif /* __FreeBSD__ */
1324 	case IEEE80211_IOC_AUTHMODE:
1325 		if (ic->ic_flags & IEEE80211_F_WPA)
1326 			ireq->i_val = IEEE80211_AUTH_WPA;
1327 		else
1328 			ireq->i_val = ic->ic_bss->ni_authmode;
1329 		break;
1330 #ifdef __FreeBSD__
1331 	case IEEE80211_IOC_CHANNEL:
1332 		ireq->i_val = ieee80211_chan2ieee(ic, getcurchan(ic));
1333 		break;
1334 	case IEEE80211_IOC_POWERSAVE:
1335 		if (ic->ic_flags & IEEE80211_F_PMGTON)
1336 			ireq->i_val = IEEE80211_POWERSAVE_ON;
1337 		else
1338 			ireq->i_val = IEEE80211_POWERSAVE_OFF;
1339 		break;
1340 	case IEEE80211_IOC_POWERSAVESLEEP:
1341 		ireq->i_val = ic->ic_lintval;
1342 		break;
1343 #endif /* __FreeBSD__ */
1344 	case IEEE80211_IOC_RTSTHRESHOLD:
1345 		ireq->i_val = ic->ic_rtsthreshold;
1346 		break;
1347 	case IEEE80211_IOC_PROTMODE:
1348 		ireq->i_val = ic->ic_protmode;
1349 		break;
1350 	case IEEE80211_IOC_TXPOWER:
1351 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
1352 			return EINVAL;
1353 		ireq->i_val = ic->ic_txpowlimit;
1354 		break;
1355 	case IEEE80211_IOC_MCASTCIPHER:
1356 		ireq->i_val = rsn->rsn_mcastcipher;
1357 		break;
1358 	case IEEE80211_IOC_MCASTKEYLEN:
1359 		ireq->i_val = rsn->rsn_mcastkeylen;
1360 		break;
1361 	case IEEE80211_IOC_UCASTCIPHERS:
1362 		ireq->i_val = 0;
1363 		for (m = 0x1; m != 0; m <<= 1)
1364 			if (rsn->rsn_ucastcipherset & m)
1365 				ireq->i_val |= 1<<cap2cipher(m);
1366 		break;
1367 	case IEEE80211_IOC_UCASTCIPHER:
1368 		ireq->i_val = rsn->rsn_ucastcipher;
1369 		break;
1370 	case IEEE80211_IOC_UCASTKEYLEN:
1371 		ireq->i_val = rsn->rsn_ucastkeylen;
1372 		break;
1373 	case IEEE80211_IOC_KEYMGTALGS:
1374 		ireq->i_val = rsn->rsn_keymgmtset;
1375 		break;
1376 	case IEEE80211_IOC_RSNCAPS:
1377 		ireq->i_val = rsn->rsn_caps;
1378 		break;
1379 	case IEEE80211_IOC_WPA:
1380 		switch (ic->ic_flags & IEEE80211_F_WPA) {
1381 		case IEEE80211_F_WPA1:
1382 			ireq->i_val = 1;
1383 			break;
1384 		case IEEE80211_F_WPA2:
1385 			ireq->i_val = 2;
1386 			break;
1387 		case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
1388 			ireq->i_val = 3;
1389 			break;
1390 		default:
1391 			ireq->i_val = 0;
1392 			break;
1393 		}
1394 		break;
1395 	case IEEE80211_IOC_CHANLIST:
1396 		error = ieee80211_ioctl_getchanlist(ic, ireq);
1397 		break;
1398 	case IEEE80211_IOC_ROAMING:
1399 		ireq->i_val = ic->ic_roaming;
1400 		break;
1401 	case IEEE80211_IOC_PRIVACY:
1402 		ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
1403 		break;
1404 	case IEEE80211_IOC_DROPUNENCRYPTED:
1405 		ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
1406 		break;
1407 	case IEEE80211_IOC_COUNTERMEASURES:
1408 		ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
1409 		break;
1410 	case IEEE80211_IOC_DRIVER_CAPS:
1411 		ireq->i_val = ic->ic_caps>>16;
1412 		ireq->i_len = ic->ic_caps&0xffff;
1413 		break;
1414 	case IEEE80211_IOC_WME:
1415 		ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
1416 		break;
1417 	case IEEE80211_IOC_HIDESSID:
1418 		ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
1419 		break;
1420 	case IEEE80211_IOC_APBRIDGE:
1421 		ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
1422 		break;
1423 	case IEEE80211_IOC_OPTIE:
1424 		if (ic->ic_opt_ie == NULL)
1425 			return EINVAL;
1426 		/* NB: truncate, caller can check length */
1427 		if (ireq->i_len > ic->ic_opt_ie_len)
1428 			ireq->i_len = ic->ic_opt_ie_len;
1429 		error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
1430 		break;
1431 	case IEEE80211_IOC_WPAKEY:
1432 		error = ieee80211_ioctl_getkey(ic, ireq);
1433 		break;
1434 	case IEEE80211_IOC_CHANINFO:
1435 		error = ieee80211_ioctl_getchaninfo(ic, ireq);
1436 		break;
1437 #ifdef __FreeBSD__
1438 	case IEEE80211_IOC_BSSID:
1439 		if (ireq->i_len != IEEE80211_ADDR_LEN)
1440 			return EINVAL;
1441 		error = copyout(ic->ic_state == IEEE80211_S_RUN ?
1442 					ic->ic_bss->ni_bssid :
1443 					ic->ic_des_bssid,
1444 				ireq->i_data, ireq->i_len);
1445 		break;
1446 #endif /* __FreeBSD__ */
1447 	case IEEE80211_IOC_WPAIE:
1448 		error = ieee80211_ioctl_getwpaie(ic, ireq);
1449 		break;
1450 	case IEEE80211_IOC_SCAN_RESULTS:
1451 		error = ieee80211_ioctl_getscanresults(ic, ireq);
1452 		break;
1453 	case IEEE80211_IOC_STA_STATS:
1454 		error = ieee80211_ioctl_getstastats(ic, ireq);
1455 		break;
1456 	case IEEE80211_IOC_TXPOWMAX:
1457 		ireq->i_val = ic->ic_bss->ni_txpower;
1458 		break;
1459 	case IEEE80211_IOC_STA_TXPOW:
1460 		error = ieee80211_ioctl_getstatxpow(ic, ireq);
1461 		break;
1462 	case IEEE80211_IOC_STA_INFO:
1463 		error = ieee80211_ioctl_getstainfo(ic, ireq);
1464 		break;
1465 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1466 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
1467 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1468 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1469 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1470 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
1471 		error = ieee80211_ioctl_getwmeparam(ic, ireq);
1472 		break;
1473 	case IEEE80211_IOC_DTIM_PERIOD:
1474 		ireq->i_val = ic->ic_dtim_period;
1475 		break;
1476 	case IEEE80211_IOC_BEACON_INTERVAL:
1477 		/* NB: get from ic_bss for station mode */
1478 		ireq->i_val = ic->ic_bss->ni_intval;
1479 		break;
1480 	case IEEE80211_IOC_PUREG:
1481 		ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
1482 		break;
1483 	default:
1484 		error = EINVAL;
1485 		break;
1486 	}
1487 	return error;
1488 }
1489 
1490 static int
1491 ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
1492 {
1493 	int error;
1494 	void *ie;
1495 
1496 	/*
1497 	 * NB: Doing this for ap operation could be useful (e.g. for
1498 	 *     WPA and/or WME) except that it typically is worthless
1499 	 *     without being able to intervene when processing
1500 	 *     association response frames--so disallow it for now.
1501 	 */
1502 	if (ic->ic_opmode != IEEE80211_M_STA)
1503 		return EINVAL;
1504 	if (ireq->i_len > IEEE80211_MAX_OPT_IE)
1505 		return EINVAL;
1506 	/* NB: data.length is validated by the wireless extensions code */
1507 	MALLOC(ie, void *, (u_long)ireq->i_len, M_DEVBUF, M_WAITOK);
1508 	if (ie == NULL)
1509 		return ENOMEM;
1510 	error = copyin(ireq->i_data, ie, ireq->i_len);
1511 	/* XXX sanity check data? */
1512 	if (ic->ic_opt_ie != NULL)
1513 		FREE(ic->ic_opt_ie, M_DEVBUF);
1514 	ic->ic_opt_ie = ie;
1515 	ic->ic_opt_ie_len = ireq->i_len;
1516 	return 0;
1517 }
1518 
1519 static int
1520 ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1521 {
1522 	struct ieee80211req_key ik;
1523 	struct ieee80211_node *ni;
1524 	struct ieee80211_key *wk;
1525 	u_int16_t kid;
1526 	int error;
1527 
1528 	if (ireq->i_len != sizeof(ik))
1529 		return EINVAL;
1530 	error = copyin(ireq->i_data, &ik, sizeof(ik));
1531 	if (error)
1532 		return error;
1533 	/* NB: cipher support is verified by ieee80211_crypt_newkey */
1534 	/* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
1535 	if (ik.ik_keylen > sizeof(ik.ik_keydata))
1536 		return E2BIG;
1537 	kid = ik.ik_keyix;
1538 	if (kid == IEEE80211_KEYIX_NONE) {
1539 		/* XXX unicast keys currently must be tx/rx */
1540 		if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
1541 			return EINVAL;
1542 		if (ic->ic_opmode == IEEE80211_M_STA) {
1543 			ni = ieee80211_ref_node(ic->ic_bss);
1544 			if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
1545 				ieee80211_free_node(ni);
1546 				return EADDRNOTAVAIL;
1547 			}
1548 		} else {
1549 			ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
1550 			if (ni == NULL)
1551 				return ENOENT;
1552 		}
1553 		wk = &ni->ni_ucastkey;
1554 	} else {
1555 		if (kid >= IEEE80211_WEP_NKID)
1556 			return EINVAL;
1557 		wk = &ic->ic_nw_keys[kid];
1558 		ni = NULL;
1559 	}
1560 	error = 0;
1561 	ieee80211_key_update_begin(ic);
1562 	if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
1563 		wk->wk_keylen = ik.ik_keylen;
1564 		/* NB: MIC presence is implied by cipher type */
1565 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
1566 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
1567 		wk->wk_keyrsc = ik.ik_keyrsc;
1568 		wk->wk_keytsc = 0;			/* new key, reset */
1569 		memset(wk->wk_key, 0, sizeof(wk->wk_key));
1570 		memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
1571 		if (!ieee80211_crypto_setkey(ic, wk,
1572 		    ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
1573 			error = EIO;
1574 		else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
1575 			ic->ic_def_txkey = kid;
1576 	} else
1577 		error = ENXIO;
1578 	ieee80211_key_update_end(ic);
1579 	if (ni != NULL)
1580 		ieee80211_free_node(ni);
1581 	return error;
1582 }
1583 
1584 static int
1585 ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1586 {
1587 	struct ieee80211req_del_key dk;
1588 	int kid, error;
1589 
1590 	if (ireq->i_len != sizeof(dk))
1591 		return EINVAL;
1592 	error = copyin(ireq->i_data, &dk, sizeof(dk));
1593 	if (error)
1594 		return error;
1595 	kid = dk.idk_keyix;
1596 	/* XXX u_int8_t -> u_int16_t */
1597 	if (dk.idk_keyix == (u_int8_t) IEEE80211_KEYIX_NONE) {
1598 		struct ieee80211_node *ni;
1599 
1600 		if (ic->ic_opmode == IEEE80211_M_STA) {
1601 			ni = ieee80211_ref_node(ic->ic_bss);
1602 			if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
1603 				ieee80211_free_node(ni);
1604 				return EADDRNOTAVAIL;
1605 			}
1606 		} else {
1607 			ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
1608 			if (ni == NULL)
1609 				return ENOENT;
1610 		}
1611 		/* XXX error return */
1612 		ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
1613 		ieee80211_free_node(ni);
1614 	} else {
1615 		if (kid >= IEEE80211_WEP_NKID)
1616 			return EINVAL;
1617 		/* XXX error return */
1618 		ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
1619 	}
1620 	return 0;
1621 }
1622 
1623 #ifndef IEEE80211_NO_HOSTAP
1624 static void
1625 domlme(void *arg, struct ieee80211_node *ni)
1626 {
1627 	struct ieee80211com *ic = ni->ni_ic;
1628 	struct ieee80211req_mlme *mlme = arg;
1629 
1630 	if (ni->ni_associd != 0) {
1631 		IEEE80211_SEND_MGMT(ic, ni,
1632 			mlme->im_op == IEEE80211_MLME_DEAUTH ?
1633 				IEEE80211_FC0_SUBTYPE_DEAUTH :
1634 				IEEE80211_FC0_SUBTYPE_DISASSOC,
1635 			mlme->im_reason);
1636 	}
1637 	ieee80211_node_leave(ic, ni);
1638 }
1639 #endif /* !IEEE80211_NO_HOSTAP */
1640 
1641 static int
1642 ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
1643 {
1644 	struct ieee80211req_mlme mlme;
1645 	struct ieee80211_node *ni;
1646 	int error;
1647 
1648 	if (ireq->i_len != sizeof(mlme))
1649 		return EINVAL;
1650 	error = copyin(ireq->i_data, &mlme, sizeof(mlme));
1651 	if (error)
1652 		return error;
1653 	switch (mlme.im_op) {
1654 	case IEEE80211_MLME_ASSOC:
1655 		if (ic->ic_opmode != IEEE80211_M_STA)
1656 			return EINVAL;
1657 		/* XXX must be in S_SCAN state? */
1658 
1659 		if (mlme.im_ssid_len != 0) {
1660 			/*
1661 			 * Desired ssid specified; must match both bssid and
1662 			 * ssid to distinguish ap advertising multiple ssid's.
1663 			 */
1664 			ni = ieee80211_find_node_with_ssid(&ic->ic_scan,
1665 				mlme.im_macaddr,
1666 				mlme.im_ssid_len, mlme.im_ssid);
1667 		} else {
1668 			/*
1669 			 * Normal case; just match bssid.
1670 			 */
1671 			ni = ieee80211_find_node(&ic->ic_scan, mlme.im_macaddr);
1672 		}
1673 		if (ni == NULL)
1674 			return EINVAL;
1675 		if (!ieee80211_sta_join(ic, ni)) {
1676 			ieee80211_free_node(ni);
1677 			return EINVAL;
1678 		}
1679 		break;
1680 	case IEEE80211_MLME_DISASSOC:
1681 	case IEEE80211_MLME_DEAUTH:
1682 		switch (ic->ic_opmode) {
1683 		case IEEE80211_M_STA:
1684 			/* XXX not quite right */
1685 			ieee80211_new_state(ic, IEEE80211_S_INIT,
1686 				mlme.im_reason);
1687 			break;
1688 		case IEEE80211_M_HOSTAP:
1689 #ifndef IEEE80211_NO_HOSTAP
1690 			/* NB: the broadcast address means do 'em all */
1691 			if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
1692 				if ((ni = ieee80211_find_node(&ic->ic_sta,
1693 						mlme.im_macaddr)) == NULL)
1694 					return EINVAL;
1695 				domlme(&mlme, ni);
1696 				ieee80211_free_node(ni);
1697 			} else {
1698 				ieee80211_iterate_nodes(&ic->ic_sta,
1699 						domlme, &mlme);
1700 			}
1701 #endif /* !IEEE80211_NO_HOSTAP */
1702 			break;
1703 		default:
1704 			return EINVAL;
1705 		}
1706 		break;
1707 	case IEEE80211_MLME_AUTHORIZE:
1708 	case IEEE80211_MLME_UNAUTHORIZE:
1709 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1710 			return EINVAL;
1711 		ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
1712 		if (ni == NULL)
1713 			return EINVAL;
1714 		if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
1715 			ieee80211_node_authorize(ic, ni);
1716 		else
1717 			ieee80211_node_unauthorize(ic, ni);
1718 		ieee80211_free_node(ni);
1719 		break;
1720 	default:
1721 		return EINVAL;
1722 	}
1723 	return 0;
1724 }
1725 
1726 static int
1727 ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
1728 {
1729 	u_int8_t mac[IEEE80211_ADDR_LEN];
1730 	const struct ieee80211_aclator *acl = ic->ic_acl;
1731 	int error;
1732 
1733 	if (ireq->i_len != sizeof(mac))
1734 		return EINVAL;
1735 	error = copyin(ireq->i_data, mac, ireq->i_len);
1736 	if (error)
1737 		return error;
1738 	if (acl == NULL) {
1739 		acl = ieee80211_aclator_get("mac");
1740 		if (acl == NULL || !acl->iac_attach(ic))
1741 			return EINVAL;
1742 		ic->ic_acl = acl;
1743 	}
1744 	if (ireq->i_type == IEEE80211_IOC_ADDMAC)
1745 		acl->iac_add(ic, mac);
1746 	else
1747 		acl->iac_remove(ic, mac);
1748 	return 0;
1749 }
1750 
1751 static int
1752 ieee80211_ioctl_maccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1753 {
1754 	const struct ieee80211_aclator *acl = ic->ic_acl;
1755 
1756 	switch (ireq->i_val) {
1757 	case IEEE80211_MACCMD_POLICY_OPEN:
1758 	case IEEE80211_MACCMD_POLICY_ALLOW:
1759 	case IEEE80211_MACCMD_POLICY_DENY:
1760 		if (acl == NULL) {
1761 			acl = ieee80211_aclator_get("mac");
1762 			if (acl == NULL || !acl->iac_attach(ic))
1763 				return EINVAL;
1764 			ic->ic_acl = acl;
1765 		}
1766 		acl->iac_setpolicy(ic, ireq->i_val);
1767 		break;
1768 	case IEEE80211_MACCMD_FLUSH:
1769 		if (acl != NULL)
1770 			acl->iac_flush(ic);
1771 		/* NB: silently ignore when not in use */
1772 		break;
1773 	case IEEE80211_MACCMD_DETACH:
1774 		if (acl != NULL) {
1775 			ic->ic_acl = NULL;
1776 			acl->iac_detach(ic);
1777 		}
1778 		break;
1779 	default:
1780 		return EINVAL;
1781 	}
1782 	return 0;
1783 }
1784 
1785 static int
1786 ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
1787 {
1788 	struct ieee80211req_chanlist list;
1789 	u_char chanlist[IEEE80211_CHAN_BYTES];
1790 	int i, j, error;
1791 
1792 	if (ireq->i_len != sizeof(list))
1793 		return EINVAL;
1794 	error = copyin(ireq->i_data, &list, sizeof(list));
1795 	if (error)
1796 		return error;
1797 	memset(chanlist, 0, sizeof(chanlist));
1798 	/*
1799 	 * Since channel 0 is not available for DS, channel 1
1800 	 * is assigned to LSB on WaveLAN.
1801 	 */
1802 	if (ic->ic_phytype == IEEE80211_T_DS)
1803 		i = 1;
1804 	else
1805 		i = 0;
1806 	for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
1807 		/*
1808 		 * NB: silently discard unavailable channels so users
1809 		 *     can specify 1-255 to get all available channels.
1810 		 */
1811 		if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i))
1812 			setbit(chanlist, i);
1813 	}
1814 	if (ic->ic_ibss_chan == NULL ||
1815 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
1816 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
1817 			if (isset(chanlist, i)) {
1818 				ic->ic_ibss_chan = &ic->ic_channels[i];
1819 				goto found;
1820 			}
1821 		return EINVAL;			/* no active channels */
1822 found:
1823 		;
1824 	}
1825 	memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
1826 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
1827 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
1828 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
1829 	return IS_UP_AUTO(ic) ? ENETRESET : 0;
1830 }
1831 
1832 static int
1833 ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1834 {
1835 	struct ieee80211_node *ni;
1836 	struct ieee80211req_sta_txpow txpow;
1837 	int error;
1838 
1839 	if (ireq->i_len != sizeof(txpow))
1840 		return EINVAL;
1841 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1842 	if (error != 0)
1843 		return error;
1844 	ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1845 	if (ni == NULL)
1846 		return EINVAL;		/* XXX */
1847 	ni->ni_txpower = txpow.it_txpow;
1848 	ieee80211_free_node(ni);
1849 	return error;
1850 }
1851 
1852 static int
1853 ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1854 {
1855 	struct ieee80211_wme_state *wme = &ic->ic_wme;
1856 	struct wmeParams *wmep, *chanp;
1857 	int isbss, ac;
1858 
1859 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1860 		return EINVAL;
1861 
1862 	isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
1863 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1864 	if (ac >= WME_NUM_AC)
1865 		ac = WME_AC_BE;
1866 	if (isbss) {
1867 		chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
1868 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1869 	} else {
1870 		chanp = &wme->wme_chanParams.cap_wmeParams[ac];
1871 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1872 	}
1873 	switch (ireq->i_type) {
1874 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1875 		if (isbss) {
1876 			wmep->wmep_logcwmin = ireq->i_val;
1877 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1878 				chanp->wmep_logcwmin = ireq->i_val;
1879 		} else {
1880 			wmep->wmep_logcwmin = chanp->wmep_logcwmin =
1881 				ireq->i_val;
1882 		}
1883 		break;
1884 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
1885 		if (isbss) {
1886 			wmep->wmep_logcwmax = ireq->i_val;
1887 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1888 				chanp->wmep_logcwmax = ireq->i_val;
1889 		} else {
1890 			wmep->wmep_logcwmax = chanp->wmep_logcwmax =
1891 				ireq->i_val;
1892 		}
1893 		break;
1894 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1895 		if (isbss) {
1896 			wmep->wmep_aifsn = ireq->i_val;
1897 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1898 				chanp->wmep_aifsn = ireq->i_val;
1899 		} else {
1900 			wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
1901 		}
1902 		break;
1903 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1904 		if (isbss) {
1905 			wmep->wmep_txopLimit = ireq->i_val;
1906 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1907 				chanp->wmep_txopLimit = ireq->i_val;
1908 		} else {
1909 			wmep->wmep_txopLimit = chanp->wmep_txopLimit =
1910 				ireq->i_val;
1911 		}
1912 		break;
1913 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1914 		wmep->wmep_acm = ireq->i_val;
1915 		if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1916 			chanp->wmep_acm = ireq->i_val;
1917 		break;
1918 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
1919 		wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
1920 			(ireq->i_val) == 0;
1921 		break;
1922 	}
1923 	ieee80211_wme_updateparams(ic);
1924 	return 0;
1925 }
1926 
1927 static int
1928 cipher2cap(int cipher)
1929 {
1930 	switch (cipher) {
1931 	case IEEE80211_CIPHER_WEP:	return IEEE80211_C_WEP;
1932 	case IEEE80211_CIPHER_AES_OCB:	return IEEE80211_C_AES;
1933 	case IEEE80211_CIPHER_AES_CCM:	return IEEE80211_C_AES_CCM;
1934 	case IEEE80211_CIPHER_CKIP:	return IEEE80211_C_CKIP;
1935 	case IEEE80211_CIPHER_TKIP:	return IEEE80211_C_TKIP;
1936 	}
1937 	return 0;
1938 }
1939 
1940 static int
1941 ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1942 {
1943 #ifdef __FreeBSD__
1944 	static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
1945 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1946 	char tmpssid[IEEE80211_NWID_LEN];
1947 	u_int8_t tmpbssid[IEEE80211_ADDR_LEN];
1948 	struct ieee80211_key *k;
1949 	u_int kid;
1950 #endif /* __FreeBSD__ */
1951 	struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1952 	int error;
1953 	const struct ieee80211_authenticator *auth;
1954 	int j, caps;
1955 
1956 	error = 0;
1957 	switch (ireq->i_type) {
1958 #ifdef __FreeBSD__
1959 	case IEEE80211_IOC_SSID:
1960 		if (ireq->i_val != 0 ||
1961 		    ireq->i_len > IEEE80211_NWID_LEN)
1962 			return EINVAL;
1963 		error = copyin(ireq->i_data, tmpssid, ireq->i_len);
1964 		if (error)
1965 			break;
1966 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
1967 		ic->ic_des_esslen = ireq->i_len;
1968 		memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
1969 		error = ENETRESET;
1970 		break;
1971 #endif /* __FreeBSD__ */
1972 	case IEEE80211_IOC_WEP:
1973 		switch (ireq->i_val) {
1974 		case IEEE80211_WEP_OFF:
1975 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1976 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1977 			break;
1978 		case IEEE80211_WEP_ON:
1979 			ic->ic_flags |= IEEE80211_F_PRIVACY;
1980 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
1981 			break;
1982 		case IEEE80211_WEP_MIXED:
1983 			ic->ic_flags |= IEEE80211_F_PRIVACY;
1984 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1985 			break;
1986 		}
1987 		error = ENETRESET;
1988 		break;
1989 #ifdef __FreeBSD__
1990 	case IEEE80211_IOC_WEPKEY:
1991 		kid = (u_int) ireq->i_val;
1992 		if (kid >= IEEE80211_WEP_NKID)
1993 			return EINVAL;
1994 		k = &ic->ic_nw_keys[kid];
1995 		if (ireq->i_len == 0) {
1996 			/* zero-len =>'s delete any existing key */
1997 			(void) ieee80211_crypto_delkey(ic, k);
1998 			break;
1999 		}
2000 		if (ireq->i_len > sizeof(tmpkey))
2001 			return EINVAL;
2002 		memset(tmpkey, 0, sizeof(tmpkey));
2003 		error = copyin(ireq->i_data, tmpkey, ireq->i_len);
2004 		if (error)
2005 			break;
2006 		ieee80211_key_update_begin(ic);
2007 		k->wk_keyix = kid;	/* NB: force fixed key id */
2008 		if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
2009 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
2010 			k->wk_keylen = ireq->i_len;
2011 			memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
2012 			if  (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
2013 				error = EINVAL;
2014 		} else
2015 			error = EINVAL;
2016 		ieee80211_key_update_end(ic);
2017 		if (!error)			/* NB: for compatibility */
2018 			error = ENETRESET;
2019 		break;
2020 	case IEEE80211_IOC_WEPTXKEY:
2021 		kid = (u_int) ireq->i_val;
2022 		if (kid >= IEEE80211_WEP_NKID &&
2023 		    (u_int16_t) kid != IEEE80211_KEYIX_NONE)
2024 			return EINVAL;
2025 		ic->ic_def_txkey = kid;
2026 		error = ENETRESET;	/* push to hardware */
2027 		break;
2028 #endif /* __FreeBSD__ */
2029 	case IEEE80211_IOC_AUTHMODE:
2030 		switch (ireq->i_val) {
2031 		case IEEE80211_AUTH_WPA:
2032 		case IEEE80211_AUTH_8021X:	/* 802.1x */
2033 		case IEEE80211_AUTH_OPEN:	/* open */
2034 		case IEEE80211_AUTH_SHARED:	/* shared-key */
2035 		case IEEE80211_AUTH_AUTO:	/* auto */
2036 			auth = ieee80211_authenticator_get(ireq->i_val);
2037 			if (auth == NULL)
2038 				return EINVAL;
2039 			break;
2040 		default:
2041 			return EINVAL;
2042 		}
2043 		switch (ireq->i_val) {
2044 		case IEEE80211_AUTH_WPA:	/* WPA w/ 802.1x */
2045 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2046 			ireq->i_val = IEEE80211_AUTH_8021X;
2047 			break;
2048 		case IEEE80211_AUTH_OPEN:	/* open */
2049 			ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
2050 			break;
2051 		case IEEE80211_AUTH_SHARED:	/* shared-key */
2052 		case IEEE80211_AUTH_8021X:	/* 802.1x */
2053 			ic->ic_flags &= ~IEEE80211_F_WPA;
2054 			/* both require a key so mark the PRIVACY capability */
2055 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2056 			break;
2057 		case IEEE80211_AUTH_AUTO:	/* auto */
2058 			ic->ic_flags &= ~IEEE80211_F_WPA;
2059 			/* XXX PRIVACY handling? */
2060 			/* XXX what's the right way to do this? */
2061 			break;
2062 		}
2063 		/* NB: authenticator attach/detach happens on state change */
2064 		ic->ic_bss->ni_authmode = ireq->i_val;
2065 		/* XXX mixed/mode/usage? */
2066 		ic->ic_auth = auth;
2067 		error = ENETRESET;
2068 		break;
2069 #ifdef __FreeBSD__
2070 	case IEEE80211_IOC_CHANNEL:
2071 		/* XXX 0xffff overflows 16-bit signed */
2072 		if (ireq->i_val == 0 ||
2073 		    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
2074 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
2075 		else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
2076 		    isclr(ic->ic_chan_active, ireq->i_val)) {
2077 			return EINVAL;
2078 		} else
2079 			ic->ic_ibss_chan = ic->ic_des_chan =
2080 				&ic->ic_channels[ireq->i_val];
2081 		switch (ic->ic_state) {
2082 		case IEEE80211_S_INIT:
2083 		case IEEE80211_S_SCAN:
2084 			error = ENETRESET;
2085 			break;
2086 		default:
2087 			/*
2088 			 * If the desired channel has changed (to something
2089 			 * other than any) and we're not already scanning,
2090 			 * then kick the state machine.
2091 			 */
2092 			if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
2093 			    ic->ic_bss->ni_chan != ic->ic_des_chan &&
2094 			    (ic->ic_flags & IEEE80211_F_SCAN) == 0)
2095 				error = ENETRESET;
2096 			break;
2097 		}
2098 		if (error == ENETRESET && ic->ic_opmode == IEEE80211_M_MONITOR)
2099 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2100 		break;
2101 	case IEEE80211_IOC_POWERSAVE:
2102 		switch (ireq->i_val) {
2103 		case IEEE80211_POWERSAVE_OFF:
2104 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
2105 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
2106 				error = ENETRESET;
2107 			}
2108 			break;
2109 		case IEEE80211_POWERSAVE_ON:
2110 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2111 				error = EINVAL;
2112 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2113 				ic->ic_flags |= IEEE80211_F_PMGTON;
2114 				error = ENETRESET;
2115 			}
2116 			break;
2117 		default:
2118 			error = EINVAL;
2119 			break;
2120 		}
2121 		break;
2122 	case IEEE80211_IOC_POWERSAVESLEEP:
2123 		if (ireq->i_val < 0)
2124 			return EINVAL;
2125 		ic->ic_lintval = ireq->i_val;
2126 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2127 		break;
2128 #endif /* __FreeBSD__ */
2129 	case IEEE80211_IOC_RTSTHRESHOLD:
2130 		if (!(IEEE80211_RTS_MIN < ireq->i_val &&
2131 		      ireq->i_val < IEEE80211_RTS_MAX))
2132 			return EINVAL;
2133 		ic->ic_rtsthreshold = ireq->i_val;
2134 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2135 		break;
2136 	case IEEE80211_IOC_PROTMODE:
2137 		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2138 			return EINVAL;
2139 		ic->ic_protmode = ireq->i_val;
2140 		/* NB: if not operating in 11g this can wait */
2141 		if (ic->ic_curmode == IEEE80211_MODE_11G)
2142 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2143 		break;
2144 	case IEEE80211_IOC_TXPOWER:
2145 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2146 			return EINVAL;
2147 		if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
2148 		      ireq->i_val < IEEE80211_TXPOWER_MAX))
2149 			return EINVAL;
2150 		ic->ic_txpowlimit = ireq->i_val;
2151 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2152 		break;
2153 	case IEEE80211_IOC_ROAMING:
2154 		if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2155 		    ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2156 			return EINVAL;
2157 		ic->ic_roaming = ireq->i_val;
2158 		/* XXXX reset? */
2159 		break;
2160 	case IEEE80211_IOC_PRIVACY:
2161 		if (ireq->i_val) {
2162 			/* XXX check for key state? */
2163 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2164 		} else
2165 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2166 		break;
2167 	case IEEE80211_IOC_DROPUNENCRYPTED:
2168 		if (ireq->i_val)
2169 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
2170 		else
2171 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2172 		break;
2173 	case IEEE80211_IOC_WPAKEY:
2174 		error = ieee80211_ioctl_setkey(ic, ireq);
2175 		break;
2176 	case IEEE80211_IOC_DELKEY:
2177 		error = ieee80211_ioctl_delkey(ic, ireq);
2178 		break;
2179 	case IEEE80211_IOC_MLME:
2180 		error = ieee80211_ioctl_setmlme(ic, ireq);
2181 		break;
2182 	case IEEE80211_IOC_OPTIE:
2183 		error = ieee80211_ioctl_setoptie(ic, ireq);
2184 		break;
2185 	case IEEE80211_IOC_COUNTERMEASURES:
2186 		if (ireq->i_val) {
2187 			if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
2188 				return EINVAL;
2189 			ic->ic_flags |= IEEE80211_F_COUNTERM;
2190 		} else
2191 			ic->ic_flags &= ~IEEE80211_F_COUNTERM;
2192 		break;
2193 	case IEEE80211_IOC_WPA:
2194 		if (ireq->i_val > 3)
2195 			return EINVAL;
2196 		/* XXX verify ciphers available */
2197 		ic->ic_flags &= ~IEEE80211_F_WPA;
2198 		switch (ireq->i_val) {
2199 		case 1:
2200 			ic->ic_flags |= IEEE80211_F_WPA1;
2201 			break;
2202 		case 2:
2203 			ic->ic_flags |= IEEE80211_F_WPA2;
2204 			break;
2205 		case 3:
2206 			ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
2207 			break;
2208 		}
2209 		error = ENETRESET;		/* XXX? */
2210 		break;
2211 	case IEEE80211_IOC_WME:
2212 		if (ireq->i_val) {
2213 			if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2214 				return EINVAL;
2215 			ic->ic_flags |= IEEE80211_F_WME;
2216 		} else
2217 			ic->ic_flags &= ~IEEE80211_F_WME;
2218 		error = ENETRESET;		/* XXX maybe not for station? */
2219 		break;
2220 	case IEEE80211_IOC_HIDESSID:
2221 		if (ireq->i_val)
2222 			ic->ic_flags |= IEEE80211_F_HIDESSID;
2223 		else
2224 			ic->ic_flags &= ~IEEE80211_F_HIDESSID;
2225 		error = ENETRESET;
2226 		break;
2227 	case IEEE80211_IOC_APBRIDGE:
2228 		if (ireq->i_val == 0)
2229 			ic->ic_flags |= IEEE80211_F_NOBRIDGE;
2230 		else
2231 			ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
2232 		break;
2233 	case IEEE80211_IOC_MCASTCIPHER:
2234 		if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
2235 		    !ieee80211_crypto_available(ireq->i_val))
2236 			return EINVAL;
2237 		rsn->rsn_mcastcipher = ireq->i_val;
2238 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2239 		break;
2240 	case IEEE80211_IOC_MCASTKEYLEN:
2241 		if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2242 			return EINVAL;
2243 		/* XXX no way to verify driver capability */
2244 		rsn->rsn_mcastkeylen = ireq->i_val;
2245 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2246 		break;
2247 	case IEEE80211_IOC_UCASTCIPHERS:
2248 		/*
2249 		 * Convert user-specified cipher set to the set
2250 		 * we can support (via hardware or software).
2251 		 * NB: this logic intentionally ignores unknown and
2252 		 * unsupported ciphers so folks can specify 0xff or
2253 		 * similar and get all available ciphers.
2254 		 */
2255 		caps = 0;
2256 		for (j = 1; j < 32; j++)	/* NB: skip WEP */
2257 			if ((ireq->i_val & (1<<j)) &&
2258 			    ((ic->ic_caps & cipher2cap(j)) ||
2259 			     ieee80211_crypto_available(j)))
2260 				caps |= 1<<j;
2261 		if (caps == 0)			/* nothing available */
2262 			return EINVAL;
2263 		/* XXX verify ciphers ok for unicast use? */
2264 		/* XXX disallow if running as it'll have no effect */
2265 		rsn->rsn_ucastcipherset = caps;
2266 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2267 		break;
2268 	case IEEE80211_IOC_UCASTCIPHER:
2269 		if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
2270 			return EINVAL;
2271 		rsn->rsn_ucastcipher = ireq->i_val;
2272 		break;
2273 	case IEEE80211_IOC_UCASTKEYLEN:
2274 		if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2275 			return EINVAL;
2276 		/* XXX no way to verify driver capability */
2277 		rsn->rsn_ucastkeylen = ireq->i_val;
2278 		break;
2279 	case IEEE80211_IOC_DRIVER_CAPS:
2280 		/* NB: for testing */
2281 		ic->ic_caps = (((u_int16_t) ireq->i_val) << 16) |
2282 			       ((u_int16_t) ireq->i_len);
2283 		break;
2284 	case IEEE80211_IOC_KEYMGTALGS:
2285 		/* XXX check */
2286 		rsn->rsn_keymgmtset = ireq->i_val;
2287 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2288 		break;
2289 	case IEEE80211_IOC_RSNCAPS:
2290 		/* XXX check */
2291 		rsn->rsn_caps = ireq->i_val;
2292 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2293 		break;
2294 #ifdef __FreeBSD__
2295 	case IEEE80211_IOC_BSSID:
2296 		/* NB: should only be set when in STA mode */
2297 		if (ic->ic_opmode != IEEE80211_M_STA)
2298 			return EINVAL;
2299 		if (ireq->i_len != sizeof(tmpbssid))
2300 			return EINVAL;
2301 		error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
2302 		if (error)
2303 			break;
2304 		IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
2305 		if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
2306 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2307 		else
2308 			ic->ic_flags |= IEEE80211_F_DESBSSID;
2309 		error = ENETRESET;
2310 		break;
2311 #endif /* __FreeBSD__ */
2312 	case IEEE80211_IOC_CHANLIST:
2313 		error = ieee80211_ioctl_setchanlist(ic, ireq);
2314 		break;
2315 	case IEEE80211_IOC_SCAN_REQ:
2316 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)	/* XXX ignore */
2317 			break;
2318 		error = ieee80211_setupscan(ic, ic->ic_chan_avail);
2319 		if (error == 0)		/* XXX background scan */
2320 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2321 		break;
2322 	case IEEE80211_IOC_ADDMAC:
2323 	case IEEE80211_IOC_DELMAC:
2324 		error = ieee80211_ioctl_macmac(ic, ireq);
2325 		break;
2326 	case IEEE80211_IOC_MACCMD:
2327 		error = ieee80211_ioctl_maccmd(ic, ireq);
2328 		break;
2329 	case IEEE80211_IOC_STA_TXPOW:
2330 		error = ieee80211_ioctl_setstatxpow(ic, ireq);
2331 		break;
2332 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
2333 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
2334 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
2335 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
2336 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
2337 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
2338 		error = ieee80211_ioctl_setwmeparam(ic, ireq);
2339 		break;
2340 	case IEEE80211_IOC_DTIM_PERIOD:
2341 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2342 		    ic->ic_opmode != IEEE80211_M_IBSS)
2343 			return EINVAL;
2344 		if (IEEE80211_DTIM_MIN <= ireq->i_val &&
2345 		    ireq->i_val <= IEEE80211_DTIM_MAX) {
2346 			ic->ic_dtim_period = ireq->i_val;
2347 			error = ENETRESET;		/* requires restart */
2348 		} else
2349 			error = EINVAL;
2350 		break;
2351 	case IEEE80211_IOC_BEACON_INTERVAL:
2352 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2353 		    ic->ic_opmode != IEEE80211_M_IBSS)
2354 			return EINVAL;
2355 		if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
2356 		    ireq->i_val <= IEEE80211_BINTVAL_MAX) {
2357 			ic->ic_lintval = ireq->i_val;
2358 			error = ENETRESET;		/* requires restart */
2359 		} else
2360 			error = EINVAL;
2361 		break;
2362 	case IEEE80211_IOC_PUREG:
2363 		if (ireq->i_val)
2364 			ic->ic_flags |= IEEE80211_F_PUREG;
2365 		else
2366 			ic->ic_flags &= ~IEEE80211_F_PUREG;
2367 		/* NB: reset only if we're operating on an 11g channel */
2368 		if (ic->ic_curmode == IEEE80211_MODE_11G)
2369 			error = ENETRESET;
2370 		break;
2371 	default:
2372 		error = EINVAL;
2373 		break;
2374 	}
2375 	if (error == ENETRESET && !IS_UP_AUTO(ic))
2376 		error = 0;
2377 	return error;
2378 }
2379 
2380 #ifdef __FreeBSD__
2381 int
2382 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2383 {
2384 	struct ifnet *ifp = ic->ic_ifp;
2385 	int error = 0;
2386 	struct ifreq *ifr;
2387 	struct ifaddr *ifa;			/* XXX */
2388 
2389 	switch (cmd) {
2390 	case SIOCSIFMEDIA:
2391 	case SIOCGIFMEDIA:
2392 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
2393 				&ic->ic_media, cmd);
2394 		break;
2395 	case SIOCG80211:
2396 		error = ieee80211_ioctl_get80211(ic, cmd,
2397 				(struct ieee80211req *) data);
2398 		break;
2399 	case SIOCS80211:
2400 		error = suser(curthread);
2401 		if (error == 0)
2402 			error = ieee80211_ioctl_set80211(ic, cmd,
2403 					(struct ieee80211req *) data);
2404 		break;
2405 	case SIOCGIFGENERIC:
2406 		error = ieee80211_cfgget(ic, cmd, data);
2407 		break;
2408 	case SIOCSIFGENERIC:
2409 		error = suser(curthread);
2410 		if (error)
2411 			break;
2412 		error = ieee80211_cfgset(ic, cmd, data);
2413 		break;
2414 	case SIOCG80211STATS:
2415 		ifr = (struct ifreq *)data;
2416 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
2417 		break;
2418 	case SIOCSIFMTU:
2419 		ifr = (struct ifreq *)data;
2420 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
2421 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
2422 			error = EINVAL;
2423 		else
2424 			ifp->if_mtu = ifr->ifr_mtu;
2425 		break;
2426 	case SIOCSIFADDR:
2427 		/*
2428 		 * XXX Handle this directly so we can supress if_init calls.
2429 		 * XXX This should be done in ether_ioctl but for the moment
2430 		 * XXX there are too many other parts of the system that
2431 		 * XXX set IFF_UP and so supress if_init being called when
2432 		 * XXX it should be.
2433 		 */
2434 		ifa = (struct ifaddr *) data;
2435 		switch (ifa->ifa_addr->sa_family) {
2436 #ifdef INET
2437 		case AF_INET:
2438 			if ((ifp->if_flags & IFF_UP) == 0) {
2439 				ifp->if_flags |= IFF_UP;
2440 				ifp->if_init(ifp->if_softc);
2441 			}
2442 			arp_ifinit(ifp, ifa);
2443 			break;
2444 #endif
2445 #ifdef IPX
2446 		/*
2447 		 * XXX - This code is probably wrong,
2448 		 *	 but has been copied many times.
2449 		 */
2450 		case AF_IPX: {
2451 			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
2452 
2453 			if (ipx_nullhost(*ina))
2454 				ina->x_host = *(union ipx_host *)
2455 				    IFP2ENADDR(ifp);
2456 			else
2457 				bcopy((caddr_t) ina->x_host.c_host,
2458 				      (caddr_t) IFP2ENADDR(ifp),
2459 				      ETHER_ADDR_LEN);
2460 			/* fall thru... */
2461 		}
2462 #endif
2463 		default:
2464 			if ((ifp->if_flags & IFF_UP) == 0) {
2465 				ifp->if_flags |= IFF_UP;
2466 				ifp->if_init(ifp->if_softc);
2467 			}
2468 			break;
2469 		}
2470 		break;
2471 	default:
2472 		error = ether_ioctl(ifp, cmd, data);
2473 		break;
2474 	}
2475 	return error;
2476 }
2477 #endif /* __FreeBSD__ */
2478 
2479 #ifdef COMPAT_20
2480 static void
2481 ieee80211_get_ostats(struct ieee80211_ostats *ostats,
2482     struct ieee80211_stats *stats)
2483 {
2484 #define	COPYSTATS1(__ostats, __nstats, __dstmemb, __srcmemb, __lastmemb)\
2485 	(void)memcpy(&(__ostats)->__dstmemb, &(__nstats)->__srcmemb,	\
2486 	    offsetof(struct ieee80211_stats, __lastmemb) -		\
2487 	    offsetof(struct ieee80211_stats, __srcmemb))
2488 #define	COPYSTATS(__ostats, __nstats, __dstmemb, __lastmemb)		\
2489 	COPYSTATS1(__ostats, __nstats, __dstmemb, __dstmemb, __lastmemb)
2490 
2491 	COPYSTATS(ostats, stats, is_rx_badversion, is_rx_unencrypted);
2492 	COPYSTATS(ostats, stats, is_rx_wepfail, is_rx_beacon);
2493 	COPYSTATS(ostats, stats, is_rx_rstoobig, is_rx_auth_countermeasures);
2494 	COPYSTATS(ostats, stats, is_rx_assoc_bss, is_rx_assoc_badwpaie);
2495 	COPYSTATS(ostats, stats, is_rx_deauth, is_rx_unauth);
2496 	COPYSTATS1(ostats, stats, is_tx_nombuf, is_tx_nobuf, is_tx_badcipher);
2497 	COPYSTATS(ostats, stats, is_scan_active, is_crypto_tkip);
2498 }
2499 #endif /* COMPAT_20 */
2500 
2501 #ifdef __NetBSD__
2502 int
2503 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2504 {
2505 	struct ifnet *ifp = ic->ic_ifp;
2506 	struct ifreq *ifr = (struct ifreq *)data;
2507 	int i, error = 0, kid, klen, s;
2508 	struct ieee80211_key *k;
2509 	struct ieee80211_nwid nwid;
2510 	struct ieee80211_nwkey *nwkey;
2511 	struct ieee80211_power *power;
2512 	struct ieee80211_bssid *bssid;
2513 	struct ieee80211chanreq *chanreq;
2514 	struct ieee80211_channel *chan;
2515 	uint32_t oflags;
2516 #ifdef COMPAT_20
2517 	struct ieee80211_ostats ostats;
2518 #endif /* COMPAT_20 */
2519 	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
2520 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2521 	};
2522 	u_int8_t tmpkey[IEEE80211_WEP_NKID][IEEE80211_KEYBUF_SIZE];
2523 
2524 	switch (cmd) {
2525 	case SIOCSIFMEDIA:
2526 	case SIOCGIFMEDIA:
2527 		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
2528 		break;
2529 	case SIOCG80211:
2530 		error = ieee80211_ioctl_get80211(ic, cmd,
2531 				(struct ieee80211req *) data);
2532 		break;
2533 	case SIOCS80211:
2534 		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
2535 			break;
2536 		error = ieee80211_ioctl_set80211(ic, cmd,
2537 				(struct ieee80211req *) data);
2538 		break;
2539 	case SIOCS80211NWID:
2540 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
2541 			break;
2542 		if (nwid.i_len > IEEE80211_NWID_LEN) {
2543 			error = EINVAL;
2544 			break;
2545 		}
2546 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
2547 		ic->ic_des_esslen = nwid.i_len;
2548 		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
2549 		error = ENETRESET;
2550 		break;
2551 	case SIOCG80211NWID:
2552 		memset(&nwid, 0, sizeof(nwid));
2553 		switch (ic->ic_state) {
2554 		case IEEE80211_S_INIT:
2555 		case IEEE80211_S_SCAN:
2556 			nwid.i_len = ic->ic_des_esslen;
2557 			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
2558 			break;
2559 		default:
2560 			nwid.i_len = ic->ic_bss->ni_esslen;
2561 			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
2562 			break;
2563 		}
2564 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
2565 		break;
2566 	case SIOCS80211NWKEY:
2567 		nwkey = (struct ieee80211_nwkey *)data;
2568 		/* transmit key index out of range? */
2569 		kid = nwkey->i_defkid - 1;
2570 		if (kid < 0 || kid >= IEEE80211_WEP_NKID) {
2571 			error = EINVAL;
2572 			break;
2573 		}
2574 		/* no such transmit key is set? */
2575 		if (nwkey->i_key[kid].i_keylen == 0 ||
2576 		    (nwkey->i_key[kid].i_keylen == -1 &&
2577 		     ic->ic_nw_keys[kid].wk_keylen == 0)) {
2578 			if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
2579 				error = EINVAL;
2580 				break;
2581 			}
2582 		}
2583 		/* check key lengths */
2584 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2585 			klen = nwkey->i_key[kid].i_keylen;
2586 			if ((klen > 0 &&
2587 			    klen < IEEE80211_WEP_KEYLEN) ||
2588 			    klen > sizeof(ic->ic_nw_keys[kid].wk_key)) {
2589 				error = EINVAL;
2590 				break;
2591 			}
2592 		}
2593 
2594 		if (error)
2595 			break;
2596 
2597 		/* copy in keys */
2598 		(void)memset(tmpkey, 0, sizeof(tmpkey));
2599 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2600 			klen = nwkey->i_key[kid].i_keylen;
2601 			if (klen <= 0)
2602 				continue;
2603 			if ((error = copyin(nwkey->i_key[kid].i_keydat,
2604 			    tmpkey[kid], klen)) != 0)
2605 				break;
2606 		}
2607 
2608 		if (error)
2609 			break;
2610 
2611 		/* set keys */
2612 		ieee80211_key_update_begin(ic);
2613 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2614 			klen = nwkey->i_key[kid].i_keylen;
2615 			if (klen <= 0)
2616 				continue;
2617 			k = &ic->ic_nw_keys[kid];
2618 			k->wk_keyix = kid;
2619 			if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
2620 			    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
2621 				error = EINVAL;
2622 				continue;
2623 			}
2624 			k->wk_keylen = nwkey->i_key[kid].i_keylen;
2625 			(void)memcpy(k->wk_key, tmpkey[kid],
2626 			    sizeof(tmpkey[kid]));
2627 			if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
2628 				error = EINVAL;
2629 		}
2630 		ieee80211_key_update_end(ic);
2631 
2632 		if (error)
2633 			break;
2634 
2635 		/* delete keys */
2636 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2637 			klen = nwkey->i_key[kid].i_keylen;
2638 			k = &ic->ic_nw_keys[kid];
2639 			if (klen <= 0)
2640 				(void)ieee80211_crypto_delkey(ic, k);
2641 		}
2642 
2643 		/* set transmit key */
2644 		kid = nwkey->i_defkid - 1;
2645 		if (ic->ic_def_txkey != kid) {
2646 			ic->ic_def_txkey = kid;
2647 			error = ENETRESET;
2648 		}
2649 		oflags = ic->ic_flags;
2650 		if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
2651 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2652 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2653 		} else {
2654 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2655 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
2656 		}
2657 		if (oflags != ic->ic_flags)
2658 			error = ENETRESET;
2659 		break;
2660 	case SIOCG80211NWKEY:
2661 		nwkey = (struct ieee80211_nwkey *)data;
2662 		if (ic->ic_flags & IEEE80211_F_PRIVACY)
2663 			nwkey->i_wepon = IEEE80211_NWKEY_WEP;
2664 		else
2665 			nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
2666 		nwkey->i_defkid = ic->ic_def_txkey + 1;
2667 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2668 			if (nwkey->i_key[i].i_keydat == NULL)
2669 				continue;
2670 			/* do not show any keys to non-root user */
2671 			if ((error = suser(curproc->p_ucred,
2672 			    &curproc->p_acflag)) != 0)
2673 				break;
2674 			nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_keylen;
2675 			if ((error = copyout(ic->ic_nw_keys[i].wk_key,
2676 			    nwkey->i_key[i].i_keydat,
2677 			    ic->ic_nw_keys[i].wk_keylen)) != 0)
2678 				break;
2679 		}
2680 		break;
2681 	case SIOCS80211POWER:
2682 		power = (struct ieee80211_power *)data;
2683 		ic->ic_lintval = power->i_maxsleep;
2684 		if (power->i_enabled != 0) {
2685 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2686 				error = EINVAL;
2687 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2688 				ic->ic_flags |= IEEE80211_F_PMGTON;
2689 				error = ENETRESET;
2690 			}
2691 		} else {
2692 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
2693 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
2694 				error = ENETRESET;
2695 			}
2696 		}
2697 		break;
2698 	case SIOCG80211POWER:
2699 		power = (struct ieee80211_power *)data;
2700 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
2701 		power->i_maxsleep = ic->ic_lintval;
2702 		break;
2703 	case SIOCS80211BSSID:
2704 		bssid = (struct ieee80211_bssid *)data;
2705 		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
2706 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2707 		else {
2708 			ic->ic_flags |= IEEE80211_F_DESBSSID;
2709 			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
2710 		}
2711 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2712 			break;
2713 		switch (ic->ic_state) {
2714 		case IEEE80211_S_INIT:
2715 		case IEEE80211_S_SCAN:
2716 			error = ENETRESET;
2717 			break;
2718 		default:
2719 			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
2720 			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
2721 			    ic->ic_bss->ni_bssid))
2722 				error = ENETRESET;
2723 			break;
2724 		}
2725 		break;
2726 	case SIOCG80211BSSID:
2727 		bssid = (struct ieee80211_bssid *)data;
2728 		switch (ic->ic_state) {
2729 		case IEEE80211_S_INIT:
2730 		case IEEE80211_S_SCAN:
2731 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2732 				IEEE80211_ADDR_COPY(bssid->i_bssid,
2733 				    ic->ic_myaddr);
2734 			else if (ic->ic_flags & IEEE80211_F_DESBSSID)
2735 				IEEE80211_ADDR_COPY(bssid->i_bssid,
2736 				    ic->ic_des_bssid);
2737 			else
2738 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
2739 			break;
2740 		default:
2741 			IEEE80211_ADDR_COPY(bssid->i_bssid,
2742 			    ic->ic_bss->ni_bssid);
2743 			break;
2744 		}
2745 		break;
2746 	case SIOCS80211CHANNEL:
2747 		chanreq = (struct ieee80211chanreq *)data;
2748 		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
2749 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
2750 		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
2751 		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
2752 			error = EINVAL;
2753 			break;
2754 		} else
2755 			ic->ic_ibss_chan = ic->ic_des_chan =
2756 			    &ic->ic_channels[chanreq->i_channel];
2757 		switch (ic->ic_state) {
2758 		case IEEE80211_S_INIT:
2759 		case IEEE80211_S_SCAN:
2760 			error = ENETRESET;
2761 			break;
2762 		default:
2763 			if (ic->ic_opmode == IEEE80211_M_STA) {
2764 				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
2765 				    ic->ic_bss->ni_chan != ic->ic_des_chan)
2766 					error = ENETRESET;
2767 			} else {
2768 				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
2769 					error = ENETRESET;
2770 			}
2771 			break;
2772 		}
2773 		break;
2774 	case SIOCG80211CHANNEL:
2775 		chanreq = (struct ieee80211chanreq *)data;
2776 		switch (ic->ic_state) {
2777 		case IEEE80211_S_INIT:
2778 		case IEEE80211_S_SCAN:
2779 			if (ic->ic_opmode == IEEE80211_M_STA)
2780 				chan = ic->ic_des_chan;
2781 			else
2782 				chan = ic->ic_ibss_chan;
2783 			break;
2784 		default:
2785 			chan = ic->ic_bss->ni_chan;
2786 			break;
2787 		}
2788 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
2789 		break;
2790 	case SIOCGIFGENERIC:
2791 		error = ieee80211_cfgget(ic, cmd, data);
2792 		break;
2793 	case SIOCSIFGENERIC:
2794 		error = suser(curproc->p_ucred, &curproc->p_acflag);
2795 		if (error)
2796 			break;
2797 		error = ieee80211_cfgset(ic, cmd, data);
2798 		break;
2799 #ifdef COMPAT_20
2800 	case OSIOCG80211STATS:
2801 	case OSIOCG80211ZSTATS:
2802 		ifr = (struct ifreq *)data;
2803 		s = splnet();
2804 		ieee80211_get_ostats(&ostats, &ic->ic_stats);
2805 		error = copyout(&ostats, ifr->ifr_data, sizeof(ostats));
2806 		if (error == 0 && cmd == OSIOCG80211ZSTATS)
2807 			(void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
2808 		splx(s);
2809 		break;
2810 #endif /* COMPAT_20 */
2811 	case SIOCG80211ZSTATS:
2812 	case SIOCG80211STATS:
2813 		ifr = (struct ifreq *)data;
2814 		s = splnet();
2815 		error = copyout(&ic->ic_stats, ifr->ifr_buf,
2816 		    MIN(sizeof(ic->ic_stats), ifr->ifr_buflen));
2817 		if (error == 0 && cmd == SIOCG80211ZSTATS)
2818 			(void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
2819 		splx(s);
2820 		break;
2821 	case SIOCSIFMTU:
2822 		ifr = (struct ifreq *)data;
2823 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
2824 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
2825 			error = EINVAL;
2826 		else
2827 			ifp->if_mtu = ifr->ifr_mtu;
2828 		break;
2829 	default:
2830 		error = ether_ioctl(ifp, cmd, data);
2831 		break;
2832 	}
2833 	return error;
2834 }
2835 #endif /* __NetBSD__ */
2836