Deleted Added
sdiff udiff text old ( 127648 ) new ( 138568 )
full compact
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

--- 14 unchanged lines hidden (view full) ---

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: head/sys/net80211/ieee80211_ioctl.c 127648 2004-03-30 22:57:57Z sam $");
35
36/*
37 * IEEE 802.11 ioctl support (FreeBSD-specific)
38 */
39
40#include "opt_inet.h"
41#include "opt_ipx.h"
42

--- 19 unchanged lines hidden (view full) ---

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
76int
77ieee80211_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 */

--- 50 unchanged lines hidden (view full) ---

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:

--- 28 unchanged lines hidden (view full) ---

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] =

--- 4 unchanged lines hidden (view full) ---

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 }

--- 15 unchanged lines hidden (view full) ---

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 */
399static int
400ieee80211_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 */
413found:
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
430int
431ieee80211_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)

--- 23 unchanged lines hidden (view full) ---

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)

--- 29 unchanged lines hidden (view full) ---

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 */

--- 31 unchanged lines hidden (view full) ---

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 */

--- 15 unchanged lines hidden (view full) ---

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
761int
762ieee80211_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 &&

--- 56 unchanged lines hidden ---