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