2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
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.
32 * $FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.13 2004/03/30 22:57:57 sam Exp $
33 * $DragonFly: src/sys/netproto/802_11/Attic/ieee80211_ioctl.c,v 1.1 2004/07/26 16:30:17 joerg Exp $
37 * IEEE 802.11 ioctl support (FreeBSD-specific)
43 #include <sys/endian.h>
44 #include <sys/param.h>
45 #include <sys/kernel.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/systm.h>
50 #include <sys/thread.h>
53 #include <net/if_arp.h>
54 #include <net/if_media.h>
55 #include <net/ethernet.h>
58 #include <netinet/in.h>
59 #include <netinet/if_ether.h>
63 #include <netproto/ipx/ipx.h>
64 #include <netproto/ipx/ipx_if.h>
67 #include <netproto/802_11/ieee80211_var.h>
68 #include <netproto/802_11/ieee80211_ioctl.h>
70 #include <netproto/802_11/if_wavelan_ieee.h>
74 * Wireless LAN specific configuration interface, which is compatible
79 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
81 struct ieee80211com *ic = (void *)ifp;
83 struct ifreq *ifr = (struct ifreq *)data;
85 struct wi_ltv_keys *keys;
87 struct ieee80211_node *ni;
88 struct ieee80211_rateset *rs;
89 struct wi_sigcache wsc;
90 struct wi_scan_p2_hdr *p2;
91 struct wi_scan_res *res;
93 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
97 switch (wreq.wi_type) {
99 /* nothing appropriate */
101 case WI_RID_NODENAME:
102 strcpy((char *)&wreq.wi_val[1], hostname);
103 wreq.wi_val[0] = htole16(strlen(hostname));
104 wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
106 case WI_RID_CURRENT_SSID:
107 if (ic->ic_state != IEEE80211_S_RUN) {
112 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
113 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
114 ic->ic_bss->ni_esslen);
115 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
117 case WI_RID_OWN_SSID:
118 case WI_RID_DESIRED_SSID:
119 wreq.wi_val[0] = htole16(ic->ic_des_esslen);
120 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
121 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
123 case WI_RID_CURRENT_BSSID:
124 if (ic->ic_state == IEEE80211_S_RUN)
125 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
127 memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
128 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
130 case WI_RID_CHANNEL_LIST:
131 memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
133 * Since channel 0 is not available for DS, channel 1
134 * is assigned to LSB on WaveLAN.
136 if (ic->ic_phytype == IEEE80211_T_DS)
140 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
141 if (isset(ic->ic_chan_active, i)) {
142 setbit((uint8_t *)wreq.wi_val, j);
143 wreq.wi_len = j / 16 + 1;
146 case WI_RID_OWN_CHNL:
147 wreq.wi_val[0] = htole16(
148 ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
151 case WI_RID_CURRENT_CHAN:
152 wreq.wi_val[0] = htole16(
153 ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
156 case WI_RID_COMMS_QUALITY:
157 wreq.wi_val[0] = 0; /* quality */
159 htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
160 wreq.wi_val[2] = 0; /* noise */
164 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
167 case WI_RID_PORTTYPE:
168 wreq.wi_val[0] = htole16(ic->ic_opmode);
171 case WI_RID_MAC_NODE:
172 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
173 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
176 if (ic->ic_fixed_rate == -1)
177 wreq.wi_val[0] = 0; /* auto */
179 wreq.wi_val[0] = htole16(
180 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
181 IEEE80211_RATE_VAL) / 2);
184 case WI_RID_CUR_TX_RATE:
185 wreq.wi_val[0] = htole16(
186 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
187 IEEE80211_RATE_VAL) / 2);
190 case WI_RID_RTS_THRESH:
191 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
194 case WI_RID_CREATE_IBSS:
196 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
199 case WI_RID_MICROWAVE_OVEN:
200 wreq.wi_val[0] = 0; /* no ... not supported */
203 case WI_RID_ROAMING_MODE:
204 wreq.wi_val[0] = htole16(1); /* enabled ... not supported */
207 case WI_RID_SYSTEM_SCALE:
208 wreq.wi_val[0] = htole16(1); /* low density ... not supp */
211 case WI_RID_PM_ENABLED:
213 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
216 case WI_RID_MAX_SLEEP:
217 wreq.wi_val[0] = htole16(ic->ic_lintval);
220 case WI_RID_CUR_BEACON_INT:
221 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
224 case WI_RID_WEP_AVAIL:
226 htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
229 case WI_RID_CNFAUTHMODE:
230 wreq.wi_val[0] = htole16(1); /* TODO: open system only */
233 case WI_RID_ENCRYPTION:
235 htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
238 case WI_RID_TX_CRYPT_KEY:
239 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
242 case WI_RID_DEFLT_CRYPT_KEYS:
243 keys = (struct wi_ltv_keys *)&wreq;
244 /* do not show keys to non-root user */
245 error = suser_cred(cr, NULL_CRED_OKAY);
247 memset(keys, 0, sizeof(*keys));
251 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
252 keys->wi_keys[i].wi_keylen =
253 htole16(ic->ic_nw_keys[i].wk_len);
254 memcpy(keys->wi_keys[i].wi_keydat,
255 ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
257 wreq.wi_len = sizeof(*keys) / 2;
259 case WI_RID_MAX_DATALEN:
260 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */
263 case WI_RID_IFACE_STATS:
264 /* XXX: should be implemented in lower drivers */
266 case WI_RID_READ_APS:
267 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
269 * Don't return results until active scan completes.
271 if (ic->ic_state == IEEE80211_S_SCAN &&
272 (ic->ic_flags & IEEE80211_F_ASCAN)) {
278 ap = (void *)((char *)wreq.wi_val + sizeof(i));
279 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
280 if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
282 memset(ap, 0, sizeof(*ap));
283 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
284 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
285 ap->namelen = ic->ic_des_esslen;
286 if (ic->ic_des_esslen)
287 memcpy(ap->name, ic->ic_des_essid,
290 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
291 ap->namelen = ni->ni_esslen;
293 memcpy(ap->name, ni->ni_essid,
296 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
297 ap->signal = (*ic->ic_node_getrssi)(ic, ni);
298 ap->capinfo = ni->ni_capinfo;
299 ap->interval = ni->ni_intval;
301 for (j = 0; j < rs->rs_nrates; j++) {
302 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
303 ap->rate = (rs->rs_rates[j] &
304 IEEE80211_RATE_VAL) * 5; /* XXX */
310 memcpy(wreq.wi_val, &i, sizeof(i));
311 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
314 wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */
315 wreq.wi_len = sizeof(uint16_t) / 2;
317 case WI_RID_SCAN_RES: /* compatibility interface */
318 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
319 ic->ic_state == IEEE80211_S_SCAN &&
320 (ic->ic_flags & IEEE80211_F_ASCAN)) {
324 /* NB: we use the Prism2 format so we can return rate info */
325 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
326 res = (void *)&p2[1];
328 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
329 if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
331 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
333 res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
334 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
335 res->wi_interval = ni->ni_intval;
336 res->wi_capinfo = ni->ni_capinfo;
337 res->wi_ssid_len = ni->ni_esslen;
338 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
339 /* NB: assumes wi_srates holds <= ni->ni_rates */
340 memcpy(res->wi_srates, ni->ni_rates.rs_rates,
341 sizeof(res->wi_srates));
342 if (ni->ni_rates.rs_nrates < 10)
343 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
344 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
350 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
352 case WI_RID_READ_CACHE:
354 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
355 if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
357 IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
358 memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
359 wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
362 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
366 wreq.wi_len = sizeof(wsc) * i / 2;
368 case WI_RID_SCAN_APS:
377 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
383 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
385 #define IEEERATE(_ic,_m,_i) \
386 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
387 int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
388 for (i = 0; i < nrates; i++)
389 if (IEEERATE(ic, mode, i) == rate)
396 * Prepare to do a user-initiated scan for AP's. If no
397 * current/default channel is setup or the current channel
398 * is invalid then pick the first available channel from
399 * the active list as the place to start the scan.
402 ieee80211_setupscan(struct ieee80211com *ic)
404 u_char *chanlist = ic->ic_chan_active;
407 if (ic->ic_ibss_chan == NULL ||
408 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
409 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
410 if (isset(chanlist, i)) {
411 ic->ic_ibss_chan = &ic->ic_channels[i];
414 return EINVAL; /* no active channels */
418 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
419 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
420 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
422 * XXX don't permit a scan to be started unless we
423 * know the device is ready. For the moment this means
424 * the device is marked up as this is the required to
425 * initialize the hardware. It would be better to permit
426 * scanning prior to being up but that'll require some
427 * changes to the infrastructure.
429 return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
433 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
435 struct ieee80211com *ic = (void *)ifp;
436 int i, j, len, error, rate;
437 struct ifreq *ifr = (struct ifreq *)data;
438 struct wi_ltv_keys *keys;
440 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
442 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
445 len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
446 switch (wreq.wi_type) {
447 case WI_RID_SERIALNO:
448 case WI_RID_NODENAME:
450 case WI_RID_CURRENT_SSID:
452 case WI_RID_OWN_SSID:
453 case WI_RID_DESIRED_SSID:
454 if (le16toh(wreq.wi_val[0]) * 2 > len ||
455 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
459 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
460 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
461 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
464 case WI_RID_CURRENT_BSSID:
466 case WI_RID_OWN_CHNL:
469 i = le16toh(wreq.wi_val[0]);
471 i > IEEE80211_CHAN_MAX ||
472 isclr(ic->ic_chan_active, i))
474 ic->ic_ibss_chan = &ic->ic_channels[i];
475 if (ic->ic_flags & IEEE80211_F_SIBSS)
478 case WI_RID_CURRENT_CHAN:
480 case WI_RID_COMMS_QUALITY:
485 if (ifp->if_flags & IFF_PROMISC) {
486 if (wreq.wi_val[0] == 0) {
487 ifp->if_flags &= ~IFF_PROMISC;
491 if (wreq.wi_val[0] != 0) {
492 ifp->if_flags |= IFF_PROMISC;
497 case WI_RID_PORTTYPE:
500 switch (le16toh(wreq.wi_val[0])) {
501 case IEEE80211_M_STA:
503 case IEEE80211_M_IBSS:
504 if (!(ic->ic_caps & IEEE80211_C_IBSS))
507 case IEEE80211_M_AHDEMO:
508 if (ic->ic_phytype != IEEE80211_T_DS ||
509 !(ic->ic_caps & IEEE80211_C_AHDEMO))
512 case IEEE80211_M_HOSTAP:
513 if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
519 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
520 ic->ic_opmode = le16toh(wreq.wi_val[0]);
525 case WI_RID_MAC_NODE:
526 if (len != IEEE80211_ADDR_LEN)
528 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
529 /* if_init will copy lladdr into ic_myaddr */
536 if (wreq.wi_val[0] == 0) {
538 ic->ic_fixed_rate = -1;
541 rate = 2 * le16toh(wreq.wi_val[0]);
542 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
544 * In autoselect mode search for the rate. We take
545 * the first instance which may not be right, but we
546 * are limited by the interface. Note that we also
547 * lock the mode to insure the rate is meaningful
550 for (j = IEEE80211_MODE_11A;
551 j < IEEE80211_MODE_MAX; j++) {
552 if ((ic->ic_modecaps & (1<<j)) == 0)
554 i = findrate(ic, j, rate);
562 i = findrate(ic, ic->ic_curmode, rate);
568 ic->ic_fixed_rate = i;
571 case WI_RID_CUR_TX_RATE:
573 case WI_RID_RTS_THRESH:
576 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
577 return EINVAL; /* TODO: RTS */
579 case WI_RID_CREATE_IBSS:
582 if (wreq.wi_val[0] != 0) {
583 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
585 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
586 ic->ic_flags |= IEEE80211_F_IBSSON;
587 if (ic->ic_opmode == IEEE80211_M_IBSS &&
588 ic->ic_state == IEEE80211_S_SCAN)
592 if (ic->ic_flags & IEEE80211_F_IBSSON) {
593 ic->ic_flags &= ~IEEE80211_F_IBSSON;
594 if (ic->ic_flags & IEEE80211_F_SIBSS) {
595 ic->ic_flags &= ~IEEE80211_F_SIBSS;
601 case WI_RID_MICROWAVE_OVEN:
604 if (wreq.wi_val[0] != 0)
605 return EINVAL; /* not supported */
607 case WI_RID_ROAMING_MODE:
610 if (le16toh(wreq.wi_val[0]) != 1)
611 return EINVAL; /* not supported */
613 case WI_RID_SYSTEM_SCALE:
616 if (le16toh(wreq.wi_val[0]) != 1)
617 return EINVAL; /* not supported */
619 case WI_RID_PM_ENABLED:
622 if (wreq.wi_val[0] != 0) {
623 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
625 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
626 ic->ic_flags |= IEEE80211_F_PMGTON;
630 if (ic->ic_flags & IEEE80211_F_PMGTON) {
631 ic->ic_flags &= ~IEEE80211_F_PMGTON;
636 case WI_RID_MAX_SLEEP:
639 ic->ic_lintval = le16toh(wreq.wi_val[0]);
640 if (ic->ic_flags & IEEE80211_F_PMGTON)
643 case WI_RID_CUR_BEACON_INT:
645 case WI_RID_WEP_AVAIL:
647 case WI_RID_CNFAUTHMODE:
650 if (le16toh(wreq.wi_val[0]) != 1)
651 return EINVAL; /* TODO: shared key auth */
653 case WI_RID_ENCRYPTION:
656 if (wreq.wi_val[0] != 0) {
657 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
659 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
660 ic->ic_flags |= IEEE80211_F_WEPON;
664 if (ic->ic_flags & IEEE80211_F_WEPON) {
665 ic->ic_flags &= ~IEEE80211_F_WEPON;
670 case WI_RID_TX_CRYPT_KEY:
673 i = le16toh(wreq.wi_val[0]);
674 if (i >= IEEE80211_WEP_NKID)
676 ic->ic_wep_txkey = i;
678 case WI_RID_DEFLT_CRYPT_KEYS:
679 if (len != sizeof(struct wi_ltv_keys))
681 keys = (struct wi_ltv_keys *)&wreq;
682 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
683 len = le16toh(keys->wi_keys[i].wi_keylen);
684 if (len != 0 && len < IEEE80211_WEP_KEYLEN)
686 if (len > sizeof(ic->ic_nw_keys[i].wk_key))
689 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
690 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
691 len = le16toh(keys->wi_keys[i].wi_keylen);
692 ic->ic_nw_keys[i].wk_len = len;
693 memcpy(ic->ic_nw_keys[i].wk_key,
694 keys->wi_keys[i].wi_keydat, len);
698 case WI_RID_MAX_DATALEN:
701 len = le16toh(wreq.wi_val[0]);
702 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
704 if (len != IEEE80211_MAX_LEN)
705 return EINVAL; /* TODO: fragment */
706 ic->ic_fragthreshold = len;
709 case WI_RID_IFACE_STATS:
712 case WI_RID_SCAN_REQ: /* XXX wicontrol */
713 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
715 error = ieee80211_setupscan(ic);
717 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
719 case WI_RID_SCAN_APS:
720 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
722 len--; /* XXX: tx rate? */
724 case WI_RID_CHANNEL_LIST:
725 memset(chanlist, 0, sizeof(chanlist));
727 * Since channel 0 is not available for DS, channel 1
728 * is assigned to LSB on WaveLAN.
730 if (ic->ic_phytype == IEEE80211_T_DS)
734 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
737 if (isclr((uint8_t *)wreq.wi_val, j))
739 if (isclr(ic->ic_chan_active, i)) {
740 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
742 if (isclr(ic->ic_chan_avail, i))
747 memcpy(ic->ic_chan_active, chanlist,
748 sizeof(ic->ic_chan_active));
749 error = ieee80211_setupscan(ic);
750 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
751 /* NB: ignore error from ieee80211_setupscan */
753 } else if (error == 0)
754 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
764 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
766 struct ieee80211com *ic = (void *)ifp;
769 struct ieee80211req *ireq;
771 uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
772 char tmpssid[IEEE80211_NWID_LEN];
773 struct ieee80211_channel *chan;
774 struct ifaddr *ifa; /* XXX */
779 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
783 ireq = (struct ieee80211req *) data;
784 switch (ireq->i_type) {
785 case IEEE80211_IOC_SSID:
786 switch (ic->ic_state) {
787 case IEEE80211_S_INIT:
788 case IEEE80211_S_SCAN:
789 ireq->i_len = ic->ic_des_esslen;
790 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
793 ireq->i_len = ic->ic_bss->ni_esslen;
794 memcpy(tmpssid, ic->ic_bss->ni_essid,
798 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
800 case IEEE80211_IOC_NUMSSIDS:
803 case IEEE80211_IOC_WEP:
804 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
805 ireq->i_val = IEEE80211_WEP_NOSUP;
807 if (ic->ic_flags & IEEE80211_F_WEPON) {
816 case IEEE80211_IOC_WEPKEY:
817 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
821 kid = (u_int) ireq->i_val;
822 if (kid >= IEEE80211_WEP_NKID) {
826 len = (u_int) ic->ic_nw_keys[kid].wk_len;
827 /* NB: only root can read WEP keys */
828 if (suser_cred(cr, NULL_CRED_OKAY) == 0) {
829 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
834 error = copyout(tmpkey, ireq->i_data, len);
836 case IEEE80211_IOC_NUMWEPKEYS:
837 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
840 ireq->i_val = IEEE80211_WEP_NKID;
842 case IEEE80211_IOC_WEPTXKEY:
843 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
846 ireq->i_val = ic->ic_wep_txkey;
848 case IEEE80211_IOC_AUTHMODE:
849 ireq->i_val = IEEE80211_AUTH_OPEN;
851 case IEEE80211_IOC_CHANNEL:
852 switch (ic->ic_state) {
853 case IEEE80211_S_INIT:
854 case IEEE80211_S_SCAN:
855 if (ic->ic_opmode == IEEE80211_M_STA)
856 chan = ic->ic_des_chan;
858 chan = ic->ic_ibss_chan;
861 chan = ic->ic_bss->ni_chan;
864 ireq->i_val = ieee80211_chan2ieee(ic, chan);
866 case IEEE80211_IOC_POWERSAVE:
867 if (ic->ic_flags & IEEE80211_F_PMGTON)
868 ireq->i_val = IEEE80211_POWERSAVE_ON;
870 ireq->i_val = IEEE80211_POWERSAVE_OFF;
872 case IEEE80211_IOC_POWERSAVESLEEP:
873 ireq->i_val = ic->ic_lintval;
875 case IEEE80211_IOC_RTSTHRESHOLD:
876 ireq->i_val = ic->ic_rtsthreshold;
878 case IEEE80211_IOC_PROTMODE:
879 ireq->i_val = ic->ic_protmode;
881 case IEEE80211_IOC_TXPOWER:
882 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
885 ireq->i_val = ic->ic_txpower;
893 error = suser_cred(cr, NULL_CRED_OKAY);
896 ireq = (struct ieee80211req *) data;
897 switch (ireq->i_type) {
898 case IEEE80211_IOC_SSID:
899 if (ireq->i_val != 0 ||
900 ireq->i_len > IEEE80211_NWID_LEN) {
904 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
907 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
908 ic->ic_des_esslen = ireq->i_len;
909 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
912 case IEEE80211_IOC_WEP:
914 * These cards only support one mode so
915 * we just turn wep on if what ever is
916 * passed in is not OFF.
918 if (ireq->i_val == IEEE80211_WEP_OFF) {
919 ic->ic_flags &= ~IEEE80211_F_WEPON;
921 ic->ic_flags |= IEEE80211_F_WEPON;
925 case IEEE80211_IOC_WEPKEY:
926 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
930 kid = (u_int) ireq->i_val;
931 if (kid >= IEEE80211_WEP_NKID) {
935 if (ireq->i_len > sizeof(tmpkey)) {
939 memset(tmpkey, 0, sizeof(tmpkey));
940 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
943 memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
945 ic->ic_nw_keys[kid].wk_len = ireq->i_len;
948 case IEEE80211_IOC_WEPTXKEY:
949 kid = (u_int) ireq->i_val;
950 if (kid >= IEEE80211_WEP_NKID) {
954 ic->ic_wep_txkey = kid;
958 case IEEE80211_IOC_AUTHMODE:
959 sc->wi_authmode = ireq->i_val;
962 case IEEE80211_IOC_CHANNEL:
963 /* XXX 0xffff overflows 16-bit signed */
964 if (ireq->i_val == 0 ||
965 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
966 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
967 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
968 isclr(ic->ic_chan_active, ireq->i_val)) {
972 ic->ic_ibss_chan = ic->ic_des_chan =
973 &ic->ic_channels[ireq->i_val];
974 switch (ic->ic_state) {
975 case IEEE80211_S_INIT:
976 case IEEE80211_S_SCAN:
980 if (ic->ic_opmode == IEEE80211_M_STA) {
981 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
982 ic->ic_bss->ni_chan != ic->ic_des_chan)
985 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
991 case IEEE80211_IOC_POWERSAVE:
992 switch (ireq->i_val) {
993 case IEEE80211_POWERSAVE_OFF:
994 if (ic->ic_flags & IEEE80211_F_PMGTON) {
995 ic->ic_flags &= ~IEEE80211_F_PMGTON;
999 case IEEE80211_POWERSAVE_ON:
1000 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1002 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
1003 ic->ic_flags |= IEEE80211_F_PMGTON;
1012 case IEEE80211_IOC_POWERSAVESLEEP:
1013 if (ireq->i_val < 0) {
1017 ic->ic_lintval = ireq->i_val;
1020 case IEEE80211_IOC_RTSTHRESHOLD:
1021 if (!(IEEE80211_RTS_MIN < ireq->i_val &&
1022 ireq->i_val < IEEE80211_RTS_MAX)) {
1026 ic->ic_rtsthreshold = ireq->i_val;
1029 case IEEE80211_IOC_PROTMODE:
1030 if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
1034 ic->ic_protmode = ireq->i_val;
1035 /* NB: if not operating in 11g this can wait */
1036 if (ic->ic_curmode == IEEE80211_MODE_11G)
1039 case IEEE80211_IOC_TXPOWER:
1040 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
1044 if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
1045 ireq->i_val < IEEE80211_TXPOWER_MAX)) {
1049 ic->ic_txpower = ireq->i_val;
1057 case SIOCGIFGENERIC:
1058 error = ieee80211_cfgget(ifp, cmd, data, cr);
1060 case SIOCSIFGENERIC:
1061 error = suser_cred(cr, NULL_CRED_OKAY);
1064 error = ieee80211_cfgset(ifp, cmd, data);
1066 case SIOCG80211STATS:
1067 ifr = (struct ifreq *)data;
1068 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
1071 ifr = (struct ifreq *)data;
1072 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
1073 ifr->ifr_mtu <= IEEE80211_MTU_MAX))
1076 ifp->if_mtu = ifr->ifr_mtu;
1080 * XXX Handle this directly so we can supress if_init calls.
1081 * XXX This should be done in ether_ioctl but for the moment
1082 * XXX there are too many other parts of the system that
1083 * XXX set IFF_UP and so supress if_init being called when
1086 ifa = (struct ifaddr *) data;
1087 switch (ifa->ifa_addr->sa_family) {
1090 if ((ifp->if_flags & IFF_UP) == 0) {
1091 ifp->if_flags |= IFF_UP;
1092 ifp->if_init(ifp->if_softc);
1094 arp_ifinit(ifp, ifa);
1099 * XXX - This code is probably wrong,
1100 * but has been copied many times.
1103 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
1104 struct arpcom *ac = (struct arpcom *)ifp;
1106 if (ipx_nullhost(*ina))
1107 ina->x_host = *(union ipx_host *) ac->ac_enaddr;
1109 bcopy((caddr_t) ina->x_host.c_host,
1110 (caddr_t) ac->ac_enaddr,
1111 sizeof(ac->ac_enaddr));
1116 if ((ifp->if_flags & IFF_UP) == 0) {
1117 ifp->if_flags |= IFF_UP;
1118 ifp->if_init(ifp->if_softc);
1124 error = ether_ioctl(ifp, cmd, data);