xref: /freebsd/sys/net80211/ieee80211_ioctl.c (revision d37ea99837e6ad50837fd9fe1771ddf1c3ba6002)
1 /*-
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * Alternatively, this software may be distributed under the terms of the
18  * GNU General Public License ("GPL") version 2 as published by the Free
19  * Software Foundation.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 /*
37  * IEEE 802.11 ioctl support (FreeBSD-specific)
38  */
39 
40 #include "opt_inet.h"
41 #include "opt_ipx.h"
42 
43 #include <sys/endian.h>
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/systm.h>
49 
50 #include <net/if.h>
51 #include <net/if_arp.h>
52 #include <net/if_media.h>
53 #include <net/ethernet.h>
54 
55 #ifdef INET
56 #include <netinet/in.h>
57 #include <netinet/if_ether.h>
58 #endif
59 
60 #ifdef IPX
61 #include <netipx/ipx.h>
62 #include <netipx/ipx_if.h>
63 #endif
64 
65 #include <net80211/ieee80211_var.h>
66 #include <net80211/ieee80211_ioctl.h>
67 
68 #include <dev/wi/if_wavelan_ieee.h>
69 
70 /*
71  * XXX
72  * Wireless LAN specific configuration interface, which is compatible
73  * with wicontrol(8).
74  */
75 
76 int
77 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
78 {
79 	struct ieee80211com *ic = (void *)ifp;
80 	int i, j, error;
81 	struct ifreq *ifr = (struct ifreq *)data;
82 	struct wi_req wreq;
83 	struct wi_ltv_keys *keys;
84 	struct wi_apinfo *ap;
85 	struct ieee80211_node *ni;
86 	struct ieee80211_rateset *rs;
87 	struct wi_sigcache wsc;
88 	struct wi_scan_p2_hdr *p2;
89 	struct wi_scan_res *res;
90 
91 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
92 	if (error)
93 		return error;
94 	wreq.wi_len = 0;
95 	switch (wreq.wi_type) {
96 	case WI_RID_SERIALNO:
97 		/* nothing appropriate */
98 		break;
99 	case WI_RID_NODENAME:
100 		strcpy((char *)&wreq.wi_val[1], hostname);
101 		wreq.wi_val[0] = htole16(strlen(hostname));
102 		wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
103 		break;
104 	case WI_RID_CURRENT_SSID:
105 		if (ic->ic_state != IEEE80211_S_RUN) {
106 			wreq.wi_val[0] = 0;
107 			wreq.wi_len = 1;
108 			break;
109 		}
110 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
111 		memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
112 		    ic->ic_bss->ni_esslen);
113 		wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
114 		break;
115 	case WI_RID_OWN_SSID:
116 	case WI_RID_DESIRED_SSID:
117 		wreq.wi_val[0] = htole16(ic->ic_des_esslen);
118 		memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
119 		wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
120 		break;
121 	case WI_RID_CURRENT_BSSID:
122 		if (ic->ic_state == IEEE80211_S_RUN)
123 			IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
124 		else
125 			memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
126 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
127 		break;
128 	case WI_RID_CHANNEL_LIST:
129 		memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
130 		/*
131 		 * Since channel 0 is not available for DS, channel 1
132 		 * is assigned to LSB on WaveLAN.
133 		 */
134 		if (ic->ic_phytype == IEEE80211_T_DS)
135 			i = 1;
136 		else
137 			i = 0;
138 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
139 			if (isset(ic->ic_chan_active, i)) {
140 				setbit((u_int8_t *)wreq.wi_val, j);
141 				wreq.wi_len = j / 16 + 1;
142 			}
143 		break;
144 	case WI_RID_OWN_CHNL:
145 		wreq.wi_val[0] = htole16(
146 			ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
147 		wreq.wi_len = 1;
148 		break;
149 	case WI_RID_CURRENT_CHAN:
150 		wreq.wi_val[0] = htole16(
151 			ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
152 		wreq.wi_len = 1;
153 		break;
154 	case WI_RID_COMMS_QUALITY:
155 		wreq.wi_val[0] = 0;				/* quality */
156 		wreq.wi_val[1] =
157 			htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
158 		wreq.wi_val[2] = 0;				/* noise */
159 		wreq.wi_len = 3;
160 		break;
161 	case WI_RID_PROMISC:
162 		wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
163 		wreq.wi_len = 1;
164 		break;
165 	case WI_RID_PORTTYPE:
166 		wreq.wi_val[0] = htole16(ic->ic_opmode);
167 		wreq.wi_len = 1;
168 		break;
169 	case WI_RID_MAC_NODE:
170 		IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
171 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
172 		break;
173 	case WI_RID_TX_RATE:
174 		if (ic->ic_fixed_rate == -1)
175 			wreq.wi_val[0] = 0;	/* auto */
176 		else
177 			wreq.wi_val[0] = htole16(
178 			    (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
179 			    IEEE80211_RATE_VAL) / 2);
180 		wreq.wi_len = 1;
181 		break;
182 	case WI_RID_CUR_TX_RATE:
183 		wreq.wi_val[0] = htole16(
184 		    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
185 		    IEEE80211_RATE_VAL) / 2);
186 		wreq.wi_len = 1;
187 		break;
188 	case WI_RID_RTS_THRESH:
189 		wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
190 		wreq.wi_len = 1;
191 		break;
192 	case WI_RID_CREATE_IBSS:
193 		wreq.wi_val[0] =
194 		    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
195 		wreq.wi_len = 1;
196 		break;
197 	case WI_RID_MICROWAVE_OVEN:
198 		wreq.wi_val[0] = 0;	/* no ... not supported */
199 		wreq.wi_len = 1;
200 		break;
201 	case WI_RID_ROAMING_MODE:
202 		wreq.wi_val[0] = htole16(1);	/* enabled ... not supported */
203 		wreq.wi_len = 1;
204 		break;
205 	case WI_RID_SYSTEM_SCALE:
206 		wreq.wi_val[0] = htole16(1);	/* low density ... not supp */
207 		wreq.wi_len = 1;
208 		break;
209 	case WI_RID_PM_ENABLED:
210 		wreq.wi_val[0] =
211 		    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
212 		wreq.wi_len = 1;
213 		break;
214 	case WI_RID_MAX_SLEEP:
215 		wreq.wi_val[0] = htole16(ic->ic_lintval);
216 		wreq.wi_len = 1;
217 		break;
218 	case WI_RID_CUR_BEACON_INT:
219 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
220 		wreq.wi_len = 1;
221 		break;
222 	case WI_RID_WEP_AVAIL:
223 		wreq.wi_val[0] =
224 		    htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
225 		wreq.wi_len = 1;
226 		break;
227 	case WI_RID_CNFAUTHMODE:
228 		wreq.wi_val[0] = htole16(1);	/* TODO: open system only */
229 		wreq.wi_len = 1;
230 		break;
231 	case WI_RID_ENCRYPTION:
232 		wreq.wi_val[0] =
233 		    htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
234 		wreq.wi_len = 1;
235 		break;
236 	case WI_RID_TX_CRYPT_KEY:
237 		wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
238 		wreq.wi_len = 1;
239 		break;
240 	case WI_RID_DEFLT_CRYPT_KEYS:
241 		keys = (struct wi_ltv_keys *)&wreq;
242 		/* do not show keys to non-root user */
243 		error = suser(curthread);
244 		if (error) {
245 			memset(keys, 0, sizeof(*keys));
246 			error = 0;
247 			break;
248 		}
249 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
250 			keys->wi_keys[i].wi_keylen =
251 			    htole16(ic->ic_nw_keys[i].wk_len);
252 			memcpy(keys->wi_keys[i].wi_keydat,
253 			    ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
254 		}
255 		wreq.wi_len = sizeof(*keys) / 2;
256 		break;
257 	case WI_RID_MAX_DATALEN:
258 		wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);	/* TODO: frag */
259 		wreq.wi_len = 1;
260 		break;
261 	case WI_RID_IFACE_STATS:
262 		/* XXX: should be implemented in lower drivers */
263 		break;
264 	case WI_RID_READ_APS:
265 		if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
266 			/*
267 			 * Don't return results until active scan completes.
268 			 */
269 			if (ic->ic_state == IEEE80211_S_SCAN &&
270 			    (ic->ic_flags & IEEE80211_F_ASCAN)) {
271 				error = EINPROGRESS;
272 				break;
273 			}
274 		}
275 		i = 0;
276 		ap = (void *)((char *)wreq.wi_val + sizeof(i));
277 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
278 			if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
279 				break;
280 			memset(ap, 0, sizeof(*ap));
281 			if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
282 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
283 				ap->namelen = ic->ic_des_esslen;
284 				if (ic->ic_des_esslen)
285 					memcpy(ap->name, ic->ic_des_essid,
286 					    ic->ic_des_esslen);
287 			} else {
288 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
289 				ap->namelen = ni->ni_esslen;
290 				if (ni->ni_esslen)
291 					memcpy(ap->name, ni->ni_essid,
292 					    ni->ni_esslen);
293 			}
294 			ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
295 			ap->signal = (*ic->ic_node_getrssi)(ic, ni);
296 			ap->capinfo = ni->ni_capinfo;
297 			ap->interval = ni->ni_intval;
298 			rs = &ni->ni_rates;
299 			for (j = 0; j < rs->rs_nrates; j++) {
300 				if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
301 					ap->rate = (rs->rs_rates[j] &
302 					    IEEE80211_RATE_VAL) * 5; /* XXX */
303 				}
304 			}
305 			i++;
306 			ap++;
307 		}
308 		memcpy(wreq.wi_val, &i, sizeof(i));
309 		wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
310 		break;
311 	case WI_RID_PRISM2:
312 		wreq.wi_val[0] = 1;	/* XXX lie so SCAN_RES can give rates */
313 		wreq.wi_len = sizeof(u_int16_t) / 2;
314 		break;
315 	case WI_RID_SCAN_RES:			/* compatibility interface */
316 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
317 		    ic->ic_state == IEEE80211_S_SCAN &&
318 		    (ic->ic_flags & IEEE80211_F_ASCAN)) {
319 			error = EINPROGRESS;
320 			break;
321 		}
322 		/* NB: we use the Prism2 format so we can return rate info */
323 		p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
324 		res = (void *)&p2[1];
325 		i = 0;
326 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
327 			if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
328 				break;
329 			res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
330 			res->wi_noise = 0;
331 			res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
332 			IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
333 			res->wi_interval = ni->ni_intval;
334 			res->wi_capinfo = ni->ni_capinfo;
335 			res->wi_ssid_len = ni->ni_esslen;
336 			memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
337 			/* NB: assumes wi_srates holds <= ni->ni_rates */
338 			memcpy(res->wi_srates, ni->ni_rates.rs_rates,
339 				sizeof(res->wi_srates));
340 			if (ni->ni_rates.rs_nrates < 10)
341 				res->wi_srates[ni->ni_rates.rs_nrates] = 0;
342 			res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
343 			res->wi_rsvd = 0;
344 			res++, i++;
345 		}
346 		p2->wi_rsvd = 0;
347 		p2->wi_reason = i;
348 		wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
349 		break;
350 	case WI_RID_READ_CACHE:
351 		i = 0;
352 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
353 			if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
354 				break;
355 			IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
356 			memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
357 			wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
358 			wsc.noise = 0;
359 			wsc.quality = 0;
360 			memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
361 			    &wsc, sizeof(wsc));
362 			i++;
363 		}
364 		wreq.wi_len = sizeof(wsc) * i / 2;
365 		break;
366 	case WI_RID_SCAN_APS:
367 		error = EINVAL;
368 		break;
369 	default:
370 		error = EINVAL;
371 		break;
372 	}
373 	if (error == 0) {
374 		wreq.wi_len++;
375 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
376 	}
377 	return error;
378 }
379 
380 static int
381 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
382 {
383 #define	IEEERATE(_ic,_m,_i) \
384 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
385 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
386 	for (i = 0; i < nrates; i++)
387 		if (IEEERATE(ic, mode, i) == rate)
388 			return i;
389 	return -1;
390 #undef IEEERATE
391 }
392 
393 /*
394  * Prepare to do a user-initiated scan for AP's.  If no
395  * current/default channel is setup or the current channel
396  * is invalid then pick the first available channel from
397  * the active list as the place to start the scan.
398  */
399 static int
400 ieee80211_setupscan(struct ieee80211com *ic)
401 {
402 	u_char *chanlist = ic->ic_chan_active;
403 	int i;
404 
405 	if (ic->ic_ibss_chan == NULL ||
406 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
407 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
408 			if (isset(chanlist, i)) {
409 				ic->ic_ibss_chan = &ic->ic_channels[i];
410 				goto found;
411 			}
412 		return EINVAL;			/* no active channels */
413 found:
414 		;
415 	}
416 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
417 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
418 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
419 	/*
420 	 * XXX don't permit a scan to be started unless we
421 	 * know the device is ready.  For the moment this means
422 	 * the device is marked up as this is the required to
423 	 * initialize the hardware.  It would be better to permit
424 	 * scanning prior to being up but that'll require some
425 	 * changes to the infrastructure.
426 	 */
427 	return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
428 }
429 
430 int
431 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
432 {
433 	struct ieee80211com *ic = (void *)ifp;
434 	int i, j, len, error, rate;
435 	struct ifreq *ifr = (struct ifreq *)data;
436 	struct wi_ltv_keys *keys;
437 	struct wi_req wreq;
438 	u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
439 
440 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
441 	if (error)
442 		return error;
443 	len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
444 	switch (wreq.wi_type) {
445 	case WI_RID_SERIALNO:
446 	case WI_RID_NODENAME:
447 		return EPERM;
448 	case WI_RID_CURRENT_SSID:
449 		return EPERM;
450 	case WI_RID_OWN_SSID:
451 	case WI_RID_DESIRED_SSID:
452 		if (le16toh(wreq.wi_val[0]) * 2 > len ||
453 		    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
454 			error = ENOSPC;
455 			break;
456 		}
457 		memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
458 		ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
459 		memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
460 		error = ENETRESET;
461 		break;
462 	case WI_RID_CURRENT_BSSID:
463 		return EPERM;
464 	case WI_RID_OWN_CHNL:
465 		if (len != 2)
466 			return EINVAL;
467 		i = le16toh(wreq.wi_val[0]);
468 		if (i < 0 ||
469 		    i > IEEE80211_CHAN_MAX ||
470 		    isclr(ic->ic_chan_active, i))
471 			return EINVAL;
472 		ic->ic_ibss_chan = &ic->ic_channels[i];
473 		if (ic->ic_flags & IEEE80211_F_SIBSS)
474 			error = ENETRESET;
475 		break;
476 	case WI_RID_CURRENT_CHAN:
477 		return EPERM;
478 	case WI_RID_COMMS_QUALITY:
479 		return EPERM;
480 	case WI_RID_PROMISC:
481 		if (len != 2)
482 			return EINVAL;
483 		if (ifp->if_flags & IFF_PROMISC) {
484 			if (wreq.wi_val[0] == 0) {
485 				ifp->if_flags &= ~IFF_PROMISC;
486 				error = ENETRESET;
487 			}
488 		} else {
489 			if (wreq.wi_val[0] != 0) {
490 				ifp->if_flags |= IFF_PROMISC;
491 				error = ENETRESET;
492 			}
493 		}
494 		break;
495 	case WI_RID_PORTTYPE:
496 		if (len != 2)
497 			return EINVAL;
498 		switch (le16toh(wreq.wi_val[0])) {
499 		case IEEE80211_M_STA:
500 			break;
501 		case IEEE80211_M_IBSS:
502 			if (!(ic->ic_caps & IEEE80211_C_IBSS))
503 				return EINVAL;
504 			break;
505 		case IEEE80211_M_AHDEMO:
506 			if (ic->ic_phytype != IEEE80211_T_DS ||
507 			    !(ic->ic_caps & IEEE80211_C_AHDEMO))
508 				return EINVAL;
509 			break;
510 		case IEEE80211_M_HOSTAP:
511 			if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
512 				return EINVAL;
513 			break;
514 		default:
515 			return EINVAL;
516 		}
517 		if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
518 			ic->ic_opmode = le16toh(wreq.wi_val[0]);
519 			error = ENETRESET;
520 		}
521 		break;
522 #if 0
523 	case WI_RID_MAC_NODE:
524 		if (len != IEEE80211_ADDR_LEN)
525 			return EINVAL;
526 		IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
527 		/* if_init will copy lladdr into ic_myaddr */
528 		error = ENETRESET;
529 		break;
530 #endif
531 	case WI_RID_TX_RATE:
532 		if (len != 2)
533 			return EINVAL;
534 		if (wreq.wi_val[0] == 0) {
535 			/* auto */
536 			ic->ic_fixed_rate = -1;
537 			break;
538 		}
539 		rate = 2 * le16toh(wreq.wi_val[0]);
540 		if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
541 			/*
542 			 * In autoselect mode search for the rate.  We take
543 			 * the first instance which may not be right, but we
544 			 * are limited by the interface.  Note that we also
545 			 * lock the mode to insure the rate is meaningful
546 			 * when it is used.
547 			 */
548 			for (j = IEEE80211_MODE_11A;
549 			     j < IEEE80211_MODE_MAX; j++) {
550 				if ((ic->ic_modecaps & (1<<j)) == 0)
551 					continue;
552 				i = findrate(ic, j, rate);
553 				if (i != -1) {
554 					/* lock mode too */
555 					ic->ic_curmode = j;
556 					goto setrate;
557 				}
558 			}
559 		} else {
560 			i = findrate(ic, ic->ic_curmode, rate);
561 			if (i != -1)
562 				goto setrate;
563 		}
564 		return EINVAL;
565 	setrate:
566 		ic->ic_fixed_rate = i;
567 		error = ENETRESET;
568 		break;
569 	case WI_RID_CUR_TX_RATE:
570 		return EPERM;
571 	case WI_RID_RTS_THRESH:
572 		if (len != 2)
573 			return EINVAL;
574 		if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
575 			return EINVAL;		/* TODO: RTS */
576 		break;
577 	case WI_RID_CREATE_IBSS:
578 		if (len != 2)
579 			return EINVAL;
580 		if (wreq.wi_val[0] != 0) {
581 			if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
582 				return EINVAL;
583 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
584 				ic->ic_flags |= IEEE80211_F_IBSSON;
585 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
586 				    ic->ic_state == IEEE80211_S_SCAN)
587 					error = ENETRESET;
588 			}
589 		} else {
590 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
591 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
592 				if (ic->ic_flags & IEEE80211_F_SIBSS) {
593 					ic->ic_flags &= ~IEEE80211_F_SIBSS;
594 					error = ENETRESET;
595 				}
596 			}
597 		}
598 		break;
599 	case WI_RID_MICROWAVE_OVEN:
600 		if (len != 2)
601 			return EINVAL;
602 		if (wreq.wi_val[0] != 0)
603 			return EINVAL;		/* not supported */
604 		break;
605 	case WI_RID_ROAMING_MODE:
606 		if (len != 2)
607 			return EINVAL;
608 		if (le16toh(wreq.wi_val[0]) != 1)
609 			return EINVAL;		/* not supported */
610 		break;
611 	case WI_RID_SYSTEM_SCALE:
612 		if (len != 2)
613 			return EINVAL;
614 		if (le16toh(wreq.wi_val[0]) != 1)
615 			return EINVAL;		/* not supported */
616 		break;
617 	case WI_RID_PM_ENABLED:
618 		if (len != 2)
619 			return EINVAL;
620 		if (wreq.wi_val[0] != 0) {
621 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
622 				return EINVAL;
623 			if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
624 				ic->ic_flags |= IEEE80211_F_PMGTON;
625 				error = ENETRESET;
626 			}
627 		} else {
628 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
629 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
630 				error = ENETRESET;
631 			}
632 		}
633 		break;
634 	case WI_RID_MAX_SLEEP:
635 		if (len != 2)
636 			return EINVAL;
637 		ic->ic_lintval = le16toh(wreq.wi_val[0]);
638 		if (ic->ic_flags & IEEE80211_F_PMGTON)
639 			error = ENETRESET;
640 		break;
641 	case WI_RID_CUR_BEACON_INT:
642 		return EPERM;
643 	case WI_RID_WEP_AVAIL:
644 		return EPERM;
645 	case WI_RID_CNFAUTHMODE:
646 		if (len != 2)
647 			return EINVAL;
648 		if (le16toh(wreq.wi_val[0]) != 1)
649 			return EINVAL;		/* TODO: shared key auth */
650 		break;
651 	case WI_RID_ENCRYPTION:
652 		if (len != 2)
653 			return EINVAL;
654 		if (wreq.wi_val[0] != 0) {
655 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
656 				return EINVAL;
657 			if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
658 				ic->ic_flags |= IEEE80211_F_WEPON;
659 				error = ENETRESET;
660 			}
661 		} else {
662 			if (ic->ic_flags & IEEE80211_F_WEPON) {
663 				ic->ic_flags &= ~IEEE80211_F_WEPON;
664 				error = ENETRESET;
665 			}
666 		}
667 		break;
668 	case WI_RID_TX_CRYPT_KEY:
669 		if (len != 2)
670 			return EINVAL;
671 		i = le16toh(wreq.wi_val[0]);
672 		if (i >= IEEE80211_WEP_NKID)
673 			return EINVAL;
674 		ic->ic_wep_txkey = i;
675 		break;
676 	case WI_RID_DEFLT_CRYPT_KEYS:
677 		if (len != sizeof(struct wi_ltv_keys))
678 			return EINVAL;
679 		keys = (struct wi_ltv_keys *)&wreq;
680 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
681 			len = le16toh(keys->wi_keys[i].wi_keylen);
682 			if (len != 0 && len < IEEE80211_WEP_KEYLEN)
683 				return EINVAL;
684 			if (len > sizeof(ic->ic_nw_keys[i].wk_key))
685 				return EINVAL;
686 		}
687 		memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
688 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
689 			len = le16toh(keys->wi_keys[i].wi_keylen);
690 			ic->ic_nw_keys[i].wk_len = len;
691 			memcpy(ic->ic_nw_keys[i].wk_key,
692 			    keys->wi_keys[i].wi_keydat, len);
693 		}
694 		error = ENETRESET;
695 		break;
696 	case WI_RID_MAX_DATALEN:
697 		if (len != 2)
698 			return EINVAL;
699 		len = le16toh(wreq.wi_val[0]);
700 		if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
701 			return EINVAL;
702 		if (len != IEEE80211_MAX_LEN)
703 			return EINVAL;		/* TODO: fragment */
704 		ic->ic_fragthreshold = len;
705 		error = ENETRESET;
706 		break;
707 	case WI_RID_IFACE_STATS:
708 		error = EPERM;
709 		break;
710 	case WI_RID_SCAN_REQ:			/* XXX wicontrol */
711 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
712 			break;
713 		error = ieee80211_setupscan(ic);
714 		if (error == 0)
715 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
716 		break;
717 	case WI_RID_SCAN_APS:
718 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
719 			break;
720 		len--;			/* XXX: tx rate? */
721 		/* FALLTHRU */
722 	case WI_RID_CHANNEL_LIST:
723 		memset(chanlist, 0, sizeof(chanlist));
724 		/*
725 		 * Since channel 0 is not available for DS, channel 1
726 		 * is assigned to LSB on WaveLAN.
727 		 */
728 		if (ic->ic_phytype == IEEE80211_T_DS)
729 			i = 1;
730 		else
731 			i = 0;
732 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
733 			if ((j / 8) >= len)
734 				break;
735 			if (isclr((u_int8_t *)wreq.wi_val, j))
736 				continue;
737 			if (isclr(ic->ic_chan_active, i)) {
738 				if (wreq.wi_type != WI_RID_CHANNEL_LIST)
739 					continue;
740 				if (isclr(ic->ic_chan_avail, i))
741 					return EPERM;
742 			}
743 			setbit(chanlist, i);
744 		}
745 		memcpy(ic->ic_chan_active, chanlist,
746 		    sizeof(ic->ic_chan_active));
747 		error = ieee80211_setupscan(ic);
748 		if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
749 			/* NB: ignore error from ieee80211_setupscan */
750 			error = ENETRESET;
751 		} else if (error == 0)
752 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
753 		break;
754 	default:
755 		error = EINVAL;
756 		break;
757 	}
758 	return error;
759 }
760 
761 int
762 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
763 {
764 	struct ieee80211com *ic = (void *)ifp;
765 	int error = 0;
766 	u_int kid, len;
767 	struct ieee80211req *ireq;
768 	struct ifreq *ifr;
769 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
770 	char tmpssid[IEEE80211_NWID_LEN];
771 	struct ieee80211_channel *chan;
772 	struct ifaddr *ifa;			/* XXX */
773 
774 	switch (cmd) {
775 	case SIOCSIFMEDIA:
776 	case SIOCGIFMEDIA:
777 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
778 				&ic->ic_media, cmd);
779 		break;
780 	case SIOCG80211:
781 		ireq = (struct ieee80211req *) data;
782 		switch (ireq->i_type) {
783 		case IEEE80211_IOC_SSID:
784 			switch (ic->ic_state) {
785 			case IEEE80211_S_INIT:
786 			case IEEE80211_S_SCAN:
787 				ireq->i_len = ic->ic_des_esslen;
788 				memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
789 				break;
790 			default:
791 				ireq->i_len = ic->ic_bss->ni_esslen;
792 				memcpy(tmpssid, ic->ic_bss->ni_essid,
793 					ireq->i_len);
794 				break;
795 			}
796 			error = copyout(tmpssid, ireq->i_data, ireq->i_len);
797 			break;
798 		case IEEE80211_IOC_NUMSSIDS:
799 			ireq->i_val = 1;
800 			break;
801 		case IEEE80211_IOC_WEP:
802 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
803 				ireq->i_val = IEEE80211_WEP_NOSUP;
804 			} else {
805 				if (ic->ic_flags & IEEE80211_F_WEPON) {
806 					ireq->i_val =
807 					    IEEE80211_WEP_MIXED;
808 				} else {
809 					ireq->i_val =
810 					    IEEE80211_WEP_OFF;
811 				}
812 			}
813 			break;
814 		case IEEE80211_IOC_WEPKEY:
815 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
816 				error = EINVAL;
817 				break;
818 			}
819 			kid = (u_int) ireq->i_val;
820 			if (kid >= IEEE80211_WEP_NKID) {
821 				error = EINVAL;
822 				break;
823 			}
824 			len = (u_int) ic->ic_nw_keys[kid].wk_len;
825 			/* NB: only root can read WEP keys */
826 			if (suser(curthread) == 0) {
827 				bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
828 			} else {
829 				bzero(tmpkey, len);
830 			}
831 			ireq->i_len = len;
832 			error = copyout(tmpkey, ireq->i_data, len);
833 			break;
834 		case IEEE80211_IOC_NUMWEPKEYS:
835 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
836 				error = EINVAL;
837 			else
838 				ireq->i_val = IEEE80211_WEP_NKID;
839 			break;
840 		case IEEE80211_IOC_WEPTXKEY:
841 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
842 				error = EINVAL;
843 			else
844 				ireq->i_val = ic->ic_wep_txkey;
845 			break;
846 		case IEEE80211_IOC_AUTHMODE:
847 			ireq->i_val = IEEE80211_AUTH_OPEN;
848 			break;
849 		case IEEE80211_IOC_CHANNEL:
850 			switch (ic->ic_state) {
851 			case IEEE80211_S_INIT:
852 			case IEEE80211_S_SCAN:
853 				if (ic->ic_opmode == IEEE80211_M_STA)
854 					chan = ic->ic_des_chan;
855 				else
856 					chan = ic->ic_ibss_chan;
857 				break;
858 			default:
859 				chan = ic->ic_bss->ni_chan;
860 				break;
861 			}
862 			ireq->i_val = ieee80211_chan2ieee(ic, chan);
863 			break;
864 		case IEEE80211_IOC_POWERSAVE:
865 			if (ic->ic_flags & IEEE80211_F_PMGTON)
866 				ireq->i_val = IEEE80211_POWERSAVE_ON;
867 			else
868 				ireq->i_val = IEEE80211_POWERSAVE_OFF;
869 			break;
870 		case IEEE80211_IOC_POWERSAVESLEEP:
871 			ireq->i_val = ic->ic_lintval;
872 			break;
873 		case IEEE80211_IOC_RTSTHRESHOLD:
874 			ireq->i_val = ic->ic_rtsthreshold;
875 			break;
876 		case IEEE80211_IOC_PROTMODE:
877 			ireq->i_val = ic->ic_protmode;
878 			break;
879 		case IEEE80211_IOC_TXPOWER:
880 			if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
881 				error = EINVAL;
882 			else
883 				ireq->i_val = ic->ic_txpower;
884 			break;
885 		default:
886 			error = EINVAL;
887 			break;
888 		}
889 		break;
890 	case SIOCS80211:
891 		error = suser(curthread);
892 		if (error)
893 			break;
894 		ireq = (struct ieee80211req *) data;
895 		switch (ireq->i_type) {
896 		case IEEE80211_IOC_SSID:
897 			if (ireq->i_val != 0 ||
898 			    ireq->i_len > IEEE80211_NWID_LEN) {
899 				error = EINVAL;
900 				break;
901 			}
902 			error = copyin(ireq->i_data, tmpssid, ireq->i_len);
903 			if (error)
904 				break;
905 			memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
906 			ic->ic_des_esslen = ireq->i_len;
907 			memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
908 			error = ENETRESET;
909 			break;
910 		case IEEE80211_IOC_WEP:
911 			/*
912 			 * These cards only support one mode so
913 			 * we just turn wep on if what ever is
914 			 * passed in is not OFF.
915 			 */
916 			if (ireq->i_val == IEEE80211_WEP_OFF) {
917 				ic->ic_flags &= ~IEEE80211_F_WEPON;
918 			} else {
919 				ic->ic_flags |= IEEE80211_F_WEPON;
920 			}
921 			error = ENETRESET;
922 			break;
923 		case IEEE80211_IOC_WEPKEY:
924 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
925 				error = EINVAL;
926 				break;
927 			}
928 			kid = (u_int) ireq->i_val;
929 			if (kid >= IEEE80211_WEP_NKID) {
930 				error = EINVAL;
931 				break;
932 			}
933 			if (ireq->i_len > sizeof(tmpkey)) {
934 				error = EINVAL;
935 				break;
936 			}
937 			memset(tmpkey, 0, sizeof(tmpkey));
938 			error = copyin(ireq->i_data, tmpkey, ireq->i_len);
939 			if (error)
940 				break;
941 			memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
942 				sizeof(tmpkey));
943 			ic->ic_nw_keys[kid].wk_len = ireq->i_len;
944 			error = ENETRESET;
945 			break;
946 		case IEEE80211_IOC_WEPTXKEY:
947 			kid = (u_int) ireq->i_val;
948 			if (kid >= IEEE80211_WEP_NKID) {
949 				error = EINVAL;
950 				break;
951 			}
952 			ic->ic_wep_txkey = kid;
953 			error = ENETRESET;
954 			break;
955 #if 0
956 		case IEEE80211_IOC_AUTHMODE:
957 			sc->wi_authmode = ireq->i_val;
958 			break;
959 #endif
960 		case IEEE80211_IOC_CHANNEL:
961 			/* XXX 0xffff overflows 16-bit signed */
962 			if (ireq->i_val == 0 ||
963 			    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
964 				ic->ic_des_chan = IEEE80211_CHAN_ANYC;
965 			else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
966 			    isclr(ic->ic_chan_active, ireq->i_val)) {
967 				error = EINVAL;
968 				break;
969 			} else
970 				ic->ic_ibss_chan = ic->ic_des_chan =
971 					&ic->ic_channels[ireq->i_val];
972 			switch (ic->ic_state) {
973 			case IEEE80211_S_INIT:
974 			case IEEE80211_S_SCAN:
975 				error = ENETRESET;
976 				break;
977 			default:
978 				if (ic->ic_opmode == IEEE80211_M_STA) {
979 					if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
980 					    ic->ic_bss->ni_chan != ic->ic_des_chan)
981 						error = ENETRESET;
982 				} else {
983 					if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
984 						error = ENETRESET;
985 				}
986 				break;
987 			}
988 			break;
989 		case IEEE80211_IOC_POWERSAVE:
990 			switch (ireq->i_val) {
991 			case IEEE80211_POWERSAVE_OFF:
992 				if (ic->ic_flags & IEEE80211_F_PMGTON) {
993 					ic->ic_flags &= ~IEEE80211_F_PMGTON;
994 					error = ENETRESET;
995 				}
996 				break;
997 			case IEEE80211_POWERSAVE_ON:
998 				if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
999 					error = EINVAL;
1000 				else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
1001 					ic->ic_flags |= IEEE80211_F_PMGTON;
1002 					error = ENETRESET;
1003 				}
1004 				break;
1005 			default:
1006 				error = EINVAL;
1007 				break;
1008 			}
1009 			break;
1010 		case IEEE80211_IOC_POWERSAVESLEEP:
1011 			if (ireq->i_val < 0) {
1012 				error = EINVAL;
1013 				break;
1014 			}
1015 			ic->ic_lintval = ireq->i_val;
1016 			error = ENETRESET;
1017 			break;
1018 		case IEEE80211_IOC_RTSTHRESHOLD:
1019 			if (!(IEEE80211_RTS_MIN < ireq->i_val &&
1020 			      ireq->i_val < IEEE80211_RTS_MAX)) {
1021 				error = EINVAL;
1022 				break;
1023 			}
1024 			ic->ic_rtsthreshold = ireq->i_val;
1025 			error = ENETRESET;
1026 			break;
1027 		case IEEE80211_IOC_PROTMODE:
1028 			if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
1029 				error = EINVAL;
1030 				break;
1031 			}
1032 			ic->ic_protmode = ireq->i_val;
1033 			/* NB: if not operating in 11g this can wait */
1034 			if (ic->ic_curmode == IEEE80211_MODE_11G)
1035 				error = ENETRESET;
1036 			break;
1037 		case IEEE80211_IOC_TXPOWER:
1038 			if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
1039 				error = EINVAL;
1040 				break;
1041 			}
1042 			if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
1043 			      ireq->i_val < IEEE80211_TXPOWER_MAX)) {
1044 				error = EINVAL;
1045 				break;
1046 			}
1047 			ic->ic_txpower = ireq->i_val;
1048 			error = ENETRESET;
1049 			break;
1050 		default:
1051 			error = EINVAL;
1052 			break;
1053 		}
1054 		break;
1055 	case SIOCGIFGENERIC:
1056 		error = ieee80211_cfgget(ifp, cmd, data);
1057 		break;
1058 	case SIOCSIFGENERIC:
1059 		error = suser(curthread);
1060 		if (error)
1061 			break;
1062 		error = ieee80211_cfgset(ifp, cmd, data);
1063 		break;
1064 	case SIOCG80211STATS:
1065 		ifr = (struct ifreq *)data;
1066 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
1067 		break;
1068 	case SIOCSIFMTU:
1069 		ifr = (struct ifreq *)data;
1070 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
1071 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
1072 			error = EINVAL;
1073 		else
1074 			ifp->if_mtu = ifr->ifr_mtu;
1075 		break;
1076 	case SIOCSIFADDR:
1077 		/*
1078 		 * XXX Handle this directly so we can supress if_init calls.
1079 		 * XXX This should be done in ether_ioctl but for the moment
1080 		 * XXX there are too many other parts of the system that
1081 		 * XXX set IFF_UP and so supress if_init being called when
1082 		 * XXX it should be.
1083 		 */
1084 		ifa = (struct ifaddr *) data;
1085 		switch (ifa->ifa_addr->sa_family) {
1086 #ifdef INET
1087 		case AF_INET:
1088 			if ((ifp->if_flags & IFF_UP) == 0) {
1089 				ifp->if_flags |= IFF_UP;
1090 				ifp->if_init(ifp->if_softc);
1091 			}
1092 			arp_ifinit(ifp, ifa);
1093 			break;
1094 #endif
1095 #ifdef IPX
1096 		/*
1097 		 * XXX - This code is probably wrong,
1098 		 *	 but has been copied many times.
1099 		 */
1100 		case AF_IPX: {
1101 			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
1102 			struct arpcom *ac = (struct arpcom *)ifp;
1103 
1104 			if (ipx_nullhost(*ina))
1105 				ina->x_host = *(union ipx_host *) ac->ac_enaddr;
1106 			else
1107 				bcopy((caddr_t) ina->x_host.c_host,
1108 				      (caddr_t) ac->ac_enaddr,
1109 				      sizeof(ac->ac_enaddr));
1110 			/* fall thru... */
1111 		}
1112 #endif
1113 		default:
1114 			if ((ifp->if_flags & IFF_UP) == 0) {
1115 				ifp->if_flags |= IFF_UP;
1116 				ifp->if_init(ifp->if_softc);
1117 			}
1118 			break;
1119 		}
1120 		break;
1121 	default:
1122 		error = ether_ioctl(ifp, cmd, data);
1123 		break;
1124 	}
1125 	return error;
1126 }
1127