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