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