1/*	$OpenBSD: ieee80211_ioctl.c,v 1.81 2022/03/07 08:13:13 stsp Exp $	*/
2/*	$NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $	*/
3
4/*-
5 * Copyright (c) 2001 Atsushi Onoe
6 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * IEEE 802.11 ioctl support
34 */
35
36#include <sys/param.h>
37#include <sys/kernel.h>
38#include <sys/socket.h>
39#include <sys/sockio.h>
40#include <sys/systm.h>
41#include <sys/endian.h>
42#include <sys/tree.h>
43
44#include <net/if.h>
45#include <net/if_media.h>
46
47#include <netinet/in.h>
48#include <netinet/if_ether.h>
49
50#include <net80211/ieee80211_var.h>
51#include <net80211/ieee80211_crypto.h>
52#include <net80211/ieee80211_ioctl.h>
53
54void	 ieee80211_node2req(struct ieee80211com *,
55	    const struct ieee80211_node *, struct ieee80211_nodereq *);
56void	 ieee80211_req2node(struct ieee80211com *,
57	    const struct ieee80211_nodereq *, struct ieee80211_node *);
58
59void
60ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
61    struct ieee80211_nodereq *nr)
62{
63	uint8_t rssi;
64
65	memset(nr, 0, sizeof(*nr));
66
67	strlcpy(nr->nr_ifname, ic->ic_if.if_xname, sizeof(nr->nr_ifname));
68
69	/* Node address and name information */
70	IEEE80211_ADDR_COPY(nr->nr_macaddr, ni->ni_macaddr);
71	IEEE80211_ADDR_COPY(nr->nr_bssid, ni->ni_bssid);
72	nr->nr_nwid_len = ni->ni_esslen;
73	bcopy(ni->ni_essid, nr->nr_nwid, IEEE80211_NWID_LEN);
74
75	/* Channel and rates */
76	nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan);
77	if (ni->ni_chan != IEEE80211_CHAN_ANYC)
78		nr->nr_chan_flags = ni->ni_chan->ic_flags;
79	if (ic->ic_curmode != IEEE80211_MODE_11N)
80		nr->nr_chan_flags &= ~IEEE80211_CHAN_HT;
81	nr->nr_nrates = ni->ni_rates.rs_nrates;
82	bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE);
83
84	/* Node status information */
85	rssi = (*ic->ic_node_getrssi)(ic, ni);
86	if (ic->ic_max_rssi) {
87		/* Driver reports RSSI relative to ic_max_rssi. */
88		nr->nr_rssi = rssi;
89	} else {
90		/*
91		 * Driver reports RSSI value in dBm.
92		 * Convert from unsigned to signed.
93		 * Some drivers report a negative value, some don't.
94		 * Reasonable range is -20dBm to -80dBm.
95		 */
96		nr->nr_rssi = (rssi < 128) ? -rssi : rssi;
97	}
98	nr->nr_max_rssi = ic->ic_max_rssi;
99	bcopy(ni->ni_tstamp, nr->nr_tstamp, sizeof(nr->nr_tstamp));
100	nr->nr_intval = ni->ni_intval;
101	nr->nr_capinfo = ni->ni_capinfo;
102	nr->nr_erp = ni->ni_erp;
103	nr->nr_pwrsave = ni->ni_pwrsave;
104	nr->nr_associd = ni->ni_associd;
105	nr->nr_txseq = ni->ni_txseq;
106	nr->nr_rxseq = ni->ni_rxseq;
107	nr->nr_fails = ni->ni_fails;
108	nr->nr_assoc_fail = ni->ni_assoc_fail; /* flag values are the same */
109	nr->nr_inact = ni->ni_inact;
110	nr->nr_txrate = ni->ni_txrate;
111	nr->nr_state = ni->ni_state;
112
113	/* RSN */
114	nr->nr_rsnciphers = ni->ni_rsnciphers;
115	nr->nr_rsnakms = 0;
116	nr->nr_rsnprotos = 0;
117	if (ni->ni_supported_rsnprotos & IEEE80211_PROTO_RSN)
118		nr->nr_rsnprotos |= IEEE80211_WPA_PROTO_WPA2;
119	if (ni->ni_supported_rsnprotos & IEEE80211_PROTO_WPA)
120		nr->nr_rsnprotos |= IEEE80211_WPA_PROTO_WPA1;
121	if (ni->ni_supported_rsnakms & IEEE80211_AKM_8021X)
122		nr->nr_rsnakms |= IEEE80211_WPA_AKM_8021X;
123	if (ni->ni_supported_rsnakms & IEEE80211_AKM_PSK)
124		nr->nr_rsnakms |= IEEE80211_WPA_AKM_PSK;
125	if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_8021X)
126		nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_8021X;
127	if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_PSK)
128		nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_PSK;
129
130	/* Node flags */
131	nr->nr_flags = 0;
132	if (bcmp(nr->nr_macaddr, nr->nr_bssid, IEEE80211_ADDR_LEN) == 0)
133		nr->nr_flags |= IEEE80211_NODEREQ_AP;
134	if (ni == ic->ic_bss)
135		nr->nr_flags |= IEEE80211_NODEREQ_AP_BSS;
136
137	/* HT */
138	nr->nr_htcaps = ni->ni_htcaps;
139	memcpy(nr->nr_rxmcs, ni->ni_rxmcs, sizeof(nr->nr_rxmcs));
140	nr->nr_max_rxrate = ni->ni_max_rxrate;
141	nr->nr_tx_mcs_set = ni->ni_tx_mcs_set;
142	if (ni->ni_flags & IEEE80211_NODE_HT)
143		nr->nr_flags |= IEEE80211_NODEREQ_HT;
144
145	/* HT / VHT */
146	nr->nr_txmcs = ni->ni_txmcs;
147
148	/* VHT */
149	nr->nr_vht_ss = ni->ni_vht_ss;
150	if (ni->ni_flags & IEEE80211_NODE_VHT)
151		nr->nr_flags |= IEEE80211_NODEREQ_VHT;
152}
153
154void
155ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr,
156    struct ieee80211_node *ni)
157{
158	/* Node address and name information */
159	IEEE80211_ADDR_COPY(ni->ni_macaddr, nr->nr_macaddr);
160	IEEE80211_ADDR_COPY(ni->ni_bssid, nr->nr_bssid);
161	ni->ni_esslen = nr->nr_nwid_len;
162	bcopy(nr->nr_nwid, ni->ni_essid, IEEE80211_NWID_LEN);
163
164	/* Rates */
165	ni->ni_rates.rs_nrates = nr->nr_nrates;
166	bcopy(nr->nr_rates, ni->ni_rates.rs_rates, IEEE80211_RATE_MAXSIZE);
167
168	/* Node information */
169	ni->ni_intval = nr->nr_intval;
170	ni->ni_capinfo = nr->nr_capinfo;
171	ni->ni_erp = nr->nr_erp;
172	ni->ni_pwrsave = nr->nr_pwrsave;
173	ni->ni_associd = nr->nr_associd;
174	ni->ni_txseq = nr->nr_txseq;
175	ni->ni_rxseq = nr->nr_rxseq;
176	ni->ni_fails = nr->nr_fails;
177	ni->ni_inact = nr->nr_inact;
178	ni->ni_txrate = nr->nr_txrate;
179	ni->ni_state = nr->nr_state;
180}
181
182void
183ieee80211_disable_wep(struct ieee80211com *ic)
184{
185	struct ieee80211_key *k;
186	int i;
187
188	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
189		k = &ic->ic_nw_keys[i];
190		if (k->k_cipher != IEEE80211_CIPHER_NONE)
191			(*ic->ic_delete_key)(ic, NULL, k);
192		explicit_bzero(k, sizeof(*k));
193	}
194	ic->ic_flags &= ~IEEE80211_F_WEPON;
195}
196
197void
198ieee80211_disable_rsn(struct ieee80211com *ic)
199{
200	ic->ic_flags &= ~(IEEE80211_F_PSK | IEEE80211_F_RSNON);
201	explicit_bzero(ic->ic_psk, sizeof(ic->ic_psk));
202	ic->ic_rsnprotos = 0;
203	ic->ic_rsnakms = 0;
204	ic->ic_rsngroupcipher = 0;
205	ic->ic_rsnciphers = 0;
206}
207
208/* Keep in sync with ieee80211_node.c:ieee80211_ess_setnwkeys() */
209static int
210ieee80211_ioctl_setnwkeys(struct ieee80211com *ic,
211    const struct ieee80211_nwkey *nwkey)
212{
213	struct ieee80211_key *k;
214	int error, i;
215
216	if (!(ic->ic_caps & IEEE80211_C_WEP))
217		return ENODEV;
218
219	if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
220		if (!(ic->ic_flags & IEEE80211_F_WEPON))
221			return 0;
222		ic->ic_flags &= ~IEEE80211_F_WEPON;
223		return ENETRESET;
224	}
225	if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID)
226		return EINVAL;
227
228	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
229		if (nwkey->i_key[i].i_keylen == 0 ||
230		    nwkey->i_key[i].i_keydat == NULL)
231			continue;	/* entry not set */
232		if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE)
233			return EINVAL;
234
235		/* map wep key to ieee80211_key */
236		k = &ic->ic_nw_keys[i];
237		if (k->k_cipher != IEEE80211_CIPHER_NONE)
238			(*ic->ic_delete_key)(ic, NULL, k);
239		memset(k, 0, sizeof(*k));
240		if (nwkey->i_key[i].i_keylen <= 5)
241			k->k_cipher = IEEE80211_CIPHER_WEP40;
242		else
243			k->k_cipher = IEEE80211_CIPHER_WEP104;
244		k->k_len = ieee80211_cipher_keylen(k->k_cipher);
245		k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
246		error = copyin(nwkey->i_key[i].i_keydat, k->k_key, k->k_len);
247		if (error != 0)
248			return error;
249		error = (*ic->ic_set_key)(ic, NULL, k);
250		switch (error) {
251		case 0:
252		case EBUSY:
253			break;
254		default:
255			return error;
256		}
257	}
258
259	ic->ic_def_txkey = nwkey->i_defkid - 1;
260	ic->ic_flags |= IEEE80211_F_WEPON;
261	if (ic->ic_flags & IEEE80211_F_RSNON)
262		ieee80211_disable_rsn(ic);
263
264	return ENETRESET;
265}
266
267static int
268ieee80211_ioctl_getnwkeys(struct ieee80211com *ic,
269    struct ieee80211_nwkey *nwkey)
270{
271	int i;
272
273	if (ic->ic_flags & IEEE80211_F_WEPON)
274		nwkey->i_wepon = IEEE80211_NWKEY_WEP;
275	else
276		nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
277
278	nwkey->i_defkid = ic->ic_wep_txkey + 1;
279
280	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
281		if (nwkey->i_key[i].i_keydat == NULL)
282			continue;
283		/* do not show any keys to userland */
284		return EPERM;
285	}
286	return 0;
287}
288
289/* Keep in sync with ieee80211_node.c:ieee80211_ess_setwpaparms() */
290static int
291ieee80211_ioctl_setwpaparms(struct ieee80211com *ic,
292    const struct ieee80211_wpaparams *wpa)
293{
294	if (!(ic->ic_caps & IEEE80211_C_RSN))
295		return ENODEV;
296
297	if (!wpa->i_enabled) {
298		if (!(ic->ic_flags & IEEE80211_F_RSNON))
299			return 0;
300		ic->ic_flags &= ~IEEE80211_F_RSNON;
301		ic->ic_rsnprotos = 0;
302		ic->ic_rsnakms = 0;
303		ic->ic_rsngroupcipher = 0;
304		ic->ic_rsnciphers = 0;
305		return ENETRESET;
306	}
307
308	ic->ic_rsnprotos = 0;
309	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1)
310		ic->ic_rsnprotos |= IEEE80211_PROTO_WPA;
311	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
312		ic->ic_rsnprotos |= IEEE80211_PROTO_RSN;
313	if (ic->ic_rsnprotos == 0)	/* set to default (RSN) */
314		ic->ic_rsnprotos = IEEE80211_PROTO_RSN;
315
316	ic->ic_rsnakms = 0;
317	if (wpa->i_akms & IEEE80211_WPA_AKM_PSK)
318		ic->ic_rsnakms |= IEEE80211_AKM_PSK;
319	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_PSK)
320		ic->ic_rsnakms |= IEEE80211_AKM_SHA256_PSK;
321	if (wpa->i_akms & IEEE80211_WPA_AKM_8021X)
322		ic->ic_rsnakms |= IEEE80211_AKM_8021X;
323	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X)
324		ic->ic_rsnakms |= IEEE80211_AKM_SHA256_8021X;
325	if (ic->ic_rsnakms == 0)	/* set to default (PSK) */
326		ic->ic_rsnakms = IEEE80211_AKM_PSK;
327
328	if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40)
329		ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP40;
330	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP)
331		ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
332	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP)
333		ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
334	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104)
335		ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP104;
336	else  {	/* set to default */
337		if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
338			ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
339		else
340			ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
341	}
342
343	ic->ic_rsnciphers = 0;
344	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP)
345		ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP;
346	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP)
347		ic->ic_rsnciphers |= IEEE80211_CIPHER_CCMP;
348	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP)
349		ic->ic_rsnciphers = IEEE80211_CIPHER_USEGROUP;
350	if (ic->ic_rsnciphers == 0) { /* set to default (CCMP, TKIP if WPA1) */
351		ic->ic_rsnciphers = IEEE80211_CIPHER_CCMP;
352		if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
353			ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP;
354	}
355
356	ic->ic_flags |= IEEE80211_F_RSNON;
357
358	return ENETRESET;
359}
360
361static int
362ieee80211_ioctl_getwpaparms(struct ieee80211com *ic,
363    struct ieee80211_wpaparams *wpa)
364{
365	wpa->i_enabled = (ic->ic_flags & IEEE80211_F_RSNON) ? 1 : 0;
366
367	wpa->i_protos = 0;
368	if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
369		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1;
370	if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)
371		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2;
372
373	wpa->i_akms = 0;
374	if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
375		wpa->i_akms |= IEEE80211_WPA_AKM_PSK;
376	if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK)
377		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK;
378	if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
379		wpa->i_akms |= IEEE80211_WPA_AKM_8021X;
380	if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X)
381		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X;
382
383	if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP40)
384		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40;
385	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_TKIP)
386		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP;
387	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP)
388		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP;
389	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP104)
390		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104;
391	else
392		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE;
393
394	wpa->i_ciphers = 0;
395	if (ic->ic_rsnciphers & IEEE80211_CIPHER_TKIP)
396		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
397	if (ic->ic_rsnciphers & IEEE80211_CIPHER_CCMP)
398		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
399	if (ic->ic_rsnciphers & IEEE80211_CIPHER_USEGROUP)
400		wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP;
401
402	return 0;
403}
404
405static void
406ieee80211_ess_getwpaparms(struct ieee80211_ess *ess,
407    struct ieee80211_wpaparams *wpa)
408{
409	wpa->i_enabled = (ess->flags & IEEE80211_F_RSNON) ? 1 : 0;
410
411	wpa->i_protos = 0;
412	if (ess->rsnprotos & IEEE80211_PROTO_WPA)
413		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1;
414	if (ess->rsnprotos & IEEE80211_PROTO_RSN)
415		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2;
416
417	wpa->i_akms = 0;
418	if (ess->rsnakms & IEEE80211_AKM_PSK)
419		wpa->i_akms |= IEEE80211_WPA_AKM_PSK;
420	if (ess->rsnakms & IEEE80211_AKM_SHA256_PSK)
421		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK;
422	if (ess->rsnakms & IEEE80211_AKM_8021X)
423		wpa->i_akms |= IEEE80211_WPA_AKM_8021X;
424	if (ess->rsnakms & IEEE80211_AKM_SHA256_8021X)
425		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X;
426
427	if (ess->rsngroupcipher == IEEE80211_CIPHER_WEP40)
428		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40;
429	else if (ess->rsngroupcipher == IEEE80211_CIPHER_TKIP)
430		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP;
431	else if (ess->rsngroupcipher == IEEE80211_CIPHER_CCMP)
432		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP;
433	else if (ess->rsngroupcipher == IEEE80211_CIPHER_WEP104)
434		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104;
435	else
436		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE;
437
438	wpa->i_ciphers = 0;
439	if (ess->rsnciphers & IEEE80211_CIPHER_TKIP)
440		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
441	if (ess->rsnciphers & IEEE80211_CIPHER_CCMP)
442		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
443	if (ess->rsnciphers & IEEE80211_CIPHER_USEGROUP)
444		wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP;
445}
446
447int
448ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
449{
450	struct ieee80211com *ic = (void *)ifp;
451	struct ifreq *ifr = (struct ifreq *)data;
452	int i, error = 0;
453	size_t len;
454	struct ieee80211_nwid nwid;
455	struct ieee80211_join join;
456	struct ieee80211_joinreq_all *ja;
457	struct ieee80211_ess *ess;
458	struct ieee80211_wpapsk *psk;
459	struct ieee80211_keyavail *ka;
460	struct ieee80211_keyrun *kr;
461	struct ieee80211_power *power;
462	struct ieee80211_bssid *bssid;
463	struct ieee80211chanreq *chanreq;
464	struct ieee80211_channel *chan;
465	struct ieee80211_txpower *txpower;
466	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
467		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
468	};
469	struct ieee80211_nodereq *nr, nrbuf;
470	struct ieee80211_nodereq_all *na;
471	struct ieee80211_node *ni;
472	struct ieee80211_chaninfo chaninfo;
473	struct ieee80211_chanreq_all *allchans;
474	u_int32_t flags;
475
476	switch (cmd) {
477	case SIOCSIFMEDIA:
478	case SIOCGIFMEDIA:
479		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
480		break;
481	case SIOCS80211NWID:
482		if ((error = suser(curproc)) != 0)
483			break;
484		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
485			break;
486		if (nwid.i_len > IEEE80211_NWID_LEN) {
487			error = EINVAL;
488			break;
489		}
490		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
491		ic->ic_des_esslen = nwid.i_len;
492		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
493		if (ic->ic_des_esslen > 0) {
494			/* 'nwid' disables auto-join magic */
495			ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN;
496		} else if (!TAILQ_EMPTY(&ic->ic_ess)) {
497			/* '-nwid' re-enables auto-join */
498			ic->ic_flags |= IEEE80211_F_AUTO_JOIN;
499		}
500		/* disable WPA/WEP */
501		ieee80211_disable_rsn(ic);
502		ieee80211_disable_wep(ic);
503		error = ENETRESET;
504		break;
505	case SIOCG80211NWID:
506		memset(&nwid, 0, sizeof(nwid));
507		switch (ic->ic_state) {
508		case IEEE80211_S_INIT:
509		case IEEE80211_S_SCAN:
510			nwid.i_len = ic->ic_des_esslen;
511			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
512			break;
513		default:
514			nwid.i_len = ic->ic_bss->ni_esslen;
515			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
516			break;
517		}
518		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
519		break;
520	case SIOCS80211JOIN:
521		if ((error = suser(curproc)) != 0)
522			break;
523		if (ic->ic_opmode != IEEE80211_M_STA)
524			break;
525		if ((error = copyin(ifr->ifr_data, &join, sizeof(join))) != 0)
526			break;
527		if (join.i_len > IEEE80211_NWID_LEN) {
528			error = EINVAL;
529			break;
530		}
531		if (join.i_flags & IEEE80211_JOIN_DEL) {
532			int update_ic = 0;
533			if (ic->ic_des_esslen == join.i_len &&
534			    memcmp(join.i_nwid, ic->ic_des_essid,
535			    join.i_len) == 0)
536				update_ic = 1;
537			if (join.i_flags & IEEE80211_JOIN_DEL_ALL &&
538			    ieee80211_get_ess(ic, ic->ic_des_essid,
539			    ic->ic_des_esslen) != NULL)
540				update_ic = 1;
541			ieee80211_del_ess(ic, join.i_nwid, join.i_len,
542			    join.i_flags & IEEE80211_JOIN_DEL_ALL ? 1 : 0);
543			if (update_ic == 1) {
544				/* Unconfigure this essid */
545				memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
546				ic->ic_des_esslen = 0;
547				/* disable WPA/WEP */
548				ieee80211_disable_rsn(ic);
549				ieee80211_disable_wep(ic);
550				error = ENETRESET;
551			}
552		} else {
553			if (ic->ic_des_esslen == join.i_len &&
554			    memcmp(join.i_nwid, ic->ic_des_essid,
555			    join.i_len) == 0) {
556				struct ieee80211_node *ni;
557
558				ieee80211_deselect_ess(ic);
559				ni = ieee80211_find_node(ic,
560				    ic->ic_bss->ni_bssid);
561				if (ni != NULL)
562					ieee80211_free_node(ic, ni);
563				error = ENETRESET;
564			}
565			/* save nwid for auto-join */
566			if (ieee80211_add_ess(ic, &join) == 0)
567				ic->ic_flags |= IEEE80211_F_AUTO_JOIN;
568		}
569		break;
570	case SIOCG80211JOIN:
571		memset(&join, 0, sizeof(join));
572		error = ENOENT;
573		if (ic->ic_bss == NULL)
574			break;
575		TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
576			if (memcmp(ess->essid, ic->ic_bss->ni_essid,
577			    IEEE80211_NWID_LEN) == 0) {
578				join.i_len = ic->ic_bss->ni_esslen;
579				memcpy(join.i_nwid, ic->ic_bss->ni_essid,
580				    join.i_len);
581				if (ic->ic_flags & IEEE80211_F_AUTO_JOIN)
582					join.i_flags = IEEE80211_JOIN_FOUND;
583				error = copyout(&join, ifr->ifr_data,
584				    sizeof(join));
585				break;
586			}
587		}
588		break;
589	case SIOCG80211JOINALL:
590		ja = (struct ieee80211_joinreq_all *)data;
591		ja->ja_nodes = len = 0;
592		TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
593			if (len + sizeof(ja->ja_node[0]) >= ja->ja_size) {
594				error = E2BIG;
595				break;
596			}
597			memset(&join, 0, sizeof(join));
598			join.i_len = ess->esslen;
599			memcpy(&join.i_nwid, ess->essid, join.i_len);
600			if (ess->flags & IEEE80211_F_RSNON)
601				join.i_flags |= IEEE80211_JOIN_WPA;
602			if (ess->flags & IEEE80211_F_PSK)
603				join.i_flags |= IEEE80211_JOIN_WPAPSK;
604			if (ess->flags & IEEE80211_JOIN_8021X)
605				join.i_flags |= IEEE80211_JOIN_8021X;
606			if (ess->flags & IEEE80211_F_WEPON)
607				join.i_flags |= IEEE80211_JOIN_NWKEY;
608			if (ess->flags & IEEE80211_JOIN_ANY)
609				join.i_flags |= IEEE80211_JOIN_ANY;
610			ieee80211_ess_getwpaparms(ess, &join.i_wpaparams);
611			error = copyout(&join, &ja->ja_node[ja->ja_nodes],
612			    sizeof(ja->ja_node[0]));
613			if (error)
614				break;
615			len += sizeof(join);
616			ja->ja_nodes++;
617		}
618		break;
619	case SIOCS80211NWKEY:
620		if ((error = suser(curproc)) != 0)
621			break;
622		error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
623		break;
624	case SIOCG80211NWKEY:
625		error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
626		break;
627	case SIOCS80211WPAPARMS:
628		if ((error = suser(curproc)) != 0)
629			break;
630		error = ieee80211_ioctl_setwpaparms(ic, (void *)data);
631		break;
632	case SIOCG80211WPAPARMS:
633		error = ieee80211_ioctl_getwpaparms(ic, (void *)data);
634		break;
635	case SIOCS80211WPAPSK:
636		if ((error = suser(curproc)) != 0)
637			break;
638		psk = (struct ieee80211_wpapsk *)data;
639		if (psk->i_enabled) {
640			ic->ic_flags |= IEEE80211_F_PSK;
641			memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
642			if (ic->ic_flags & IEEE80211_F_WEPON)
643				ieee80211_disable_wep(ic);
644		} else {
645			ic->ic_flags &= ~IEEE80211_F_PSK;
646			memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
647		}
648		error = ENETRESET;
649		break;
650	case SIOCG80211WPAPSK:
651		psk = (struct ieee80211_wpapsk *)data;
652		if (ic->ic_flags & IEEE80211_F_PSK) {
653			/* do not show any keys to userland */
654			psk->i_enabled = 2;
655			memset(psk->i_psk, 0, sizeof(psk->i_psk));
656			break;	/* return ok but w/o key */
657		} else
658			psk->i_enabled = 0;
659		break;
660	case SIOCS80211KEYAVAIL:
661		if ((error = suser(curproc)) != 0)
662			break;
663		ka = (struct ieee80211_keyavail *)data;
664		(void)ieee80211_pmksa_add(ic, IEEE80211_AKM_8021X,
665		    ka->i_macaddr, ka->i_key, ka->i_lifetime);
666		break;
667	case SIOCS80211KEYRUN:
668		if ((error = suser(curproc)) != 0)
669			break;
670		kr = (struct ieee80211_keyrun *)data;
671		error = ieee80211_keyrun(ic, kr->i_macaddr);
672		if (error == 0 && (ic->ic_flags & IEEE80211_F_WEPON))
673			ieee80211_disable_wep(ic);
674		break;
675	case SIOCS80211POWER:
676		if ((error = suser(curproc)) != 0)
677			break;
678		power = (struct ieee80211_power *)data;
679		ic->ic_lintval = power->i_maxsleep;
680		if (power->i_enabled != 0) {
681			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
682				error = EINVAL;
683			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
684				ic->ic_flags |= IEEE80211_F_PMGTON;
685				error = ENETRESET;
686			}
687		} else {
688			if (ic->ic_flags & IEEE80211_F_PMGTON) {
689				ic->ic_flags &= ~IEEE80211_F_PMGTON;
690				error = ENETRESET;
691			}
692		}
693		break;
694	case SIOCG80211POWER:
695		power = (struct ieee80211_power *)data;
696		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
697		power->i_maxsleep = ic->ic_lintval;
698		break;
699	case SIOCS80211BSSID:
700		if ((error = suser(curproc)) != 0)
701			break;
702		bssid = (struct ieee80211_bssid *)data;
703		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
704			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
705		else {
706			ic->ic_flags |= IEEE80211_F_DESBSSID;
707			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
708		}
709#ifndef IEEE80211_STA_ONLY
710		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
711			break;
712#endif
713		switch (ic->ic_state) {
714		case IEEE80211_S_INIT:
715		case IEEE80211_S_SCAN:
716			error = ENETRESET;
717			break;
718		default:
719			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
720			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
721			    ic->ic_bss->ni_bssid))
722				error = ENETRESET;
723			break;
724		}
725		break;
726	case SIOCG80211BSSID:
727		bssid = (struct ieee80211_bssid *)data;
728		switch (ic->ic_state) {
729		case IEEE80211_S_INIT:
730		case IEEE80211_S_SCAN:
731#ifndef IEEE80211_STA_ONLY
732			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
733				IEEE80211_ADDR_COPY(bssid->i_bssid,
734				    ic->ic_myaddr);
735			else
736#endif
737			if (ic->ic_flags & IEEE80211_F_DESBSSID)
738				IEEE80211_ADDR_COPY(bssid->i_bssid,
739				    ic->ic_des_bssid);
740			else
741				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
742			break;
743		default:
744			IEEE80211_ADDR_COPY(bssid->i_bssid,
745			    ic->ic_bss->ni_bssid);
746			break;
747		}
748		break;
749	case SIOCS80211CHANNEL:
750		if ((error = suser(curproc)) != 0)
751			break;
752		chanreq = (struct ieee80211chanreq *)data;
753		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
754			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
755		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
756		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
757			error = EINVAL;
758			break;
759		} else
760			ic->ic_ibss_chan = ic->ic_des_chan =
761			    &ic->ic_channels[chanreq->i_channel];
762		switch (ic->ic_state) {
763		case IEEE80211_S_INIT:
764		case IEEE80211_S_SCAN:
765			error = ENETRESET;
766			break;
767		default:
768			if (ic->ic_opmode == IEEE80211_M_STA) {
769				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
770				    ic->ic_bss->ni_chan != ic->ic_des_chan)
771					error = ENETRESET;
772			} else {
773				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
774					error = ENETRESET;
775			}
776			break;
777		}
778		break;
779	case SIOCG80211CHANNEL:
780		chanreq = (struct ieee80211chanreq *)data;
781		switch (ic->ic_state) {
782		case IEEE80211_S_INIT:
783		case IEEE80211_S_SCAN:
784			if (ic->ic_opmode == IEEE80211_M_STA)
785				chan = ic->ic_des_chan;
786			else
787				chan = ic->ic_ibss_chan;
788			break;
789		default:
790			chan = ic->ic_bss->ni_chan;
791			break;
792		}
793		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
794		break;
795	case SIOCG80211ALLCHANS:
796		allchans = (struct ieee80211_chanreq_all *)data;
797		for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
798			chan = &ic->ic_channels[i];
799			chaninfo.ic_freq = chan->ic_freq;
800			chaninfo.ic_flags = 0;
801			if (chan->ic_flags & IEEE80211_CHAN_2GHZ)
802				chaninfo.ic_flags |= IEEE80211_CHANINFO_2GHZ;
803			if (chan->ic_flags & IEEE80211_CHAN_5GHZ)
804				chaninfo.ic_flags |= IEEE80211_CHANINFO_5GHZ;
805			if (chan->ic_flags & IEEE80211_CHAN_PASSIVE)
806				chaninfo.ic_flags |= IEEE80211_CHANINFO_PASSIVE;
807			error = copyout(&chaninfo, &allchans->i_chans[i],
808			    sizeof(chaninfo));
809			if (error)
810				break;
811		}
812		break;
813#if 0
814	case SIOCG80211ZSTATS:
815#endif
816	case SIOCG80211STATS:
817		ifr = (struct ifreq *)data;
818		error = copyout(&ic->ic_stats, ifr->ifr_data,
819		    sizeof(ic->ic_stats));
820#if 0
821		if (cmd == SIOCG80211ZSTATS)
822			memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
823#endif
824		break;
825	case SIOCS80211TXPOWER:
826		if ((error = suser(curproc)) != 0)
827			break;
828		txpower = (struct ieee80211_txpower *)data;
829		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
830			error = EINVAL;
831			break;
832		}
833		if (!(IEEE80211_TXPOWER_MIN <= txpower->i_val &&
834			txpower->i_val <= IEEE80211_TXPOWER_MAX)) {
835			error = EINVAL;
836			break;
837		}
838		ic->ic_txpower = txpower->i_val;
839		error = ENETRESET;
840		break;
841	case SIOCG80211TXPOWER:
842		txpower = (struct ieee80211_txpower *)data;
843		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
844			error = EINVAL;
845		else
846			txpower->i_val = ic->ic_txpower;
847		break;
848	case SIOCSIFMTU:
849		ifr = (struct ifreq *)data;
850		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
851		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
852			error = EINVAL;
853		else
854			ifp->if_mtu = ifr->ifr_mtu;
855		break;
856	case SIOCS80211SCAN:
857		/* Disabled. SIOCG80211ALLNODES is enough. */
858		break;
859	case SIOCG80211NODE:
860		nr = (struct ieee80211_nodereq *)data;
861		if (ic->ic_bss &&
862		    IEEE80211_ADDR_EQ(nr->nr_macaddr, ic->ic_bss->ni_macaddr))
863			ni = ic->ic_bss;
864		else
865			ni = ieee80211_find_node(ic, nr->nr_macaddr);
866		if (ni == NULL) {
867			error = ENOENT;
868			break;
869		}
870		ieee80211_node2req(ic, ni, nr);
871		break;
872	case SIOCS80211NODE:
873		if ((error = suser(curproc)) != 0)
874			break;
875#ifndef IEEE80211_STA_ONLY
876		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
877			error = EINVAL;
878			break;
879		}
880#endif
881		nr = (struct ieee80211_nodereq *)data;
882
883		ni = ieee80211_find_node(ic, nr->nr_macaddr);
884		if (ni == NULL)
885			ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
886		if (ni == NULL) {
887			error = ENOENT;
888			break;
889		}
890
891		if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
892			ieee80211_req2node(ic, nr, ni);
893		break;
894#ifndef IEEE80211_STA_ONLY
895	case SIOCS80211DELNODE:
896		if ((error = suser(curproc)) != 0)
897			break;
898		nr = (struct ieee80211_nodereq *)data;
899		ni = ieee80211_find_node(ic, nr->nr_macaddr);
900		if (ni == NULL)
901			error = ENOENT;
902		else if (ni == ic->ic_bss)
903			error = EPERM;
904		else {
905			if (ni->ni_state == IEEE80211_STA_COLLECT)
906				break;
907
908			/* Disassociate station. */
909			if (ni->ni_state == IEEE80211_STA_ASSOC)
910				IEEE80211_SEND_MGMT(ic, ni,
911				    IEEE80211_FC0_SUBTYPE_DISASSOC,
912				    IEEE80211_REASON_ASSOC_LEAVE);
913
914			/* Deauth station. */
915			if (ni->ni_state >= IEEE80211_STA_AUTH)
916				IEEE80211_SEND_MGMT(ic, ni,
917				    IEEE80211_FC0_SUBTYPE_DEAUTH,
918				    IEEE80211_REASON_AUTH_LEAVE);
919
920			ieee80211_node_leave(ic, ni);
921		}
922		break;
923#endif
924	case SIOCG80211ALLNODES:
925		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
926		    (IFF_UP | IFF_RUNNING)) {
927			error = ENETDOWN;
928			break;
929		}
930
931		na = (struct ieee80211_nodereq_all *)data;
932		na->na_nodes = i = 0;
933		ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
934		while (ni && na->na_size >=
935		    i + sizeof(struct ieee80211_nodereq)) {
936			ieee80211_node2req(ic, ni, &nrbuf);
937			error = copyout(&nrbuf, (caddr_t)na->na_node + i,
938			    sizeof(struct ieee80211_nodereq));
939			if (error)
940				break;
941			i += sizeof(struct ieee80211_nodereq);
942			na->na_nodes++;
943			ni = RBT_NEXT(ieee80211_tree, ni);
944		}
945		if (suser(curproc) == 0)
946			ieee80211_begin_bgscan(ifp);
947		break;
948	case SIOCG80211FLAGS:
949		flags = ic->ic_userflags;
950#ifndef IEEE80211_STA_ONLY
951		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
952#endif
953			flags &= ~IEEE80211_F_HOSTAPMASK;
954		ifr->ifr_flags = flags;
955		break;
956	case SIOCS80211FLAGS:
957		if ((error = suser(curproc)) != 0)
958			break;
959		flags = ifr->ifr_flags;
960		if (
961#ifndef IEEE80211_STA_ONLY
962		    ic->ic_opmode != IEEE80211_M_HOSTAP &&
963#endif
964		    (flags & IEEE80211_F_HOSTAPMASK)) {
965			error = EINVAL;
966			break;
967		}
968		ic->ic_userflags = flags;
969		error = ENETRESET;
970		break;
971	case SIOCADDMULTI:
972	case SIOCDELMULTI:
973		error = (cmd == SIOCADDMULTI) ?
974		    ether_addmulti(ifr, &ic->ic_ac) :
975		    ether_delmulti(ifr, &ic->ic_ac);
976		if (error == ENETRESET)
977			error = 0;
978		break;
979	default:
980		error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
981	}
982
983	return error;
984}
985