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