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