xref: /openbsd-src/sys/net80211/ieee80211_ioctl.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: ieee80211_ioctl.c,v 1.35 2014/07/10 14:32:28 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/proc.h>
43 #include <sys/tree.h>
44 
45 #include <net/if.h>
46 #include <net/if_arp.h>
47 #include <net/if_media.h>
48 
49 #ifdef INET
50 #include <netinet/in.h>
51 #include <netinet/if_ether.h>
52 #endif
53 
54 #include <net80211/ieee80211_var.h>
55 #include <net80211/ieee80211_crypto.h>
56 #include <net80211/ieee80211_ioctl.h>
57 
58 void	 ieee80211_node2req(struct ieee80211com *,
59 	    const struct ieee80211_node *, struct ieee80211_nodereq *);
60 void	 ieee80211_req2node(struct ieee80211com *,
61 	    const struct ieee80211_nodereq *, struct ieee80211_node *);
62 
63 void
64 ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
65     struct ieee80211_nodereq *nr)
66 {
67 	/* Node address and name information */
68 	IEEE80211_ADDR_COPY(nr->nr_macaddr, ni->ni_macaddr);
69 	IEEE80211_ADDR_COPY(nr->nr_bssid, ni->ni_bssid);
70 	nr->nr_nwid_len = ni->ni_esslen;
71 	bcopy(ni->ni_essid, nr->nr_nwid, IEEE80211_NWID_LEN);
72 
73 	/* Channel and rates */
74 	nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan);
75 	nr->nr_chan_flags = ni->ni_chan->ic_flags;
76 	nr->nr_nrates = ni->ni_rates.rs_nrates;
77 	bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE);
78 
79 	/* Node status information */
80 	nr->nr_rssi = (*ic->ic_node_getrssi)(ic, ni);
81 	nr->nr_max_rssi = ic->ic_max_rssi;
82 	bcopy(ni->ni_tstamp, nr->nr_tstamp, sizeof(nr->nr_tstamp));
83 	nr->nr_intval = ni->ni_intval;
84 	nr->nr_capinfo = ni->ni_capinfo;
85 	nr->nr_erp = ni->ni_erp;
86 	nr->nr_pwrsave = ni->ni_pwrsave;
87 	nr->nr_associd = ni->ni_associd;
88 	nr->nr_txseq = ni->ni_txseq;
89 	nr->nr_rxseq = ni->ni_rxseq;
90 	nr->nr_fails = ni->ni_fails;
91 	nr->nr_inact = ni->ni_inact;
92 	nr->nr_txrate = ni->ni_txrate;
93 	nr->nr_state = ni->ni_state;
94 
95 	/* RSN */
96 	nr->nr_rsnciphers = ni->ni_rsnciphers;
97 	nr->nr_rsnakms = 0;
98 	if (ni->ni_rsnakms & IEEE80211_AKM_8021X)
99 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_8021X;
100 	if (ni->ni_rsnakms & IEEE80211_AKM_PSK)
101 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_PSK;
102 	if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X)
103 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_8021X;
104 	if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK)
105 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_PSK;
106 
107 	/* Node flags */
108 	nr->nr_flags = 0;
109 	if (bcmp(nr->nr_macaddr, nr->nr_bssid, IEEE80211_ADDR_LEN) == 0)
110 		nr->nr_flags |= IEEE80211_NODEREQ_AP;
111 	if (ni == ic->ic_bss)
112 		nr->nr_flags |= IEEE80211_NODEREQ_AP_BSS;
113 }
114 
115 void
116 ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr,
117     struct ieee80211_node *ni)
118 {
119 	/* Node address and name information */
120 	IEEE80211_ADDR_COPY(ni->ni_macaddr, nr->nr_macaddr);
121 	IEEE80211_ADDR_COPY(ni->ni_bssid, nr->nr_bssid);
122 	ni->ni_esslen = nr->nr_nwid_len;
123 	bcopy(nr->nr_nwid, ni->ni_essid, IEEE80211_NWID_LEN);
124 
125 	/* Rates */
126 	ni->ni_rates.rs_nrates = nr->nr_nrates;
127 	bcopy(nr->nr_rates, ni->ni_rates.rs_rates, IEEE80211_RATE_MAXSIZE);
128 
129 	/* Node information */
130 	ni->ni_intval = nr->nr_intval;
131 	ni->ni_capinfo = nr->nr_capinfo;
132 	ni->ni_erp = nr->nr_erp;
133 	ni->ni_pwrsave = nr->nr_pwrsave;
134 	ni->ni_associd = nr->nr_associd;
135 	ni->ni_txseq = nr->nr_txseq;
136 	ni->ni_rxseq = nr->nr_rxseq;
137 	ni->ni_fails = nr->nr_fails;
138 	ni->ni_inact = nr->nr_inact;
139 	ni->ni_txrate = nr->nr_txrate;
140 	ni->ni_state = nr->nr_state;
141 }
142 
143 static int
144 ieee80211_ioctl_setnwkeys(struct ieee80211com *ic,
145     const struct ieee80211_nwkey *nwkey)
146 {
147 	struct ieee80211_key *k;
148 	int error, i;
149 
150 	if (!(ic->ic_caps & IEEE80211_C_WEP))
151 		return ENODEV;
152 
153 	if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
154 		if (!(ic->ic_flags & IEEE80211_F_WEPON))
155 			return 0;
156 		ic->ic_flags &= ~IEEE80211_F_WEPON;
157 		return ENETRESET;
158 	}
159 	if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID)
160 		return EINVAL;
161 
162 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
163 		if (nwkey->i_key[i].i_keylen == 0 ||
164 		    nwkey->i_key[i].i_keydat == NULL)
165 			continue;	/* entry not set */
166 		if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE)
167 			return EINVAL;
168 
169 		/* map wep key to ieee80211_key */
170 		k = &ic->ic_nw_keys[i];
171 		if (k->k_cipher != IEEE80211_CIPHER_NONE)
172 			(*ic->ic_delete_key)(ic, NULL, k);
173 		memset(k, 0, sizeof(*k));
174 		if (nwkey->i_key[i].i_keylen <= 5)
175 			k->k_cipher = IEEE80211_CIPHER_WEP40;
176 		else
177 			k->k_cipher = IEEE80211_CIPHER_WEP104;
178 		k->k_len = ieee80211_cipher_keylen(k->k_cipher);
179 		k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
180 		error = copyin(nwkey->i_key[i].i_keydat, k->k_key, k->k_len);
181 		if (error != 0)
182 			return error;
183 		if ((error = (*ic->ic_set_key)(ic, NULL, k)) != 0)
184 			return error;
185 	}
186 
187 	ic->ic_def_txkey = nwkey->i_defkid - 1;
188 	ic->ic_flags |= IEEE80211_F_WEPON;
189 
190 	return ENETRESET;
191 }
192 
193 static int
194 ieee80211_ioctl_getnwkeys(struct ieee80211com *ic,
195     struct ieee80211_nwkey *nwkey)
196 {
197 	struct ieee80211_key *k;
198 	int error, i;
199 
200 	if (ic->ic_flags & IEEE80211_F_WEPON)
201 		nwkey->i_wepon = IEEE80211_NWKEY_WEP;
202 	else
203 		nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
204 
205 	nwkey->i_defkid = ic->ic_wep_txkey + 1;
206 
207 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
208 		if (nwkey->i_key[i].i_keydat == NULL)
209 			continue;
210 		/* do not show any keys to non-root user */
211 		if ((error = suser(curproc, 0)) != 0)
212 			return error;
213 		k = &ic->ic_nw_keys[i];
214 		if (k->k_cipher != IEEE80211_CIPHER_WEP40 &&
215 		    k->k_cipher != IEEE80211_CIPHER_WEP104)
216 			nwkey->i_key[i].i_keylen = 0;
217 		else
218 			nwkey->i_key[i].i_keylen = k->k_len;
219 		error = copyout(k->k_key, nwkey->i_key[i].i_keydat,
220 		    nwkey->i_key[i].i_keylen);
221 		if (error != 0)
222 			return error;
223 	}
224 	return 0;
225 }
226 
227 static int
228 ieee80211_ioctl_setwpaparms(struct ieee80211com *ic,
229     const struct ieee80211_wpaparams *wpa)
230 {
231 	if (!(ic->ic_caps & IEEE80211_C_RSN))
232 		return ENODEV;
233 
234 	if (!wpa->i_enabled) {
235 		if (!(ic->ic_flags & IEEE80211_F_RSNON))
236 			return 0;
237 		ic->ic_flags &= ~IEEE80211_F_RSNON;
238 		return ENETRESET;
239 	}
240 
241 	ic->ic_rsnprotos = 0;
242 	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1)
243 		ic->ic_rsnprotos |= IEEE80211_PROTO_WPA;
244 	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
245 		ic->ic_rsnprotos |= IEEE80211_PROTO_RSN;
246 	if (ic->ic_rsnprotos == 0)	/* set to default (WPA+RSN) */
247 		ic->ic_rsnprotos = IEEE80211_PROTO_WPA | IEEE80211_PROTO_RSN;
248 
249 	ic->ic_rsnakms = 0;
250 	if (wpa->i_akms & IEEE80211_WPA_AKM_PSK)
251 		ic->ic_rsnakms |= IEEE80211_AKM_PSK;
252 	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_PSK)
253 		ic->ic_rsnakms |= IEEE80211_AKM_SHA256_PSK;
254 	if (wpa->i_akms & IEEE80211_WPA_AKM_8021X)
255 		ic->ic_rsnakms |= IEEE80211_AKM_8021X;
256 	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X)
257 		ic->ic_rsnakms |= IEEE80211_AKM_SHA256_8021X;
258 	if (ic->ic_rsnakms == 0)	/* set to default (PSK) */
259 		ic->ic_rsnakms = IEEE80211_AKM_PSK;
260 
261 	if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40)
262 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP40;
263 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP)
264 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
265 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP)
266 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
267 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104)
268 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP104;
269 	else  {	/* set to default */
270 		if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
271 			ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
272 		else
273 			ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
274 	}
275 
276 	ic->ic_rsnciphers = 0;
277 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP)
278 		ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP;
279 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP)
280 		ic->ic_rsnciphers |= IEEE80211_CIPHER_CCMP;
281 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP)
282 		ic->ic_rsnciphers = IEEE80211_CIPHER_USEGROUP;
283 	if (ic->ic_rsnciphers == 0)	/* set to default (TKIP+CCMP) */
284 		ic->ic_rsnciphers = IEEE80211_CIPHER_TKIP |
285 		    IEEE80211_CIPHER_CCMP;
286 
287 	ic->ic_flags |= IEEE80211_F_RSNON;
288 
289 	return ENETRESET;
290 }
291 
292 static int
293 ieee80211_ioctl_getwpaparms(struct ieee80211com *ic,
294     struct ieee80211_wpaparams *wpa)
295 {
296 	wpa->i_enabled = (ic->ic_flags & IEEE80211_F_RSNON) ? 1 : 0;
297 
298 	wpa->i_protos = 0;
299 	if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
300 		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1;
301 	if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)
302 		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2;
303 
304 	wpa->i_akms = 0;
305 	if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
306 		wpa->i_akms |= IEEE80211_WPA_AKM_PSK;
307 	if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK)
308 		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK;
309 	if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
310 		wpa->i_akms |= IEEE80211_WPA_AKM_8021X;
311 	if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X)
312 		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X;
313 
314 	if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP40)
315 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40;
316 	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_TKIP)
317 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP;
318 	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP)
319 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP;
320 	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP104)
321 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104;
322 	else
323 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE;
324 
325 	wpa->i_ciphers = 0;
326 	if (ic->ic_rsnciphers & IEEE80211_CIPHER_TKIP)
327 		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
328 	if (ic->ic_rsnciphers & IEEE80211_CIPHER_CCMP)
329 		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
330 	if (ic->ic_rsnciphers & IEEE80211_CIPHER_USEGROUP)
331 		wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP;
332 
333 	return 0;
334 }
335 
336 int
337 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
338 {
339 	struct ieee80211com *ic = (void *)ifp;
340 	struct ifreq *ifr = (struct ifreq *)data;
341 	int i, error = 0;
342 	struct ieee80211_nwid nwid;
343 	struct ieee80211_wpapsk *psk;
344 	struct ieee80211_wmmparams *wmm;
345 	struct ieee80211_keyavail *ka;
346 	struct ieee80211_keyrun *kr;
347 	struct ieee80211_power *power;
348 	struct ieee80211_bssid *bssid;
349 	struct ieee80211chanreq *chanreq;
350 	struct ieee80211_channel *chan;
351 	struct ieee80211_txpower *txpower;
352 	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
353 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
354 	};
355 	struct ieee80211_nodereq *nr, nrbuf;
356 	struct ieee80211_nodereq_all *na;
357 	struct ieee80211_node *ni;
358 	u_int32_t flags;
359 
360 	switch (cmd) {
361 	case SIOCSIFMEDIA:
362 	case SIOCGIFMEDIA:
363 		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
364 		break;
365 	case SIOCS80211NWID:
366 		if ((error = suser(curproc, 0)) != 0)
367 			break;
368 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
369 			break;
370 		if (nwid.i_len > IEEE80211_NWID_LEN) {
371 			error = EINVAL;
372 			break;
373 		}
374 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
375 		ic->ic_des_esslen = nwid.i_len;
376 		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
377 		error = ENETRESET;
378 		break;
379 	case SIOCG80211NWID:
380 		memset(&nwid, 0, sizeof(nwid));
381 		switch (ic->ic_state) {
382 		case IEEE80211_S_INIT:
383 		case IEEE80211_S_SCAN:
384 			nwid.i_len = ic->ic_des_esslen;
385 			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
386 			break;
387 		default:
388 			nwid.i_len = ic->ic_bss->ni_esslen;
389 			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
390 			break;
391 		}
392 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
393 		break;
394 	case SIOCS80211NWKEY:
395 		if ((error = suser(curproc, 0)) != 0)
396 			break;
397 		error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
398 		break;
399 	case SIOCG80211NWKEY:
400 		error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
401 		break;
402 	case SIOCS80211WMMPARMS:
403 		if ((error = suser(curproc, 0)) != 0)
404 			break;
405 		if (!(ic->ic_flags & IEEE80211_C_QOS)) {
406 			error = ENODEV;
407 			break;
408 		}
409 		wmm = (struct ieee80211_wmmparams *)data;
410 		if (wmm->i_enabled)
411 			ic->ic_flags |= IEEE80211_F_QOS;
412 		else
413 			ic->ic_flags &= ~IEEE80211_F_QOS;
414 		error = ENETRESET;
415 		break;
416 	case SIOCG80211WMMPARMS:
417 		wmm = (struct ieee80211_wmmparams *)data;
418 		wmm->i_enabled = (ic->ic_flags & IEEE80211_F_QOS) ? 1 : 0;
419 		break;
420 	case SIOCS80211WPAPARMS:
421 		if ((error = suser(curproc, 0)) != 0)
422 			break;
423 		error = ieee80211_ioctl_setwpaparms(ic, (void *)data);
424 		break;
425 	case SIOCG80211WPAPARMS:
426 		error = ieee80211_ioctl_getwpaparms(ic, (void *)data);
427 		break;
428 	case SIOCS80211WPAPSK:
429 		if ((error = suser(curproc, 0)) != 0)
430 			break;
431 		psk = (struct ieee80211_wpapsk *)data;
432 		if (psk->i_enabled) {
433 			ic->ic_flags |= IEEE80211_F_PSK;
434 			memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
435 		} else {
436 			ic->ic_flags &= ~IEEE80211_F_PSK;
437 			memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
438 		}
439 		error = ENETRESET;
440 		break;
441 	case SIOCG80211WPAPSK:
442 		psk = (struct ieee80211_wpapsk *)data;
443 		if (ic->ic_flags & IEEE80211_F_PSK) {
444 			psk->i_enabled = 1;
445 			/* do not show any keys to non-root user */
446 			if (suser(curproc, 0) != 0) {
447 				psk->i_enabled = 2;
448 				memset(psk->i_psk, 0, sizeof(psk->i_psk));
449 				break;	/* return ok but w/o key */
450 			}
451 			memcpy(psk->i_psk, ic->ic_psk, sizeof(psk->i_psk));
452 		} else
453 			psk->i_enabled = 0;
454 		break;
455 	case SIOCS80211KEYAVAIL:
456 		if ((error = suser(curproc, 0)) != 0)
457 			break;
458 		ka = (struct ieee80211_keyavail *)data;
459 		(void)ieee80211_pmksa_add(ic, IEEE80211_AKM_8021X,
460 		    ka->i_macaddr, ka->i_key, ka->i_lifetime);
461 		break;
462 	case SIOCS80211KEYRUN:
463 		if ((error = suser(curproc, 0)) != 0)
464 			break;
465 		kr = (struct ieee80211_keyrun *)data;
466 		error = ieee80211_keyrun(ic, kr->i_macaddr);
467 		break;
468 	case SIOCS80211POWER:
469 		if ((error = suser(curproc, 0)) != 0)
470 			break;
471 		power = (struct ieee80211_power *)data;
472 		ic->ic_lintval = power->i_maxsleep;
473 		if (power->i_enabled != 0) {
474 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
475 				error = EINVAL;
476 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
477 				ic->ic_flags |= IEEE80211_F_PMGTON;
478 				error = ENETRESET;
479 			}
480 		} else {
481 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
482 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
483 				error = ENETRESET;
484 			}
485 		}
486 		break;
487 	case SIOCG80211POWER:
488 		power = (struct ieee80211_power *)data;
489 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
490 		power->i_maxsleep = ic->ic_lintval;
491 		break;
492 	case SIOCS80211BSSID:
493 		if ((error = suser(curproc, 0)) != 0)
494 			break;
495 		bssid = (struct ieee80211_bssid *)data;
496 		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
497 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
498 		else {
499 			ic->ic_flags |= IEEE80211_F_DESBSSID;
500 			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
501 		}
502 #ifndef IEEE80211_STA_ONLY
503 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
504 			break;
505 #endif
506 		switch (ic->ic_state) {
507 		case IEEE80211_S_INIT:
508 		case IEEE80211_S_SCAN:
509 			error = ENETRESET;
510 			break;
511 		default:
512 			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
513 			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
514 			    ic->ic_bss->ni_bssid))
515 				error = ENETRESET;
516 			break;
517 		}
518 		break;
519 	case SIOCG80211BSSID:
520 		bssid = (struct ieee80211_bssid *)data;
521 		switch (ic->ic_state) {
522 		case IEEE80211_S_INIT:
523 		case IEEE80211_S_SCAN:
524 #ifndef IEEE80211_STA_ONLY
525 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
526 				IEEE80211_ADDR_COPY(bssid->i_bssid,
527 				    ic->ic_myaddr);
528 			else
529 #endif
530 			if (ic->ic_flags & IEEE80211_F_DESBSSID)
531 				IEEE80211_ADDR_COPY(bssid->i_bssid,
532 				    ic->ic_des_bssid);
533 			else
534 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
535 			break;
536 		default:
537 			IEEE80211_ADDR_COPY(bssid->i_bssid,
538 			    ic->ic_bss->ni_bssid);
539 			break;
540 		}
541 		break;
542 	case SIOCS80211CHANNEL:
543 		if ((error = suser(curproc, 0)) != 0)
544 			break;
545 		chanreq = (struct ieee80211chanreq *)data;
546 		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
547 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
548 		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
549 		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
550 			error = EINVAL;
551 			break;
552 		} else
553 			ic->ic_ibss_chan = ic->ic_des_chan =
554 			    &ic->ic_channels[chanreq->i_channel];
555 		switch (ic->ic_state) {
556 		case IEEE80211_S_INIT:
557 		case IEEE80211_S_SCAN:
558 			error = ENETRESET;
559 			break;
560 		default:
561 			if (ic->ic_opmode == IEEE80211_M_STA) {
562 				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
563 				    ic->ic_bss->ni_chan != ic->ic_des_chan)
564 					error = ENETRESET;
565 			} else {
566 				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
567 					error = ENETRESET;
568 			}
569 			break;
570 		}
571 		break;
572 	case SIOCG80211CHANNEL:
573 		chanreq = (struct ieee80211chanreq *)data;
574 		switch (ic->ic_state) {
575 		case IEEE80211_S_INIT:
576 		case IEEE80211_S_SCAN:
577 			if (ic->ic_opmode == IEEE80211_M_STA)
578 				chan = ic->ic_des_chan;
579 			else
580 				chan = ic->ic_ibss_chan;
581 			break;
582 		default:
583 			chan = ic->ic_bss->ni_chan;
584 			break;
585 		}
586 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
587 		break;
588 	case SIOCG80211ALLCHANS:
589 		error = copyout(ic->ic_channels,
590 		    ((struct ieee80211_chanreq_all *)data)->i_chans,
591 		    sizeof(ic->ic_channels));
592 		break;
593 #if 0
594 	case SIOCG80211ZSTATS:
595 #endif
596 	case SIOCG80211STATS:
597 		ifr = (struct ifreq *)data;
598 		error = copyout(&ic->ic_stats, ifr->ifr_data,
599 		    sizeof(ic->ic_stats));
600 #if 0
601 		if (cmd == SIOCG80211ZSTATS)
602 			memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
603 #endif
604 		break;
605 	case SIOCS80211TXPOWER:
606 		if ((error = suser(curproc, 0)) != 0)
607 			break;
608 		txpower = (struct ieee80211_txpower *)data;
609 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
610 			error = EINVAL;
611 			break;
612 		}
613 		if (!(IEEE80211_TXPOWER_MIN <= txpower->i_val &&
614 			txpower->i_val <= IEEE80211_TXPOWER_MAX)) {
615 			error = EINVAL;
616 			break;
617 		}
618 		ic->ic_txpower = txpower->i_val;
619 		error = ENETRESET;
620 		break;
621 	case SIOCG80211TXPOWER:
622 		txpower = (struct ieee80211_txpower *)data;
623 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
624 			error = EINVAL;
625 		else
626 			txpower->i_val = ic->ic_txpower;
627 		break;
628 	case SIOCSIFMTU:
629 		ifr = (struct ifreq *)data;
630 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
631 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
632 			error = EINVAL;
633 		else
634 			ifp->if_mtu = ifr->ifr_mtu;
635 		break;
636 	case SIOCS80211SCAN:
637 		if ((error = suser(curproc, 0)) != 0)
638 			break;
639 #ifndef IEEE80211_STA_ONLY
640 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
641 			break;
642 #endif
643 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
644 		    (IFF_UP | IFF_RUNNING)) {
645 			error = ENETDOWN;
646 			break;
647 		}
648 		if ((ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) == 0) {
649 			if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED)
650 				ic->ic_scan_lock |= IEEE80211_SCAN_RESUME;
651 			ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST;
652 			if (ic->ic_state != IEEE80211_S_SCAN)
653 				ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
654 		}
655 		/* Let the userspace process wait for completion */
656 		error = tsleep(&ic->ic_scan_lock, PCATCH, "80211scan",
657 		    hz * IEEE80211_SCAN_TIMEOUT);
658 		break;
659 	case SIOCG80211NODE:
660 		nr = (struct ieee80211_nodereq *)data;
661 		ni = ieee80211_find_node(ic, nr->nr_macaddr);
662 		if (ni == NULL) {
663 			error = ENOENT;
664 			break;
665 		}
666 		ieee80211_node2req(ic, ni, nr);
667 		break;
668 	case SIOCS80211NODE:
669 		if ((error = suser(curproc, 0)) != 0)
670 			break;
671 #ifndef IEEE80211_STA_ONLY
672 		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
673 			error = EINVAL;
674 			break;
675 		}
676 #endif
677 		nr = (struct ieee80211_nodereq *)data;
678 
679 		ni = ieee80211_find_node(ic, nr->nr_macaddr);
680 		if (ni == NULL)
681 			ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
682 		if (ni == NULL) {
683 			error = ENOENT;
684 			break;
685 		}
686 
687 		if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
688 			ieee80211_req2node(ic, nr, ni);
689 		break;
690 #ifndef IEEE80211_STA_ONLY
691 	case SIOCS80211DELNODE:
692 		if ((error = suser(curproc, 0)) != 0)
693 			break;
694 		nr = (struct ieee80211_nodereq *)data;
695 		ni = ieee80211_find_node(ic, nr->nr_macaddr);
696 		if (ni == NULL)
697 			error = ENOENT;
698 		else if (ni == ic->ic_bss)
699 			error = EPERM;
700 		else {
701 			if (ni->ni_state == IEEE80211_STA_COLLECT)
702 				break;
703 
704 			/* Disassociate station. */
705 			if (ni->ni_state == IEEE80211_STA_ASSOC)
706 				IEEE80211_SEND_MGMT(ic, ni,
707 				    IEEE80211_FC0_SUBTYPE_DISASSOC,
708 				    IEEE80211_REASON_ASSOC_LEAVE);
709 
710 			/* Deauth station. */
711 			if (ni->ni_state >= IEEE80211_STA_AUTH)
712 				IEEE80211_SEND_MGMT(ic, ni,
713 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
714 				    IEEE80211_REASON_AUTH_LEAVE);
715 
716 			ieee80211_node_leave(ic, ni);
717 		}
718 		break;
719 #endif
720 	case SIOCG80211ALLNODES:
721 		na = (struct ieee80211_nodereq_all *)data;
722 		na->na_nodes = i = 0;
723 		ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
724 		while (ni && na->na_size >=
725 		    i + sizeof(struct ieee80211_nodereq)) {
726 			ieee80211_node2req(ic, ni, &nrbuf);
727 			error = copyout(&nrbuf, (caddr_t)na->na_node + i,
728 			    sizeof(struct ieee80211_nodereq));
729 			if (error)
730 				break;
731 			i += sizeof(struct ieee80211_nodereq);
732 			na->na_nodes++;
733 			ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
734 		}
735 		break;
736 	case SIOCG80211FLAGS:
737 		flags = ic->ic_flags;
738 #ifndef IEEE80211_STA_ONLY
739 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
740 #endif
741 			flags &= ~IEEE80211_F_HOSTAPMASK;
742 		ifr->ifr_flags = flags >> IEEE80211_F_USERSHIFT;
743 		break;
744 	case SIOCS80211FLAGS:
745 		if ((error = suser(curproc, 0)) != 0)
746 			break;
747 		flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
748 		if (
749 #ifndef IEEE80211_STA_ONLY
750 		    ic->ic_opmode != IEEE80211_M_HOSTAP &&
751 #endif
752 		    (flags & IEEE80211_F_HOSTAPMASK)) {
753 			error = EINVAL;
754 			break;
755 		}
756 		ic->ic_flags = (ic->ic_flags & ~IEEE80211_F_USERMASK) | flags;
757 		error = ENETRESET;
758 		break;
759 	default:
760 		error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
761 	}
762 
763 	return error;
764 }
765