xref: /netbsd-src/sys/net80211/ieee80211_ioctl.c (revision bf1e9b32e27832f0c493206710fb8b58a980838a)
1 /*	$NetBSD: ieee80211_ioctl.c,v 1.20 2005/06/26 04:31:51 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.18 2005/01/24 19:32:09 sam Exp $");
37 #endif
38 #ifdef __NetBSD__
39 __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.20 2005/06/26 04:31:51 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 static struct ieee80211_channel *
845 getcurchan(struct ieee80211com *ic)
846 {
847 	switch (ic->ic_state) {
848 	case IEEE80211_S_INIT:
849 	case IEEE80211_S_SCAN:
850 		return ic->ic_des_chan;
851 	default:
852 		return ic->ic_ibss_chan;
853 	}
854 }
855 
856 static int
857 cap2cipher(int flag)
858 {
859 	switch (flag) {
860 	case IEEE80211_C_WEP:		return IEEE80211_CIPHER_WEP;
861 	case IEEE80211_C_AES:		return IEEE80211_CIPHER_AES_OCB;
862 	case IEEE80211_C_AES_CCM:	return IEEE80211_CIPHER_AES_CCM;
863 	case IEEE80211_C_CKIP:		return IEEE80211_CIPHER_CKIP;
864 	case IEEE80211_C_TKIP:		return IEEE80211_CIPHER_TKIP;
865 	}
866 	return -1;
867 }
868 
869 static int
870 ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
871 {
872 	struct ieee80211_node *ni;
873 	struct ieee80211req_key ik;
874 	struct ieee80211_key *wk;
875 	const struct ieee80211_cipher *cip;
876 	u_int kid;
877 	int error;
878 
879 	if (ireq->i_len != sizeof(ik))
880 		return EINVAL;
881 	error = copyin(ireq->i_data, &ik, sizeof(ik));
882 	if (error)
883 		return error;
884 	kid = ik.ik_keyix;
885 	if (kid == IEEE80211_KEYIX_NONE) {
886 		ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
887 		if (ni == NULL)
888 			return EINVAL;		/* XXX */
889 		wk = &ni->ni_ucastkey;
890 	} else {
891 		if (kid >= IEEE80211_WEP_NKID)
892 			return EINVAL;
893 		wk = &ic->ic_nw_keys[kid];
894 		IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
895 		ni = NULL;
896 	}
897 	cip = wk->wk_cipher;
898 	ik.ik_type = cip->ic_cipher;
899 	ik.ik_keylen = wk->wk_keylen;
900 	ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
901 	if (wk->wk_keyix == ic->ic_def_txkey)
902 		ik.ik_flags |= IEEE80211_KEY_DEFAULT;
903 	if (suser(curproc->p_ucred, &curproc->p_acflag) == 0) {
904 		/* NB: only root can read key data */
905 		ik.ik_keyrsc = wk->wk_keyrsc;
906 		ik.ik_keytsc = wk->wk_keytsc;
907 		memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
908 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
909 			memcpy(ik.ik_keydata+wk->wk_keylen,
910 				wk->wk_key + IEEE80211_KEYBUF_SIZE,
911 				IEEE80211_MICBUF_SIZE);
912 			ik.ik_keylen += IEEE80211_MICBUF_SIZE;
913 		}
914 	} else {
915 		ik.ik_keyrsc = 0;
916 		ik.ik_keytsc = 0;
917 		memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
918 	}
919 	if (ni != NULL)
920 		ieee80211_free_node(ni);
921 	return copyout(&ik, ireq->i_data, sizeof(ik));
922 }
923 
924 static int
925 ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
926 {
927 
928 	if (sizeof(ic->ic_chan_active) > ireq->i_len)
929 		ireq->i_len = sizeof(ic->ic_chan_active);
930 	return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
931 }
932 
933 static int
934 ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
935 {
936 	struct ieee80211req_chaninfo chans;	/* XXX off stack? */
937 	int i, space;
938 
939 	/*
940 	 * Since channel 0 is not available for DS, channel 1
941 	 * is assigned to LSB on WaveLAN.
942 	 */
943 	if (ic->ic_phytype == IEEE80211_T_DS)
944 		i = 1;
945 	else
946 		i = 0;
947 	memset(&chans, 0, sizeof(chans));
948 	for (; i <= IEEE80211_CHAN_MAX; i++)
949 		if (isset(ic->ic_chan_avail, i)) {
950 			struct ieee80211_channel *c = &ic->ic_channels[i];
951 			chans.ic_chans[chans.ic_nchans].ic_freq = c->ic_freq;
952 			chans.ic_chans[chans.ic_nchans].ic_flags = c->ic_flags;
953 			chans.ic_nchans++;
954 		}
955 	space = __offsetof(struct ieee80211req_chaninfo,
956 			ic_chans[chans.ic_nchans]);
957 	if (space > ireq->i_len)
958 		space = ireq->i_len;
959 	return copyout(&chans, ireq->i_data, space);
960 }
961 
962 static int
963 ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
964 {
965 	struct ieee80211_node *ni;
966 	struct ieee80211req_wpaie wpaie;
967 	int error;
968 
969 	if (ireq->i_len < IEEE80211_ADDR_LEN)
970 		return EINVAL;
971 	error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
972 	if (error != 0)
973 		return error;
974 	ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
975 	if (ni == NULL)
976 		return EINVAL;		/* XXX */
977 	memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
978 	if (ni->ni_wpa_ie != NULL) {
979 		int ielen = ni->ni_wpa_ie[1] + 2;
980 		if (ielen > sizeof(wpaie.wpa_ie))
981 			ielen = sizeof(wpaie.wpa_ie);
982 		memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
983 	}
984 	ieee80211_free_node(ni);
985 	if (ireq->i_len > sizeof(wpaie))
986 		ireq->i_len = sizeof(wpaie);
987 	return copyout(&wpaie, ireq->i_data, ireq->i_len);
988 }
989 
990 static int
991 ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
992 {
993 	struct ieee80211_node *ni;
994 	u_int8_t macaddr[IEEE80211_ADDR_LEN];
995 	const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
996 	int error;
997 
998 	if (ireq->i_len < off)
999 		return EINVAL;
1000 	error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1001 	if (error != 0)
1002 		return error;
1003 	ni = ieee80211_find_node(&ic->ic_sta, macaddr);
1004 	if (ni == NULL)
1005 		return EINVAL;		/* XXX */
1006 	if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
1007 		ireq->i_len = sizeof(struct ieee80211req_sta_stats);
1008 	/* NB: copy out only the statistics */
1009 	error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off,
1010 			ireq->i_len - off);
1011 	ieee80211_free_node(ni);
1012 	return error;
1013 }
1014 
1015 static void
1016 get_scan_result(struct ieee80211req_scan_result *sr,
1017 	const struct ieee80211_node *ni)
1018 {
1019 	struct ieee80211com *ic = ni->ni_ic;
1020 
1021 	memset(sr, 0, sizeof(*sr));
1022 	sr->isr_ssid_len = ni->ni_esslen;
1023 	if (ni->ni_wpa_ie != NULL)
1024 		sr->isr_ie_len += 2+ni->ni_wpa_ie[1];
1025 	if (ni->ni_wme_ie != NULL)
1026 		sr->isr_ie_len += 2+ni->ni_wme_ie[1];
1027 	sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len;
1028 	sr->isr_len = roundup(sr->isr_len, sizeof(u_int32_t));
1029 	if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
1030 		sr->isr_freq = ni->ni_chan->ic_freq;
1031 		sr->isr_flags = ni->ni_chan->ic_flags;
1032 	}
1033 	sr->isr_rssi = ic->ic_node_getrssi(ni);
1034 	sr->isr_intval = ni->ni_intval;
1035 	sr->isr_capinfo = ni->ni_capinfo;
1036 	sr->isr_erp = ni->ni_erp;
1037 	IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid);
1038 	sr->isr_nrates = ni->ni_rates.rs_nrates;
1039 	if (sr->isr_nrates > 15)
1040 		sr->isr_nrates = 15;
1041 	memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates);
1042 }
1043 
1044 static int
1045 ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
1046 {
1047 	union {
1048 		struct ieee80211req_scan_result res;
1049 		char data[512];		/* XXX shrink? */
1050 	} u;
1051 	struct ieee80211req_scan_result *sr = &u.res;
1052 	struct ieee80211_node_table *nt;
1053 	struct ieee80211_node *ni;
1054 	int error, space;
1055 	u_int8_t *p, *cp;
1056 
1057 	p = ireq->i_data;
1058 	space = ireq->i_len;
1059 	error = 0;
1060 	/* XXX locking */
1061 	nt =  &ic->ic_scan;
1062 	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1063 		/* NB: skip pre-scan node state */
1064 		if (ni->ni_chan == IEEE80211_CHAN_ANYC)
1065 			continue;
1066 		get_scan_result(sr, ni);
1067 		if (sr->isr_len > sizeof(u))
1068 			continue;		/* XXX */
1069 		if (space < sr->isr_len)
1070 			break;
1071 		cp = (u_int8_t *)(sr+1);
1072 		memcpy(cp, ni->ni_essid, ni->ni_esslen);
1073 		cp += ni->ni_esslen;
1074 		if (ni->ni_wpa_ie != NULL) {
1075 			memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
1076 			cp += 2+ni->ni_wpa_ie[1];
1077 		}
1078 		if (ni->ni_wme_ie != NULL) {
1079 			memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
1080 			cp += 2+ni->ni_wme_ie[1];
1081 		}
1082 		error = copyout(sr, p, sr->isr_len);
1083 		if (error)
1084 			break;
1085 		p += sr->isr_len;
1086 		space -= sr->isr_len;
1087 	}
1088 	ireq->i_len -= space;
1089 	return error;
1090 }
1091 
1092 static void
1093 get_sta_info(struct ieee80211req_sta_info *si, const struct ieee80211_node *ni)
1094 {
1095 	struct ieee80211com *ic = ni->ni_ic;
1096 
1097 	si->isi_ie_len = 0;
1098 	if (ni->ni_wpa_ie != NULL)
1099 		si->isi_ie_len += 2+ni->ni_wpa_ie[1];
1100 	if (ni->ni_wme_ie != NULL)
1101 		si->isi_ie_len += 2+ni->ni_wme_ie[1];
1102 	si->isi_len = sizeof(*si) + si->isi_ie_len, sizeof(u_int32_t);
1103 	si->isi_len = roundup(si->isi_len, sizeof(u_int32_t));
1104 	si->isi_freq = ni->ni_chan->ic_freq;
1105 	si->isi_flags = ni->ni_chan->ic_flags;
1106 	si->isi_state = ni->ni_flags;
1107 	si->isi_authmode = ni->ni_authmode;
1108 	si->isi_rssi = ic->ic_node_getrssi(ni);
1109 	si->isi_capinfo = ni->ni_capinfo;
1110 	si->isi_erp = ni->ni_erp;
1111 	IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
1112 	si->isi_nrates = ni->ni_rates.rs_nrates;
1113 	if (si->isi_nrates > 15)
1114 		si->isi_nrates = 15;
1115 	memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
1116 	si->isi_txrate = ni->ni_txrate;
1117 	si->isi_associd = ni->ni_associd;
1118 	si->isi_txpower = ni->ni_txpower;
1119 	si->isi_vlan = ni->ni_vlan;
1120 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
1121 		memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
1122 		memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
1123 	} else {
1124 		si->isi_txseqs[0] = ni->ni_txseqs[0];
1125 		si->isi_rxseqs[0] = ni->ni_rxseqs[0];
1126 	}
1127 	if (ic->ic_opmode == IEEE80211_M_IBSS || ni->ni_associd != 0)
1128 		si->isi_inact = ic->ic_inact_run;
1129 	else if (ieee80211_node_is_authorized(ni))
1130 		si->isi_inact = ic->ic_inact_auth;
1131 	else
1132 		si->isi_inact = ic->ic_inact_init;
1133 	si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
1134 }
1135 
1136 static int
1137 ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
1138 {
1139 	union {
1140 		struct ieee80211req_sta_info info;
1141 		char data[512];		/* XXX shrink? */
1142 	} u;
1143 	struct ieee80211req_sta_info *si = &u.info;
1144 	struct ieee80211_node_table *nt;
1145 	struct ieee80211_node *ni;
1146 	int error, space;
1147 	u_int8_t *p, *cp;
1148 
1149 	nt = &ic->ic_sta;
1150 	p = ireq->i_data;
1151 	space = ireq->i_len;
1152 	error = 0;
1153 	/* XXX locking */
1154 	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1155 		get_sta_info(si, ni);
1156 		if (si->isi_len > sizeof(u))
1157 			continue;		/* XXX */
1158 		if (space < si->isi_len)
1159 			break;
1160 		cp = (u_int8_t *)(si+1);
1161 		if (ni->ni_wpa_ie != NULL) {
1162 			memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
1163 			cp += 2+ni->ni_wpa_ie[1];
1164 		}
1165 		if (ni->ni_wme_ie != NULL) {
1166 			memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
1167 			cp += 2+ni->ni_wme_ie[1];
1168 		}
1169 		error = copyout(si, p, si->isi_len);
1170 		if (error)
1171 			break;
1172 		p += si->isi_len;
1173 		space -= si->isi_len;
1174 	}
1175 	ireq->i_len -= space;
1176 	return error;
1177 }
1178 
1179 static int
1180 ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1181 {
1182 	struct ieee80211_node *ni;
1183 	struct ieee80211req_sta_txpow txpow;
1184 	int error;
1185 
1186 	if (ireq->i_len != sizeof(txpow))
1187 		return EINVAL;
1188 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1189 	if (error != 0)
1190 		return error;
1191 	ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1192 	if (ni == NULL)
1193 		return EINVAL;		/* XXX */
1194 	txpow.it_txpow = ni->ni_txpower;
1195 	error = copyout(&txpow, ireq->i_data, sizeof(txpow));
1196 	ieee80211_free_node(ni);
1197 	return error;
1198 }
1199 
1200 static int
1201 ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1202 {
1203 	struct ieee80211_wme_state *wme = &ic->ic_wme;
1204 	struct wmeParams *wmep;
1205 	int ac;
1206 
1207 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1208 		return EINVAL;
1209 
1210 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1211 	if (ac >= WME_NUM_AC)
1212 		ac = WME_AC_BE;
1213 	if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
1214 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1215 	else
1216 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1217 	switch (ireq->i_type) {
1218 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1219 		ireq->i_val = wmep->wmep_logcwmin;
1220 		break;
1221 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
1222 		ireq->i_val = wmep->wmep_logcwmax;
1223 		break;
1224 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1225 		ireq->i_val = wmep->wmep_aifsn;
1226 		break;
1227 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1228 		ireq->i_val = wmep->wmep_txopLimit;
1229 		break;
1230 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1231 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1232 		ireq->i_val = wmep->wmep_acm;
1233 		break;
1234 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
1235 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1236 		ireq->i_val = !wmep->wmep_noackPolicy;
1237 		break;
1238 	}
1239 	return 0;
1240 }
1241 
1242 /*
1243  * When building the kernel with -O2 on the i386 architecture, gcc
1244  * seems to want to inline this function into ieee80211_ioctl()
1245  * (which is the only routine that calls it). When this happens,
1246  * ieee80211_ioctl() ends up consuming an additional 2K of stack
1247  * space. (Exactly why it needs so much is unclear.) The problem
1248  * is that it's possible for ieee80211_ioctl() to invoke other
1249  * routines (including driver init functions) which could then find
1250  * themselves perilously close to exhausting the stack.
1251  *
1252  * To avoid this, we deliberately prevent gcc from inlining this
1253  * routine. Another way to avoid this is to use less agressive
1254  * optimization when compiling this file (i.e. -O instead of -O2)
1255  * but special-casing the compilation of this one module in the
1256  * build system would be awkward.
1257  */
1258 #ifdef __GNUC__
1259 __attribute__ ((noinline))
1260 #endif
1261 static int
1262 ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1263 {
1264 	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1265 	int error = 0;
1266 	u_int kid, len, m;
1267 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1268 	char tmpssid[IEEE80211_NWID_LEN];
1269 
1270 	switch (ireq->i_type) {
1271 	case IEEE80211_IOC_SSID:
1272 		switch (ic->ic_state) {
1273 		case IEEE80211_S_INIT:
1274 		case IEEE80211_S_SCAN:
1275 			ireq->i_len = ic->ic_des_esslen;
1276 			memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
1277 			break;
1278 		default:
1279 			ireq->i_len = ic->ic_bss->ni_esslen;
1280 			memcpy(tmpssid, ic->ic_bss->ni_essid,
1281 				ireq->i_len);
1282 			break;
1283 		}
1284 		error = copyout(tmpssid, ireq->i_data, ireq->i_len);
1285 		break;
1286 	case IEEE80211_IOC_NUMSSIDS:
1287 		ireq->i_val = 1;
1288 		break;
1289 	case IEEE80211_IOC_WEP:
1290 		if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
1291 			ireq->i_val = IEEE80211_WEP_OFF;
1292 		else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
1293 			ireq->i_val = IEEE80211_WEP_ON;
1294 		else
1295 			ireq->i_val = IEEE80211_WEP_MIXED;
1296 		break;
1297 	case IEEE80211_IOC_WEPKEY:
1298 		kid = (u_int) ireq->i_val;
1299 		if (kid >= IEEE80211_WEP_NKID)
1300 			return EINVAL;
1301 		len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
1302 		/* NB: only root can read WEP keys */
1303 		if (suser(curproc->p_ucred, &curproc->p_acflag) == 0) {
1304 			bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
1305 		} else {
1306 			bzero(tmpkey, len);
1307 		}
1308 		ireq->i_len = len;
1309 		error = copyout(tmpkey, ireq->i_data, len);
1310 		break;
1311 	case IEEE80211_IOC_NUMWEPKEYS:
1312 		ireq->i_val = IEEE80211_WEP_NKID;
1313 		break;
1314 	case IEEE80211_IOC_WEPTXKEY:
1315 		ireq->i_val = ic->ic_def_txkey;
1316 		break;
1317 	case IEEE80211_IOC_AUTHMODE:
1318 		if (ic->ic_flags & IEEE80211_F_WPA)
1319 			ireq->i_val = IEEE80211_AUTH_WPA;
1320 		else
1321 			ireq->i_val = ic->ic_bss->ni_authmode;
1322 		break;
1323 	case IEEE80211_IOC_CHANNEL:
1324 		ireq->i_val = ieee80211_chan2ieee(ic, getcurchan(ic));
1325 		break;
1326 	case IEEE80211_IOC_POWERSAVE:
1327 		if (ic->ic_flags & IEEE80211_F_PMGTON)
1328 			ireq->i_val = IEEE80211_POWERSAVE_ON;
1329 		else
1330 			ireq->i_val = IEEE80211_POWERSAVE_OFF;
1331 		break;
1332 	case IEEE80211_IOC_POWERSAVESLEEP:
1333 		ireq->i_val = ic->ic_lintval;
1334 		break;
1335 	case IEEE80211_IOC_RTSTHRESHOLD:
1336 		ireq->i_val = ic->ic_rtsthreshold;
1337 		break;
1338 	case IEEE80211_IOC_PROTMODE:
1339 		ireq->i_val = ic->ic_protmode;
1340 		break;
1341 	case IEEE80211_IOC_TXPOWER:
1342 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
1343 			return EINVAL;
1344 		ireq->i_val = ic->ic_txpowlimit;
1345 		break;
1346 	case IEEE80211_IOC_MCASTCIPHER:
1347 		ireq->i_val = rsn->rsn_mcastcipher;
1348 		break;
1349 	case IEEE80211_IOC_MCASTKEYLEN:
1350 		ireq->i_val = rsn->rsn_mcastkeylen;
1351 		break;
1352 	case IEEE80211_IOC_UCASTCIPHERS:
1353 		ireq->i_val = 0;
1354 		for (m = 0x1; m != 0; m <<= 1)
1355 			if (rsn->rsn_ucastcipherset & m)
1356 				ireq->i_val |= 1<<cap2cipher(m);
1357 		break;
1358 	case IEEE80211_IOC_UCASTCIPHER:
1359 		ireq->i_val = rsn->rsn_ucastcipher;
1360 		break;
1361 	case IEEE80211_IOC_UCASTKEYLEN:
1362 		ireq->i_val = rsn->rsn_ucastkeylen;
1363 		break;
1364 	case IEEE80211_IOC_KEYMGTALGS:
1365 		ireq->i_val = rsn->rsn_keymgmtset;
1366 		break;
1367 	case IEEE80211_IOC_RSNCAPS:
1368 		ireq->i_val = rsn->rsn_caps;
1369 		break;
1370 	case IEEE80211_IOC_WPA:
1371 		switch (ic->ic_flags & IEEE80211_F_WPA) {
1372 		case IEEE80211_F_WPA1:
1373 			ireq->i_val = 1;
1374 			break;
1375 		case IEEE80211_F_WPA2:
1376 			ireq->i_val = 2;
1377 			break;
1378 		case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
1379 			ireq->i_val = 3;
1380 			break;
1381 		default:
1382 			ireq->i_val = 0;
1383 			break;
1384 		}
1385 		break;
1386 	case IEEE80211_IOC_CHANLIST:
1387 		error = ieee80211_ioctl_getchanlist(ic, ireq);
1388 		break;
1389 	case IEEE80211_IOC_ROAMING:
1390 		ireq->i_val = ic->ic_roaming;
1391 		break;
1392 	case IEEE80211_IOC_PRIVACY:
1393 		ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
1394 		break;
1395 	case IEEE80211_IOC_DROPUNENCRYPTED:
1396 		ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
1397 		break;
1398 	case IEEE80211_IOC_COUNTERMEASURES:
1399 		ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
1400 		break;
1401 	case IEEE80211_IOC_DRIVER_CAPS:
1402 		ireq->i_val = ic->ic_caps>>16;
1403 		ireq->i_len = ic->ic_caps&0xffff;
1404 		break;
1405 	case IEEE80211_IOC_WME:
1406 		ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
1407 		break;
1408 	case IEEE80211_IOC_HIDESSID:
1409 		ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
1410 		break;
1411 	case IEEE80211_IOC_APBRIDGE:
1412 		ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
1413 		break;
1414 	case IEEE80211_IOC_OPTIE:
1415 		if (ic->ic_opt_ie == NULL)
1416 			return EINVAL;
1417 		/* NB: truncate, caller can check length */
1418 		if (ireq->i_len > ic->ic_opt_ie_len)
1419 			ireq->i_len = ic->ic_opt_ie_len;
1420 		error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
1421 		break;
1422 	case IEEE80211_IOC_WPAKEY:
1423 		error = ieee80211_ioctl_getkey(ic, ireq);
1424 		break;
1425 	case IEEE80211_IOC_CHANINFO:
1426 		error = ieee80211_ioctl_getchaninfo(ic, ireq);
1427 		break;
1428 	case IEEE80211_IOC_BSSID:
1429 		if (ireq->i_len != IEEE80211_ADDR_LEN)
1430 			return EINVAL;
1431 		error = copyout(ic->ic_state == IEEE80211_S_RUN ?
1432 					ic->ic_bss->ni_bssid :
1433 					ic->ic_des_bssid,
1434 				ireq->i_data, ireq->i_len);
1435 		break;
1436 	case IEEE80211_IOC_WPAIE:
1437 		error = ieee80211_ioctl_getwpaie(ic, ireq);
1438 		break;
1439 	case IEEE80211_IOC_SCAN_RESULTS:
1440 		error = ieee80211_ioctl_getscanresults(ic, ireq);
1441 		break;
1442 	case IEEE80211_IOC_STA_STATS:
1443 		error = ieee80211_ioctl_getstastats(ic, ireq);
1444 		break;
1445 	case IEEE80211_IOC_TXPOWMAX:
1446 		ireq->i_val = ic->ic_bss->ni_txpower;
1447 		break;
1448 	case IEEE80211_IOC_STA_TXPOW:
1449 		error = ieee80211_ioctl_getstatxpow(ic, ireq);
1450 		break;
1451 	case IEEE80211_IOC_STA_INFO:
1452 		error = ieee80211_ioctl_getstainfo(ic, ireq);
1453 		break;
1454 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1455 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
1456 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1457 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1458 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1459 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
1460 		error = ieee80211_ioctl_getwmeparam(ic, ireq);
1461 		break;
1462 	case IEEE80211_IOC_DTIM_PERIOD:
1463 		ireq->i_val = ic->ic_dtim_period;
1464 		break;
1465 	case IEEE80211_IOC_BEACON_INTERVAL:
1466 		/* NB: get from ic_bss for station mode */
1467 		ireq->i_val = ic->ic_bss->ni_intval;
1468 		break;
1469 	default:
1470 		error = EINVAL;
1471 		break;
1472 	}
1473 	return error;
1474 }
1475 
1476 static int
1477 ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
1478 {
1479 	int error;
1480 	void *ie;
1481 
1482 	/*
1483 	 * NB: Doing this for ap operation could be useful (e.g. for
1484 	 *     WPA and/or WME) except that it typically is worthless
1485 	 *     without being able to intervene when processing
1486 	 *     association response frames--so disallow it for now.
1487 	 */
1488 	if (ic->ic_opmode != IEEE80211_M_STA)
1489 		return EINVAL;
1490 	if (ireq->i_len > IEEE80211_MAX_OPT_IE)
1491 		return EINVAL;
1492 	/* NB: data.length is validated by the wireless extensions code */
1493 	MALLOC(ie, void *, (u_long)ireq->i_len, M_DEVBUF, M_WAITOK);
1494 	if (ie == NULL)
1495 		return ENOMEM;
1496 	error = copyin(ireq->i_data, ie, ireq->i_len);
1497 	/* XXX sanity check data? */
1498 	if (ic->ic_opt_ie != NULL)
1499 		FREE(ic->ic_opt_ie, M_DEVBUF);
1500 	ic->ic_opt_ie = ie;
1501 	ic->ic_opt_ie_len = ireq->i_len;
1502 	return 0;
1503 }
1504 
1505 static int
1506 ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1507 {
1508 	struct ieee80211req_key ik;
1509 	struct ieee80211_node *ni;
1510 	struct ieee80211_key *wk;
1511 	u_int16_t kid;
1512 	int error;
1513 
1514 	if (ireq->i_len != sizeof(ik))
1515 		return EINVAL;
1516 	error = copyin(ireq->i_data, &ik, sizeof(ik));
1517 	if (error)
1518 		return error;
1519 	/* NB: cipher support is verified by ieee80211_crypt_newkey */
1520 	/* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
1521 	if (ik.ik_keylen > sizeof(ik.ik_keydata))
1522 		return E2BIG;
1523 	kid = ik.ik_keyix;
1524 	if (kid == IEEE80211_KEYIX_NONE) {
1525 		/* XXX unicast keys currently must be tx/rx */
1526 		if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
1527 			return EINVAL;
1528 		if (ic->ic_opmode == IEEE80211_M_STA) {
1529 			ni = ic->ic_bss;
1530 			if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid))
1531 				return EADDRNOTAVAIL;
1532 		} else {
1533 			ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
1534 			if (ni == NULL)
1535 				return ENOENT;
1536 		}
1537 		wk = &ni->ni_ucastkey;
1538 	} else {
1539 		if (kid >= IEEE80211_WEP_NKID)
1540 			return EINVAL;
1541 		wk = &ic->ic_nw_keys[kid];
1542 		ni = NULL;
1543 		/* XXX auto-add group key flag until applications are updated */
1544 		if ((ik.ik_flags & IEEE80211_KEY_XMIT) == 0)	/* XXX */
1545 			ik.ik_flags |= IEEE80211_KEY_GROUP;	/* XXX */
1546 	}
1547 	error = 0;
1548 	ieee80211_key_update_begin(ic);
1549 	if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
1550 		wk->wk_keylen = ik.ik_keylen;
1551 		/* NB: MIC presence is implied by cipher type */
1552 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
1553 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
1554 		wk->wk_keyrsc = ik.ik_keyrsc;
1555 		wk->wk_keytsc = 0;			/* new key, reset */
1556 		memset(wk->wk_key, 0, sizeof(wk->wk_key));
1557 		memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
1558 		if (!ieee80211_crypto_setkey(ic, wk,
1559 		    ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
1560 			error = EIO;
1561 		else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
1562 			ic->ic_def_txkey = kid;
1563 	} else
1564 		error = ENXIO;
1565 	ieee80211_key_update_end(ic);
1566 	if (ni != NULL)
1567 		ieee80211_free_node(ni);
1568 	return error;
1569 }
1570 
1571 static int
1572 ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1573 {
1574 	struct ieee80211req_del_key dk;
1575 	int kid, error;
1576 
1577 	if (ireq->i_len != sizeof(dk))
1578 		return EINVAL;
1579 	error = copyin(ireq->i_data, &dk, sizeof(dk));
1580 	if (error)
1581 		return error;
1582 	kid = dk.idk_keyix;
1583 	/* XXX u_int8_t -> u_int16_t */
1584 	if (dk.idk_keyix == (u_int8_t) IEEE80211_KEYIX_NONE) {
1585 		struct ieee80211_node *ni;
1586 
1587 		ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
1588 		if (ni == NULL)
1589 			return EINVAL;		/* XXX */
1590 		/* XXX error return */
1591 		ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
1592 		ieee80211_free_node(ni);
1593 	} else {
1594 		if (kid >= IEEE80211_WEP_NKID)
1595 			return EINVAL;
1596 		/* XXX error return */
1597 		ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
1598 	}
1599 	return 0;
1600 }
1601 
1602 #ifndef IEEE80211_NO_HOSTAP
1603 static void
1604 domlme(void *arg, struct ieee80211_node *ni)
1605 {
1606 	struct ieee80211com *ic = ni->ni_ic;
1607 	struct ieee80211req_mlme *mlme = arg;
1608 
1609 	if (ni->ni_associd != 0) {
1610 		IEEE80211_SEND_MGMT(ic, ni,
1611 			mlme->im_op == IEEE80211_MLME_DEAUTH ?
1612 				IEEE80211_FC0_SUBTYPE_DEAUTH :
1613 				IEEE80211_FC0_SUBTYPE_DISASSOC,
1614 			mlme->im_reason);
1615 	}
1616 	ieee80211_node_leave(ic, ni);
1617 }
1618 #endif /* !IEEE80211_NO_HOSTAP */
1619 
1620 static int
1621 ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
1622 {
1623 	struct ieee80211req_mlme mlme;
1624 	struct ieee80211_node *ni;
1625 	int error;
1626 
1627 	if (ireq->i_len != sizeof(mlme))
1628 		return EINVAL;
1629 	error = copyin(ireq->i_data, &mlme, sizeof(mlme));
1630 	if (error)
1631 		return error;
1632 	switch (mlme.im_op) {
1633 	case IEEE80211_MLME_ASSOC:
1634 		if (ic->ic_opmode != IEEE80211_M_STA)
1635 			return EINVAL;
1636 		/* XXX must be in S_SCAN state? */
1637 
1638 		if (ic->ic_des_esslen != 0) {
1639 			/*
1640 			 * Desired ssid specified; must match both bssid and
1641 			 * ssid to distinguish ap advertising multiple ssid's.
1642 			 */
1643 			ni = ieee80211_find_node_with_ssid(&ic->ic_scan,
1644 				mlme.im_macaddr,
1645 				ic->ic_des_esslen, ic->ic_des_essid);
1646 		} else {
1647 			/*
1648 			 * Normal case; just match bssid.
1649 			 */
1650 			ni = ieee80211_find_node(&ic->ic_scan, mlme.im_macaddr);
1651 		}
1652 		if (ni == NULL)
1653 			return EINVAL;
1654 		if (!ieee80211_sta_join(ic, ni)) {
1655 			ieee80211_free_node(ni);
1656 			return EINVAL;
1657 		}
1658 		break;
1659 	case IEEE80211_MLME_DISASSOC:
1660 	case IEEE80211_MLME_DEAUTH:
1661 		switch (ic->ic_opmode) {
1662 		case IEEE80211_M_STA:
1663 			/* XXX not quite right */
1664 			ieee80211_new_state(ic, IEEE80211_S_INIT,
1665 				mlme.im_reason);
1666 			break;
1667 		case IEEE80211_M_HOSTAP:
1668 #ifndef IEEE80211_NO_HOSTAP
1669 			/* NB: the broadcast address means do 'em all */
1670 			if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
1671 				if ((ni = ieee80211_find_node(&ic->ic_sta,
1672 						mlme.im_macaddr)) == NULL)
1673 					return EINVAL;
1674 				domlme(&mlme, ni);
1675 				ieee80211_free_node(ni);
1676 			} else {
1677 				ieee80211_iterate_nodes(&ic->ic_sta,
1678 						domlme, &mlme);
1679 			}
1680 #endif /* !IEEE80211_NO_HOSTAP */
1681 			break;
1682 		default:
1683 			return EINVAL;
1684 		}
1685 		break;
1686 	case IEEE80211_MLME_AUTHORIZE:
1687 	case IEEE80211_MLME_UNAUTHORIZE:
1688 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1689 			return EINVAL;
1690 		ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
1691 		if (ni == NULL)
1692 			return EINVAL;
1693 		if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
1694 			ieee80211_node_authorize(ic, ni);
1695 		else
1696 			ieee80211_node_unauthorize(ic, ni);
1697 		ieee80211_free_node(ni);
1698 		break;
1699 	default:
1700 		return EINVAL;
1701 	}
1702 	return 0;
1703 }
1704 
1705 static int
1706 ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
1707 {
1708 	u_int8_t mac[IEEE80211_ADDR_LEN];
1709 	const struct ieee80211_aclator *acl = ic->ic_acl;
1710 	int error;
1711 
1712 	if (ireq->i_len != sizeof(mac))
1713 		return EINVAL;
1714 	error = copyin(ireq->i_data, mac, ireq->i_len);
1715 	if (error)
1716 		return error;
1717 	if (acl == NULL) {
1718 		acl = ieee80211_aclator_get("mac");
1719 		if (acl == NULL || !acl->iac_attach(ic))
1720 			return EINVAL;
1721 		ic->ic_acl = acl;
1722 	}
1723 	if (ireq->i_type == IEEE80211_IOC_ADDMAC)
1724 		acl->iac_add(ic, mac);
1725 	else
1726 		acl->iac_remove(ic, mac);
1727 	return 0;
1728 }
1729 
1730 static int
1731 ieee80211_ioctl_maccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1732 {
1733 	const struct ieee80211_aclator *acl = ic->ic_acl;
1734 
1735 	switch (ireq->i_val) {
1736 	case IEEE80211_MACCMD_POLICY_OPEN:
1737 	case IEEE80211_MACCMD_POLICY_ALLOW:
1738 	case IEEE80211_MACCMD_POLICY_DENY:
1739 		if (acl == NULL) {
1740 			acl = ieee80211_aclator_get("mac");
1741 			if (acl == NULL || !acl->iac_attach(ic))
1742 				return EINVAL;
1743 			ic->ic_acl = acl;
1744 		}
1745 		acl->iac_setpolicy(ic, ireq->i_val);
1746 		break;
1747 	case IEEE80211_MACCMD_FLUSH:
1748 		if (acl != NULL)
1749 			acl->iac_flush(ic);
1750 		/* NB: silently ignore when not in use */
1751 		break;
1752 	case IEEE80211_MACCMD_DETACH:
1753 		if (acl != NULL) {
1754 			ic->ic_acl = NULL;
1755 			acl->iac_detach(ic);
1756 		}
1757 		break;
1758 	default:
1759 		return EINVAL;
1760 	}
1761 	return 0;
1762 }
1763 
1764 static int
1765 ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
1766 {
1767 	struct ieee80211req_chanlist list;
1768 	u_char chanlist[IEEE80211_CHAN_BYTES];
1769 	int i, j, error;
1770 
1771 	if (ireq->i_len != sizeof(list))
1772 		return EINVAL;
1773 	error = copyin(ireq->i_data, &list, sizeof(list));
1774 	if (error)
1775 		return error;
1776 	memset(chanlist, 0, sizeof(chanlist));
1777 	/*
1778 	 * Since channel 0 is not available for DS, channel 1
1779 	 * is assigned to LSB on WaveLAN.
1780 	 */
1781 	if (ic->ic_phytype == IEEE80211_T_DS)
1782 		i = 1;
1783 	else
1784 		i = 0;
1785 	for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
1786 		/*
1787 		 * NB: silently discard unavailable channels so users
1788 		 *     can specify 1-255 to get all available channels.
1789 		 */
1790 		if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i))
1791 			setbit(chanlist, i);
1792 	}
1793 	if (ic->ic_ibss_chan == NULL ||
1794 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
1795 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
1796 			if (isset(chanlist, i)) {
1797 				ic->ic_ibss_chan = &ic->ic_channels[i];
1798 				goto found;
1799 			}
1800 		return EINVAL;			/* no active channels */
1801 found:
1802 		;
1803 	}
1804 	memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
1805 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
1806 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
1807 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
1808 	return IS_UP_AUTO(ic) ? ENETRESET : 0;
1809 }
1810 
1811 static int
1812 ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1813 {
1814 	struct ieee80211_node *ni;
1815 	struct ieee80211req_sta_txpow txpow;
1816 	int error;
1817 
1818 	if (ireq->i_len != sizeof(txpow))
1819 		return EINVAL;
1820 	error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1821 	if (error != 0)
1822 		return error;
1823 	ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1824 	if (ni == NULL)
1825 		return EINVAL;		/* XXX */
1826 	ni->ni_txpower = txpow.it_txpow;
1827 	ieee80211_free_node(ni);
1828 	return error;
1829 }
1830 
1831 static int
1832 ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1833 {
1834 	struct ieee80211_wme_state *wme = &ic->ic_wme;
1835 	struct wmeParams *wmep, *chanp;
1836 	int isbss, ac;
1837 
1838 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1839 		return EINVAL;
1840 
1841 	isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
1842 	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1843 	if (ac >= WME_NUM_AC)
1844 		ac = WME_AC_BE;
1845 	if (isbss) {
1846 		chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
1847 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1848 	} else {
1849 		chanp = &wme->wme_chanParams.cap_wmeParams[ac];
1850 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1851 	}
1852 	switch (ireq->i_type) {
1853 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
1854 		if (isbss) {
1855 			wmep->wmep_logcwmin = ireq->i_val;
1856 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1857 				chanp->wmep_logcwmin = ireq->i_val;
1858 		} else {
1859 			wmep->wmep_logcwmin = chanp->wmep_logcwmin =
1860 				ireq->i_val;
1861 		}
1862 		break;
1863 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
1864 		if (isbss) {
1865 			wmep->wmep_logcwmax = ireq->i_val;
1866 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1867 				chanp->wmep_logcwmax = ireq->i_val;
1868 		} else {
1869 			wmep->wmep_logcwmax = chanp->wmep_logcwmax =
1870 				ireq->i_val;
1871 		}
1872 		break;
1873 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
1874 		if (isbss) {
1875 			wmep->wmep_aifsn = ireq->i_val;
1876 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1877 				chanp->wmep_aifsn = ireq->i_val;
1878 		} else {
1879 			wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
1880 		}
1881 		break;
1882 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
1883 		if (isbss) {
1884 			wmep->wmep_txopLimit = ireq->i_val;
1885 			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1886 				chanp->wmep_txopLimit = ireq->i_val;
1887 		} else {
1888 			wmep->wmep_txopLimit = chanp->wmep_txopLimit =
1889 				ireq->i_val;
1890 		}
1891 		break;
1892 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
1893 		wmep->wmep_acm = ireq->i_val;
1894 		if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1895 			chanp->wmep_acm = ireq->i_val;
1896 		break;
1897 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
1898 		wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
1899 			(ireq->i_val) == 0;
1900 		break;
1901 	}
1902 	ieee80211_wme_updateparams(ic);
1903 	return 0;
1904 }
1905 
1906 static int
1907 cipher2cap(int cipher)
1908 {
1909 	switch (cipher) {
1910 	case IEEE80211_CIPHER_WEP:	return IEEE80211_C_WEP;
1911 	case IEEE80211_CIPHER_AES_OCB:	return IEEE80211_C_AES;
1912 	case IEEE80211_CIPHER_AES_CCM:	return IEEE80211_C_AES_CCM;
1913 	case IEEE80211_CIPHER_CKIP:	return IEEE80211_C_CKIP;
1914 	case IEEE80211_CIPHER_TKIP:	return IEEE80211_C_TKIP;
1915 	}
1916 	return 0;
1917 }
1918 
1919 static int
1920 ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1921 {
1922 	static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
1923 	struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1924 	int error;
1925 	const struct ieee80211_authenticator *auth;
1926 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1927 	char tmpssid[IEEE80211_NWID_LEN];
1928 	u_int8_t tmpbssid[IEEE80211_ADDR_LEN];
1929 	struct ieee80211_key *k;
1930 	int j, caps;
1931 	u_int kid;
1932 
1933 	error = 0;
1934 	switch (ireq->i_type) {
1935 	case IEEE80211_IOC_SSID:
1936 		if (ireq->i_val != 0 ||
1937 		    ireq->i_len > IEEE80211_NWID_LEN)
1938 			return EINVAL;
1939 		error = copyin(ireq->i_data, tmpssid, ireq->i_len);
1940 		if (error)
1941 			break;
1942 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
1943 		ic->ic_des_esslen = ireq->i_len;
1944 		memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
1945 		error = ENETRESET;
1946 		break;
1947 	case IEEE80211_IOC_WEP:
1948 		switch (ireq->i_val) {
1949 		case IEEE80211_WEP_OFF:
1950 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1951 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1952 			break;
1953 		case IEEE80211_WEP_ON:
1954 			ic->ic_flags |= IEEE80211_F_PRIVACY;
1955 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
1956 			break;
1957 		case IEEE80211_WEP_MIXED:
1958 			ic->ic_flags |= IEEE80211_F_PRIVACY;
1959 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1960 			break;
1961 		}
1962 		error = ENETRESET;
1963 		break;
1964 	case IEEE80211_IOC_WEPKEY:
1965 		kid = (u_int) ireq->i_val;
1966 		if (kid >= IEEE80211_WEP_NKID)
1967 			return EINVAL;
1968 		k = &ic->ic_nw_keys[kid];
1969 		if (ireq->i_len == 0) {
1970 			/* zero-len =>'s delete any existing key */
1971 			(void) ieee80211_crypto_delkey(ic, k);
1972 			break;
1973 		}
1974 		if (ireq->i_len > sizeof(tmpkey))
1975 			return EINVAL;
1976 		memset(tmpkey, 0, sizeof(tmpkey));
1977 		error = copyin(ireq->i_data, tmpkey, ireq->i_len);
1978 		if (error)
1979 			break;
1980 		ieee80211_key_update_begin(ic);
1981 		k->wk_keyix = kid;	/* NB: force fixed key id */
1982 		if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
1983 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
1984 			k->wk_keylen = ireq->i_len;
1985 			memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
1986 			if  (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
1987 				error = EINVAL;
1988 		} else
1989 			error = EINVAL;
1990 		ieee80211_key_update_end(ic);
1991 		break;
1992 	case IEEE80211_IOC_WEPTXKEY:
1993 		kid = (u_int) ireq->i_val;
1994 		if (kid >= IEEE80211_WEP_NKID &&
1995 		    (u_int16_t) kid != IEEE80211_KEYIX_NONE)
1996 			return EINVAL;
1997 		ic->ic_def_txkey = kid;
1998 		error = ENETRESET;	/* push to hardware */
1999 		break;
2000 	case IEEE80211_IOC_AUTHMODE:
2001 		switch (ireq->i_val) {
2002 		case IEEE80211_AUTH_WPA:
2003 		case IEEE80211_AUTH_8021X:	/* 802.1x */
2004 		case IEEE80211_AUTH_OPEN:	/* open */
2005 		case IEEE80211_AUTH_SHARED:	/* shared-key */
2006 		case IEEE80211_AUTH_AUTO:	/* auto */
2007 			auth = ieee80211_authenticator_get(ireq->i_val);
2008 			if (auth == NULL)
2009 				return EINVAL;
2010 			break;
2011 		default:
2012 			return EINVAL;
2013 		}
2014 		switch (ireq->i_val) {
2015 		case IEEE80211_AUTH_WPA:	/* WPA w/ 802.1x */
2016 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2017 			ireq->i_val = IEEE80211_AUTH_8021X;
2018 			break;
2019 		case IEEE80211_AUTH_OPEN:	/* open */
2020 			ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
2021 			break;
2022 		case IEEE80211_AUTH_SHARED:	/* shared-key */
2023 		case IEEE80211_AUTH_8021X:	/* 802.1x */
2024 			ic->ic_flags &= ~IEEE80211_F_WPA;
2025 			/* both require a key so mark the PRIVACY capability */
2026 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2027 			break;
2028 		case IEEE80211_AUTH_AUTO:	/* auto */
2029 			ic->ic_flags &= ~IEEE80211_F_WPA;
2030 			/* XXX PRIVACY handling? */
2031 			/* XXX what's the right way to do this? */
2032 			break;
2033 		}
2034 		/* NB: authenticator attach/detach happens on state change */
2035 		ic->ic_bss->ni_authmode = ireq->i_val;
2036 		/* XXX mixed/mode/usage? */
2037 		ic->ic_auth = auth;
2038 		error = ENETRESET;
2039 		break;
2040 	case IEEE80211_IOC_CHANNEL:
2041 		/* XXX 0xffff overflows 16-bit signed */
2042 		if (ireq->i_val == 0 ||
2043 		    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
2044 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
2045 		else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
2046 		    isclr(ic->ic_chan_active, ireq->i_val)) {
2047 			return EINVAL;
2048 		} else
2049 			ic->ic_ibss_chan = ic->ic_des_chan =
2050 				&ic->ic_channels[ireq->i_val];
2051 		switch (ic->ic_state) {
2052 		case IEEE80211_S_INIT:
2053 		case IEEE80211_S_SCAN:
2054 			error = ENETRESET;
2055 			break;
2056 		default:
2057 			/*
2058 			 * If the desired channel has changed (to something
2059 			 * other than any) and we're not already scanning,
2060 			 * then kick the state machine.
2061 			 */
2062 			if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
2063 			    ic->ic_bss->ni_chan != ic->ic_des_chan &&
2064 			    (ic->ic_flags & IEEE80211_F_SCAN) == 0)
2065 				error = ENETRESET;
2066 			break;
2067 		}
2068 		if (error == ENETRESET && ic->ic_opmode == IEEE80211_M_MONITOR)
2069 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2070 		break;
2071 	case IEEE80211_IOC_POWERSAVE:
2072 		switch (ireq->i_val) {
2073 		case IEEE80211_POWERSAVE_OFF:
2074 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
2075 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
2076 				error = ENETRESET;
2077 			}
2078 			break;
2079 		case IEEE80211_POWERSAVE_ON:
2080 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2081 				error = EINVAL;
2082 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2083 				ic->ic_flags |= IEEE80211_F_PMGTON;
2084 				error = ENETRESET;
2085 			}
2086 			break;
2087 		default:
2088 			error = EINVAL;
2089 			break;
2090 		}
2091 		break;
2092 	case IEEE80211_IOC_POWERSAVESLEEP:
2093 		if (ireq->i_val < 0)
2094 			return EINVAL;
2095 		ic->ic_lintval = ireq->i_val;
2096 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2097 		break;
2098 	case IEEE80211_IOC_RTSTHRESHOLD:
2099 		if (!(IEEE80211_RTS_MIN < ireq->i_val &&
2100 		      ireq->i_val < IEEE80211_RTS_MAX))
2101 			return EINVAL;
2102 		ic->ic_rtsthreshold = ireq->i_val;
2103 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2104 		break;
2105 	case IEEE80211_IOC_PROTMODE:
2106 		if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2107 			return EINVAL;
2108 		ic->ic_protmode = ireq->i_val;
2109 		/* NB: if not operating in 11g this can wait */
2110 		if (ic->ic_curmode == IEEE80211_MODE_11G)
2111 			error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2112 		break;
2113 	case IEEE80211_IOC_TXPOWER:
2114 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2115 			return EINVAL;
2116 		if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
2117 		      ireq->i_val < IEEE80211_TXPOWER_MAX))
2118 			return EINVAL;
2119 		ic->ic_txpowlimit = ireq->i_val;
2120 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2121 		break;
2122 	case IEEE80211_IOC_ROAMING:
2123 		if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2124 		    ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2125 			return EINVAL;
2126 		ic->ic_roaming = ireq->i_val;
2127 		/* XXXX reset? */
2128 		break;
2129 	case IEEE80211_IOC_PRIVACY:
2130 		if (ireq->i_val) {
2131 			/* XXX check for key state? */
2132 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2133 		} else
2134 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2135 		break;
2136 	case IEEE80211_IOC_DROPUNENCRYPTED:
2137 		if (ireq->i_val)
2138 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
2139 		else
2140 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2141 		break;
2142 	case IEEE80211_IOC_WPAKEY:
2143 		error = ieee80211_ioctl_setkey(ic, ireq);
2144 		break;
2145 	case IEEE80211_IOC_DELKEY:
2146 		error = ieee80211_ioctl_delkey(ic, ireq);
2147 		break;
2148 	case IEEE80211_IOC_MLME:
2149 		error = ieee80211_ioctl_setmlme(ic, ireq);
2150 		break;
2151 	case IEEE80211_IOC_OPTIE:
2152 		error = ieee80211_ioctl_setoptie(ic, ireq);
2153 		break;
2154 	case IEEE80211_IOC_COUNTERMEASURES:
2155 		if (ireq->i_val) {
2156 			if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
2157 				return EINVAL;
2158 			ic->ic_flags |= IEEE80211_F_COUNTERM;
2159 		} else
2160 			ic->ic_flags &= ~IEEE80211_F_COUNTERM;
2161 		break;
2162 	case IEEE80211_IOC_WPA:
2163 		if (ireq->i_val > 3)
2164 			return EINVAL;
2165 		/* XXX verify ciphers available */
2166 		ic->ic_flags &= ~IEEE80211_F_WPA;
2167 		switch (ireq->i_val) {
2168 		case 1:
2169 			ic->ic_flags |= IEEE80211_F_WPA1;
2170 			break;
2171 		case 2:
2172 			ic->ic_flags |= IEEE80211_F_WPA2;
2173 			break;
2174 		case 3:
2175 			ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
2176 			break;
2177 		}
2178 		error = ENETRESET;		/* XXX? */
2179 		break;
2180 	case IEEE80211_IOC_WME:
2181 		if (ireq->i_val) {
2182 			if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2183 				return EINVAL;
2184 			ic->ic_flags |= IEEE80211_F_WME;
2185 		} else
2186 			ic->ic_flags &= ~IEEE80211_F_WME;
2187 		error = ENETRESET;		/* XXX maybe not for station? */
2188 		break;
2189 	case IEEE80211_IOC_HIDESSID:
2190 		if (ireq->i_val)
2191 			ic->ic_flags |= IEEE80211_F_HIDESSID;
2192 		else
2193 			ic->ic_flags &= ~IEEE80211_F_HIDESSID;
2194 		error = ENETRESET;
2195 		break;
2196 	case IEEE80211_IOC_APBRIDGE:
2197 		if (ireq->i_val == 0)
2198 			ic->ic_flags |= IEEE80211_F_NOBRIDGE;
2199 		else
2200 			ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
2201 		break;
2202 	case IEEE80211_IOC_MCASTCIPHER:
2203 		if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
2204 		    !ieee80211_crypto_available(ireq->i_val))
2205 			return EINVAL;
2206 		rsn->rsn_mcastcipher = ireq->i_val;
2207 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2208 		break;
2209 	case IEEE80211_IOC_MCASTKEYLEN:
2210 		if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2211 			return EINVAL;
2212 		/* XXX no way to verify driver capability */
2213 		rsn->rsn_mcastkeylen = ireq->i_val;
2214 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2215 		break;
2216 	case IEEE80211_IOC_UCASTCIPHERS:
2217 		/*
2218 		 * Convert user-specified cipher set to the set
2219 		 * we can support (via hardware or software).
2220 		 * NB: this logic intentionally ignores unknown and
2221 		 * unsupported ciphers so folks can specify 0xff or
2222 		 * similar and get all available ciphers.
2223 		 */
2224 		caps = 0;
2225 		for (j = 1; j < 32; j++)	/* NB: skip WEP */
2226 			if ((ireq->i_val & (1<<j)) &&
2227 			    ((ic->ic_caps & cipher2cap(j)) ||
2228 			     ieee80211_crypto_available(j)))
2229 				caps |= 1<<j;
2230 		if (caps == 0)			/* nothing available */
2231 			return EINVAL;
2232 		/* XXX verify ciphers ok for unicast use? */
2233 		/* XXX disallow if running as it'll have no effect */
2234 		rsn->rsn_ucastcipherset = caps;
2235 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2236 		break;
2237 	case IEEE80211_IOC_UCASTCIPHER:
2238 		if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
2239 			return EINVAL;
2240 		rsn->rsn_ucastcipher = ireq->i_val;
2241 		break;
2242 	case IEEE80211_IOC_UCASTKEYLEN:
2243 		if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2244 			return EINVAL;
2245 		/* XXX no way to verify driver capability */
2246 		rsn->rsn_ucastkeylen = ireq->i_val;
2247 		break;
2248 	case IEEE80211_IOC_DRIVER_CAPS:
2249 		/* NB: for testing */
2250 		ic->ic_caps = (((u_int16_t) ireq->i_val) << 16) |
2251 			       ((u_int16_t) ireq->i_len);
2252 		break;
2253 	case IEEE80211_IOC_KEYMGTALGS:
2254 		/* XXX check */
2255 		rsn->rsn_keymgmtset = ireq->i_val;
2256 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2257 		break;
2258 	case IEEE80211_IOC_RSNCAPS:
2259 		/* XXX check */
2260 		rsn->rsn_caps = ireq->i_val;
2261 		error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2262 		break;
2263 	case IEEE80211_IOC_BSSID:
2264 		/* NB: should only be set when in STA mode */
2265 		if (ic->ic_opmode != IEEE80211_M_STA)
2266 			return EINVAL;
2267 		if (ireq->i_len != sizeof(tmpbssid))
2268 			return EINVAL;
2269 		error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
2270 		if (error)
2271 			break;
2272 		IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
2273 		if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
2274 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2275 		else
2276 			ic->ic_flags |= IEEE80211_F_DESBSSID;
2277 		error = ENETRESET;
2278 		break;
2279 	case IEEE80211_IOC_CHANLIST:
2280 		error = ieee80211_ioctl_setchanlist(ic, ireq);
2281 		break;
2282 	case IEEE80211_IOC_SCAN_REQ:
2283 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)	/* XXX ignore */
2284 			break;
2285 		error = ieee80211_setupscan(ic, ic->ic_chan_avail);
2286 		if (error == 0)		/* XXX background scan */
2287 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2288 		break;
2289 	case IEEE80211_IOC_ADDMAC:
2290 	case IEEE80211_IOC_DELMAC:
2291 		error = ieee80211_ioctl_macmac(ic, ireq);
2292 		break;
2293 	case IEEE80211_IOC_MACCMD:
2294 		error = ieee80211_ioctl_maccmd(ic, ireq);
2295 		break;
2296 	case IEEE80211_IOC_STA_TXPOW:
2297 		error = ieee80211_ioctl_setstatxpow(ic, ireq);
2298 		break;
2299 	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
2300 	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
2301 	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
2302 	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
2303 	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
2304 	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
2305 		error = ieee80211_ioctl_setwmeparam(ic, ireq);
2306 		break;
2307 	case IEEE80211_IOC_DTIM_PERIOD:
2308 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2309 		    ic->ic_opmode != IEEE80211_M_IBSS)
2310 			return EINVAL;
2311 		if (IEEE80211_DTIM_MIN <= ireq->i_val &&
2312 		    ireq->i_val <= IEEE80211_DTIM_MAX) {
2313 			ic->ic_dtim_period = ireq->i_val;
2314 			error = ENETRESET;		/* requires restart */
2315 		} else
2316 			error = EINVAL;
2317 		break;
2318 	case IEEE80211_IOC_BEACON_INTERVAL:
2319 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2320 		    ic->ic_opmode != IEEE80211_M_IBSS)
2321 			return EINVAL;
2322 		if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
2323 		    ireq->i_val <= IEEE80211_BINTVAL_MAX) {
2324 			ic->ic_lintval = ireq->i_val;
2325 			error = ENETRESET;		/* requires restart */
2326 		} else
2327 			error = EINVAL;
2328 		break;
2329 	default:
2330 		error = EINVAL;
2331 		break;
2332 	}
2333 	if (error == ENETRESET && !IS_UP_AUTO(ic))
2334 		error = 0;
2335 	return error;
2336 }
2337 
2338 #ifdef __FreeBSD__
2339 int
2340 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2341 {
2342 	struct ifnet *ifp = ic->ic_ifp;
2343 	int error = 0;
2344 	struct ifreq *ifr;
2345 	struct ifaddr *ifa;			/* XXX */
2346 
2347 	switch (cmd) {
2348 	case SIOCSIFMEDIA:
2349 	case SIOCGIFMEDIA:
2350 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
2351 				&ic->ic_media, cmd);
2352 		break;
2353 	case SIOCG80211:
2354 		error = ieee80211_ioctl_get80211(ic, cmd,
2355 				(struct ieee80211req *) data);
2356 		break;
2357 	case SIOCS80211:
2358 		error = suser(curthread);
2359 		if (error == 0)
2360 			error = ieee80211_ioctl_set80211(ic, cmd,
2361 					(struct ieee80211req *) data);
2362 		break;
2363 	case SIOCGIFGENERIC:
2364 		error = ieee80211_cfgget(ic, cmd, data);
2365 		break;
2366 	case SIOCSIFGENERIC:
2367 		error = suser(curthread);
2368 		if (error)
2369 			break;
2370 		error = ieee80211_cfgset(ic, cmd, data);
2371 		break;
2372 	case SIOCG80211STATS:
2373 		ifr = (struct ifreq *)data;
2374 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
2375 		break;
2376 	case SIOCSIFMTU:
2377 		ifr = (struct ifreq *)data;
2378 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
2379 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
2380 			error = EINVAL;
2381 		else
2382 			ifp->if_mtu = ifr->ifr_mtu;
2383 		break;
2384 	case SIOCSIFADDR:
2385 		/*
2386 		 * XXX Handle this directly so we can supress if_init calls.
2387 		 * XXX This should be done in ether_ioctl but for the moment
2388 		 * XXX there are too many other parts of the system that
2389 		 * XXX set IFF_UP and so supress if_init being called when
2390 		 * XXX it should be.
2391 		 */
2392 		ifa = (struct ifaddr *) data;
2393 		switch (ifa->ifa_addr->sa_family) {
2394 #ifdef INET
2395 		case AF_INET:
2396 			if ((ifp->if_flags & IFF_UP) == 0) {
2397 				ifp->if_flags |= IFF_UP;
2398 				ifp->if_init(ifp->if_softc);
2399 			}
2400 			arp_ifinit(ifp, ifa);
2401 			break;
2402 #endif
2403 #ifdef IPX
2404 		/*
2405 		 * XXX - This code is probably wrong,
2406 		 *	 but has been copied many times.
2407 		 */
2408 		case AF_IPX: {
2409 			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
2410 			struct arpcom *ac = (struct arpcom *)ifp;
2411 
2412 			if (ipx_nullhost(*ina))
2413 				ina->x_host = *(union ipx_host *) ac->ac_enaddr;
2414 			else
2415 				bcopy((caddr_t) ina->x_host.c_host,
2416 				      (caddr_t) ac->ac_enaddr,
2417 				      sizeof(ac->ac_enaddr));
2418 			/* fall thru... */
2419 		}
2420 #endif
2421 		default:
2422 			if ((ifp->if_flags & IFF_UP) == 0) {
2423 				ifp->if_flags |= IFF_UP;
2424 				ifp->if_init(ifp->if_softc);
2425 			}
2426 			break;
2427 		}
2428 		break;
2429 	default:
2430 		error = ether_ioctl(ifp, cmd, data);
2431 		break;
2432 	}
2433 	return error;
2434 }
2435 #endif /* __FreeBSD__ */
2436 
2437 #ifdef __NetBSD__
2438 int
2439 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2440 {
2441 	struct ifnet *ifp = ic->ic_ifp;
2442 	struct ifreq *ifr = (struct ifreq *)data;
2443 	int i, error = 0, kid, klen, s;
2444 	struct ieee80211_key *k;
2445 	struct ieee80211_nwid nwid;
2446 	struct ieee80211_nwkey *nwkey;
2447 	struct ieee80211_power *power;
2448 	struct ieee80211_bssid *bssid;
2449 	struct ieee80211chanreq *chanreq;
2450 	struct ieee80211_channel *chan;
2451 	uint32_t oflags;
2452 	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
2453 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2454 	};
2455 	u_int8_t tmpkey[IEEE80211_WEP_NKID][IEEE80211_KEYBUF_SIZE];
2456 
2457 	switch (cmd) {
2458 	case SIOCSIFMEDIA:
2459 	case SIOCGIFMEDIA:
2460 		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
2461 		break;
2462 	case SIOCG80211:
2463 		error = ieee80211_ioctl_get80211(ic, cmd,
2464 				(struct ieee80211req *) data);
2465 		break;
2466 	case SIOCS80211:
2467 		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
2468 			break;
2469 		error = ieee80211_ioctl_set80211(ic, cmd,
2470 				(struct ieee80211req *) data);
2471 		break;
2472 	case SIOCS80211NWID:
2473 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
2474 			break;
2475 		if (nwid.i_len > IEEE80211_NWID_LEN) {
2476 			error = EINVAL;
2477 			break;
2478 		}
2479 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
2480 		ic->ic_des_esslen = nwid.i_len;
2481 		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
2482 		error = ENETRESET;
2483 		break;
2484 	case SIOCG80211NWID:
2485 		memset(&nwid, 0, sizeof(nwid));
2486 		switch (ic->ic_state) {
2487 		case IEEE80211_S_INIT:
2488 		case IEEE80211_S_SCAN:
2489 			nwid.i_len = ic->ic_des_esslen;
2490 			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
2491 			break;
2492 		default:
2493 			nwid.i_len = ic->ic_bss->ni_esslen;
2494 			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
2495 			break;
2496 		}
2497 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
2498 		break;
2499 	case SIOCS80211NWKEY:
2500 		nwkey = (struct ieee80211_nwkey *)data;
2501 		/* transmit key index out of range? */
2502 		kid = nwkey->i_defkid - 1;
2503 		if (kid < 0 || kid >= IEEE80211_WEP_NKID) {
2504 			error = EINVAL;
2505 			break;
2506 		}
2507 		/* no such transmit key is set? */
2508 		if (nwkey->i_key[kid].i_keylen == 0 ||
2509 		    (nwkey->i_key[kid].i_keylen == -1 &&
2510 		     ic->ic_nw_keys[kid].wk_keylen == 0)) {
2511 			if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
2512 				error = EINVAL;
2513 				break;
2514 			}
2515 		}
2516 		/* check key lengths */
2517 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2518 			klen = nwkey->i_key[kid].i_keylen;
2519 			if ((klen > 0 &&
2520 			    klen < IEEE80211_WEP_KEYLEN) ||
2521 			    klen > sizeof(ic->ic_nw_keys[kid].wk_key)) {
2522 				error = EINVAL;
2523 				break;
2524 			}
2525 		}
2526 
2527 		if (error)
2528 			break;
2529 
2530 		/* copy in keys */
2531 		(void)memset(tmpkey, 0, sizeof(tmpkey));
2532 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2533 			klen = nwkey->i_key[kid].i_keylen;
2534 			if (klen <= 0)
2535 				continue;
2536 			if ((error = copyin(nwkey->i_key[kid].i_keydat,
2537 			    tmpkey[kid], klen)) != 0)
2538 				break;
2539 		}
2540 
2541 		if (error)
2542 			break;
2543 
2544 		/* set keys */
2545 		ieee80211_key_update_begin(ic);
2546 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2547 			klen = nwkey->i_key[kid].i_keylen;
2548 			if (klen <= 0)
2549 				continue;
2550 			k = &ic->ic_nw_keys[kid];
2551 			k->wk_keyix = kid;
2552 			if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
2553 			    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
2554 				error = EINVAL;
2555 				continue;
2556 			}
2557 			k->wk_keylen = nwkey->i_key[kid].i_keylen;
2558 			(void)memcpy(k->wk_key, tmpkey[kid],
2559 			    sizeof(tmpkey[kid]));
2560 			if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
2561 				error = EINVAL;
2562 		}
2563 		ieee80211_key_update_end(ic);
2564 
2565 		if (error)
2566 			break;
2567 
2568 		/* delete keys */
2569 		for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
2570 			klen = nwkey->i_key[kid].i_keylen;
2571 			k = &ic->ic_nw_keys[kid];
2572 			if (klen <= 0)
2573 				(void)ieee80211_crypto_delkey(ic, k);
2574 		}
2575 
2576 		/* set transmit key */
2577 		kid = nwkey->i_defkid - 1;
2578 		if (ic->ic_def_txkey != kid) {
2579 			ic->ic_def_txkey = kid;
2580 			error = ENETRESET;
2581 		}
2582 		oflags = ic->ic_flags;
2583 		if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
2584 			ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2585 			ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2586 		} else {
2587 			ic->ic_flags |= IEEE80211_F_PRIVACY;
2588 			ic->ic_flags |= IEEE80211_F_DROPUNENC;
2589 		}
2590 		if (oflags != ic->ic_flags)
2591 			error = ENETRESET;
2592 		break;
2593 	case SIOCG80211NWKEY:
2594 		nwkey = (struct ieee80211_nwkey *)data;
2595 		if (ic->ic_flags & IEEE80211_F_PRIVACY)
2596 			nwkey->i_wepon = IEEE80211_NWKEY_WEP;
2597 		else
2598 			nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
2599 		nwkey->i_defkid = ic->ic_def_txkey + 1;
2600 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2601 			if (nwkey->i_key[i].i_keydat == NULL)
2602 				continue;
2603 			/* do not show any keys to non-root user */
2604 			if ((error = suser(curproc->p_ucred,
2605 			    &curproc->p_acflag)) != 0)
2606 				break;
2607 			nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_keylen;
2608 			if ((error = copyout(ic->ic_nw_keys[i].wk_key,
2609 			    nwkey->i_key[i].i_keydat,
2610 			    ic->ic_nw_keys[i].wk_keylen)) != 0)
2611 				break;
2612 		}
2613 		break;
2614 	case SIOCS80211POWER:
2615 		power = (struct ieee80211_power *)data;
2616 		ic->ic_lintval = power->i_maxsleep;
2617 		if (power->i_enabled != 0) {
2618 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2619 				error = EINVAL;
2620 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2621 				ic->ic_flags |= IEEE80211_F_PMGTON;
2622 				error = ENETRESET;
2623 			}
2624 		} else {
2625 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
2626 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
2627 				error = ENETRESET;
2628 			}
2629 		}
2630 		break;
2631 	case SIOCG80211POWER:
2632 		power = (struct ieee80211_power *)data;
2633 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
2634 		power->i_maxsleep = ic->ic_lintval;
2635 		break;
2636 	case SIOCS80211BSSID:
2637 		bssid = (struct ieee80211_bssid *)data;
2638 		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
2639 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2640 		else {
2641 			ic->ic_flags |= IEEE80211_F_DESBSSID;
2642 			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
2643 		}
2644 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2645 			break;
2646 		switch (ic->ic_state) {
2647 		case IEEE80211_S_INIT:
2648 		case IEEE80211_S_SCAN:
2649 			error = ENETRESET;
2650 			break;
2651 		default:
2652 			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
2653 			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
2654 			    ic->ic_bss->ni_bssid))
2655 				error = ENETRESET;
2656 			break;
2657 		}
2658 		break;
2659 	case SIOCG80211BSSID:
2660 		bssid = (struct ieee80211_bssid *)data;
2661 		switch (ic->ic_state) {
2662 		case IEEE80211_S_INIT:
2663 		case IEEE80211_S_SCAN:
2664 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2665 				IEEE80211_ADDR_COPY(bssid->i_bssid,
2666 				    ic->ic_myaddr);
2667 			else if (ic->ic_flags & IEEE80211_F_DESBSSID)
2668 				IEEE80211_ADDR_COPY(bssid->i_bssid,
2669 				    ic->ic_des_bssid);
2670 			else
2671 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
2672 			break;
2673 		default:
2674 			IEEE80211_ADDR_COPY(bssid->i_bssid,
2675 			    ic->ic_bss->ni_bssid);
2676 			break;
2677 		}
2678 		break;
2679 	case SIOCS80211CHANNEL:
2680 		chanreq = (struct ieee80211chanreq *)data;
2681 		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
2682 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
2683 		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
2684 		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
2685 			error = EINVAL;
2686 			break;
2687 		} else
2688 			ic->ic_ibss_chan = ic->ic_des_chan =
2689 			    &ic->ic_channels[chanreq->i_channel];
2690 		switch (ic->ic_state) {
2691 		case IEEE80211_S_INIT:
2692 		case IEEE80211_S_SCAN:
2693 			error = ENETRESET;
2694 			break;
2695 		default:
2696 			if (ic->ic_opmode == IEEE80211_M_STA) {
2697 				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
2698 				    ic->ic_bss->ni_chan != ic->ic_des_chan)
2699 					error = ENETRESET;
2700 			} else {
2701 				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
2702 					error = ENETRESET;
2703 			}
2704 			break;
2705 		}
2706 		break;
2707 	case SIOCG80211CHANNEL:
2708 		chanreq = (struct ieee80211chanreq *)data;
2709 		switch (ic->ic_state) {
2710 		case IEEE80211_S_INIT:
2711 		case IEEE80211_S_SCAN:
2712 			if (ic->ic_opmode == IEEE80211_M_STA)
2713 				chan = ic->ic_des_chan;
2714 			else
2715 				chan = ic->ic_ibss_chan;
2716 			break;
2717 		default:
2718 			chan = ic->ic_bss->ni_chan;
2719 			break;
2720 		}
2721 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
2722 		break;
2723 	case SIOCGIFGENERIC:
2724 		error = ieee80211_cfgget(ic, cmd, data);
2725 		break;
2726 	case SIOCSIFGENERIC:
2727 		error = suser(curproc->p_ucred, &curproc->p_acflag);
2728 		if (error)
2729 			break;
2730 		error = ieee80211_cfgset(ic, cmd, data);
2731 		break;
2732 	case SIOCG80211ZSTATS:
2733 	case SIOCG80211STATS:
2734 		ifr = (struct ifreq *)data;
2735 		s = splnet();
2736 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
2737 		if (cmd == SIOCG80211ZSTATS)
2738 			(void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
2739 		splx(s);
2740 		break;
2741 	case SIOCSIFMTU:
2742 		ifr = (struct ifreq *)data;
2743 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
2744 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
2745 			error = EINVAL;
2746 		else
2747 			ifp->if_mtu = ifr->ifr_mtu;
2748 		break;
2749 	default:
2750 		error = ether_ioctl(ifp, cmd, data);
2751 		break;
2752 	}
2753 	return error;
2754 }
2755 #endif /* __NetBSD__ */
2756