ieee80211_ioctl.c revision 117040
1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3116742Ssam * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 4116742Ssam * All rights reserved. 5116742Ssam * 6116742Ssam * Redistribution and use in source and binary forms, with or without 7116742Ssam * modification, are permitted provided that the following conditions 8116742Ssam * are met: 9116742Ssam * 1. Redistributions of source code must retain the above copyright 10116904Ssam * notice, this list of conditions and the following disclaimer. 11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright 12116904Ssam * notice, this list of conditions and the following disclaimer in the 13116904Ssam * documentation and/or other materials provided with the distribution. 14116904Ssam * 3. The name of the author may not be used to endorse or promote products 15116904Ssam * derived from this software without specific prior written permission. 16116742Ssam * 17116742Ssam * Alternatively, this software may be distributed under the terms of the 18116742Ssam * GNU General Public License ("GPL") version 2 as published by the Free 19116742Ssam * Software Foundation. 20116742Ssam * 21116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31116742Ssam */ 32116742Ssam 33116742Ssam#include <sys/cdefs.h> 34116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ioctl.c 117040 2003-06-29 20:12:17Z sam $"); 35116742Ssam 36116742Ssam/* 37116742Ssam * IEEE 802.11 ioctl support (FreeBSD-specific) 38116742Ssam */ 39116742Ssam 40116742Ssam#include <sys/endian.h> 41116742Ssam#include <sys/param.h> 42116742Ssam#include <sys/kernel.h> 43116742Ssam#include <sys/socket.h> 44116742Ssam#include <sys/sockio.h> 45116742Ssam#include <sys/systm.h> 46116742Ssam 47116742Ssam#include <net/if.h> 48116742Ssam#include <net/if_arp.h> 49116742Ssam#include <net/if_media.h> 50116742Ssam#include <net/ethernet.h> 51116742Ssam 52116742Ssam#include <net80211/ieee80211_var.h> 53116742Ssam#include <net80211/ieee80211_ioctl.h> 54116742Ssam 55116742Ssam#include <dev/wi/if_wavelan_ieee.h> 56116742Ssam 57116742Ssam/* 58116742Ssam * XXX 59116742Ssam * Wireless LAN specific configuration interface, which is compatible 60116742Ssam * with wicontrol(8). 61116742Ssam */ 62116742Ssam 63116742Ssamint 64116742Ssamieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data) 65116742Ssam{ 66116742Ssam struct ieee80211com *ic = (void *)ifp; 67116742Ssam int i, j, error; 68116742Ssam struct ifreq *ifr = (struct ifreq *)data; 69116742Ssam struct wi_req wreq; 70116742Ssam struct wi_ltv_keys *keys; 71116742Ssam struct wi_apinfo *ap; 72116742Ssam struct ieee80211_node *ni; 73116742Ssam struct ieee80211_rateset *rs; 74116742Ssam struct wi_sigcache wsc; 75116742Ssam struct wi_scan_p2_hdr *p2; 76116742Ssam struct wi_scan_res *res; 77116742Ssam 78116742Ssam error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 79116742Ssam if (error) 80116742Ssam return error; 81116742Ssam wreq.wi_len = 0; 82116742Ssam switch (wreq.wi_type) { 83116742Ssam case WI_RID_SERIALNO: 84116742Ssam /* nothing appropriate */ 85116742Ssam break; 86116742Ssam case WI_RID_NODENAME: 87116742Ssam strcpy((char *)&wreq.wi_val[1], hostname); 88116742Ssam wreq.wi_val[0] = htole16(strlen(hostname)); 89116742Ssam wreq.wi_len = (1 + strlen(hostname) + 1) / 2; 90116742Ssam break; 91116742Ssam case WI_RID_CURRENT_SSID: 92116742Ssam if (ic->ic_state != IEEE80211_S_RUN) { 93116742Ssam wreq.wi_val[0] = 0; 94116742Ssam wreq.wi_len = 1; 95116742Ssam break; 96116742Ssam } 97116742Ssam wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen); 98116742Ssam memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid, 99116742Ssam ic->ic_bss->ni_esslen); 100116742Ssam wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2; 101116742Ssam break; 102116742Ssam case WI_RID_OWN_SSID: 103116742Ssam case WI_RID_DESIRED_SSID: 104116742Ssam wreq.wi_val[0] = htole16(ic->ic_des_esslen); 105116742Ssam memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen); 106116742Ssam wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2; 107116742Ssam break; 108116742Ssam case WI_RID_CURRENT_BSSID: 109116742Ssam if (ic->ic_state == IEEE80211_S_RUN) 110116742Ssam IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid); 111116742Ssam else 112116742Ssam memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN); 113116742Ssam wreq.wi_len = IEEE80211_ADDR_LEN / 2; 114116742Ssam break; 115116742Ssam case WI_RID_CHANNEL_LIST: 116116742Ssam memset(wreq.wi_val, 0, sizeof(wreq.wi_val)); 117116742Ssam /* 118116742Ssam * Since channel 0 is not available for DS, channel 1 119116742Ssam * is assigned to LSB on WaveLAN. 120116742Ssam */ 121116742Ssam if (ic->ic_phytype == IEEE80211_T_DS) 122116742Ssam i = 1; 123116742Ssam else 124116742Ssam i = 0; 125116742Ssam for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) 126116742Ssam if (isset(ic->ic_chan_active, i)) { 127116742Ssam setbit((u_int8_t *)wreq.wi_val, j); 128116742Ssam wreq.wi_len = j / 16 + 1; 129116742Ssam } 130116742Ssam break; 131116742Ssam case WI_RID_OWN_CHNL: 132116742Ssam wreq.wi_val[0] = htole16( 133116742Ssam ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); 134116742Ssam wreq.wi_len = 1; 135116742Ssam break; 136116742Ssam case WI_RID_CURRENT_CHAN: 137116742Ssam wreq.wi_val[0] = htole16( 138116742Ssam ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)); 139116742Ssam wreq.wi_len = 1; 140116742Ssam break; 141116742Ssam case WI_RID_COMMS_QUALITY: 142116742Ssam wreq.wi_val[0] = 0; /* quality */ 143116742Ssam wreq.wi_val[1] = htole16(ic->ic_bss->ni_rssi); /* signal */ 144116742Ssam wreq.wi_val[2] = 0; /* noise */ 145116742Ssam wreq.wi_len = 3; 146116742Ssam break; 147116742Ssam case WI_RID_PROMISC: 148116742Ssam wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0); 149116742Ssam wreq.wi_len = 1; 150116742Ssam break; 151116742Ssam case WI_RID_PORTTYPE: 152116742Ssam wreq.wi_val[0] = htole16(ic->ic_opmode); 153116742Ssam wreq.wi_len = 1; 154116742Ssam break; 155116742Ssam case WI_RID_MAC_NODE: 156116742Ssam IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr); 157116742Ssam wreq.wi_len = IEEE80211_ADDR_LEN / 2; 158116742Ssam break; 159116742Ssam case WI_RID_TX_RATE: 160116742Ssam if (ic->ic_fixed_rate == -1) 161116742Ssam wreq.wi_val[0] = 0; /* auto */ 162116742Ssam else 163116742Ssam wreq.wi_val[0] = htole16( 164116742Ssam (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] & 165116742Ssam IEEE80211_RATE_VAL) / 2); 166116742Ssam wreq.wi_len = 1; 167116742Ssam break; 168116742Ssam case WI_RID_CUR_TX_RATE: 169116742Ssam wreq.wi_val[0] = htole16( 170116742Ssam (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & 171116742Ssam IEEE80211_RATE_VAL) / 2); 172116742Ssam wreq.wi_len = 1; 173116742Ssam break; 174116742Ssam case WI_RID_RTS_THRESH: 175116742Ssam wreq.wi_val[0] = htole16(ic->ic_rtsthreshold); 176116742Ssam wreq.wi_len = 1; 177116742Ssam break; 178116742Ssam case WI_RID_CREATE_IBSS: 179116742Ssam wreq.wi_val[0] = 180116742Ssam htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0); 181116742Ssam wreq.wi_len = 1; 182116742Ssam break; 183116742Ssam case WI_RID_MICROWAVE_OVEN: 184116742Ssam wreq.wi_val[0] = 0; /* no ... not supported */ 185116742Ssam wreq.wi_len = 1; 186116742Ssam break; 187116742Ssam case WI_RID_ROAMING_MODE: 188116742Ssam wreq.wi_val[0] = htole16(1); /* enabled ... not supported */ 189116742Ssam wreq.wi_len = 1; 190116742Ssam break; 191116742Ssam case WI_RID_SYSTEM_SCALE: 192116742Ssam wreq.wi_val[0] = htole16(1); /* low density ... not supp */ 193116742Ssam wreq.wi_len = 1; 194116742Ssam break; 195116742Ssam case WI_RID_PM_ENABLED: 196116742Ssam wreq.wi_val[0] = 197116742Ssam htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); 198116742Ssam wreq.wi_len = 1; 199116742Ssam break; 200116742Ssam case WI_RID_MAX_SLEEP: 201116742Ssam wreq.wi_val[0] = htole16(ic->ic_lintval); 202116742Ssam wreq.wi_len = 1; 203116742Ssam break; 204116742Ssam case WI_RID_CUR_BEACON_INT: 205116742Ssam wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval); 206116742Ssam wreq.wi_len = 1; 207116742Ssam break; 208116742Ssam case WI_RID_WEP_AVAIL: 209116742Ssam wreq.wi_val[0] = 210116742Ssam htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0); 211116742Ssam wreq.wi_len = 1; 212116742Ssam break; 213116742Ssam case WI_RID_CNFAUTHMODE: 214116742Ssam wreq.wi_val[0] = htole16(1); /* TODO: open system only */ 215116742Ssam wreq.wi_len = 1; 216116742Ssam break; 217116742Ssam case WI_RID_ENCRYPTION: 218116742Ssam wreq.wi_val[0] = 219116742Ssam htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0); 220116742Ssam wreq.wi_len = 1; 221116742Ssam break; 222116742Ssam case WI_RID_TX_CRYPT_KEY: 223116742Ssam wreq.wi_val[0] = htole16(ic->ic_wep_txkey); 224116742Ssam wreq.wi_len = 1; 225116742Ssam break; 226116742Ssam case WI_RID_DEFLT_CRYPT_KEYS: 227116742Ssam keys = (struct wi_ltv_keys *)&wreq; 228116742Ssam /* do not show keys to non-root user */ 229116742Ssam error = suser(curthread); 230116742Ssam if (error) { 231116742Ssam memset(keys, 0, sizeof(*keys)); 232116742Ssam error = 0; 233116742Ssam break; 234116742Ssam } 235116742Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) { 236116742Ssam keys->wi_keys[i].wi_keylen = 237116742Ssam htole16(ic->ic_nw_keys[i].wk_len); 238116742Ssam memcpy(keys->wi_keys[i].wi_keydat, 239116742Ssam ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len); 240116742Ssam } 241116742Ssam wreq.wi_len = sizeof(*keys) / 2; 242116742Ssam break; 243116742Ssam case WI_RID_MAX_DATALEN: 244116742Ssam wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */ 245116742Ssam wreq.wi_len = 1; 246116742Ssam break; 247116742Ssam case WI_RID_IFACE_STATS: 248116742Ssam /* XXX: should be implemented in lower drivers */ 249116742Ssam break; 250116742Ssam case WI_RID_READ_APS: 251116742Ssam if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 252116742Ssam /* 253116742Ssam * Don't return results until active scan completes. 254116742Ssam */ 255116742Ssam if (ic->ic_state == IEEE80211_S_SCAN && 256116742Ssam (ic->ic_flags & IEEE80211_F_ASCAN)) { 257116742Ssam error = EINPROGRESS; 258116742Ssam break; 259116742Ssam } 260116742Ssam } 261116742Ssam i = 0; 262116742Ssam ap = (void *)((char *)wreq.wi_val + sizeof(i)); 263116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 264116742Ssam if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1)) 265116742Ssam break; 266116742Ssam memset(ap, 0, sizeof(*ap)); 267116742Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 268116742Ssam IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr); 269116742Ssam ap->namelen = ic->ic_des_esslen; 270116742Ssam if (ic->ic_des_esslen) 271116742Ssam memcpy(ap->name, ic->ic_des_essid, 272116742Ssam ic->ic_des_esslen); 273116742Ssam } else { 274116742Ssam IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid); 275116742Ssam ap->namelen = ni->ni_esslen; 276116742Ssam if (ni->ni_esslen) 277116742Ssam memcpy(ap->name, ni->ni_essid, 278116742Ssam ni->ni_esslen); 279116742Ssam } 280116742Ssam ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan); 281116742Ssam ap->signal = ni->ni_rssi; 282116742Ssam ap->capinfo = ni->ni_capinfo; 283116742Ssam ap->interval = ni->ni_intval; 284116742Ssam rs = &ni->ni_rates; 285116742Ssam for (j = 0; j < rs->rs_nrates; j++) { 286116742Ssam if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) { 287116742Ssam ap->rate = (rs->rs_rates[j] & 288116742Ssam IEEE80211_RATE_VAL) * 5; /* XXX */ 289116742Ssam } 290116742Ssam } 291116742Ssam i++; 292116742Ssam ap++; 293116742Ssam } 294116742Ssam memcpy(wreq.wi_val, &i, sizeof(i)); 295116742Ssam wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2; 296116742Ssam break; 297116742Ssam case WI_RID_PRISM2: 298116742Ssam wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */ 299116742Ssam wreq.wi_len = sizeof(u_int16_t) / 2; 300116742Ssam break; 301116742Ssam case WI_RID_SCAN_RES: /* compatibility interface */ 302116742Ssam if (ic->ic_opmode != IEEE80211_M_HOSTAP && 303116742Ssam ic->ic_state == IEEE80211_S_SCAN) { 304116742Ssam error = EINPROGRESS; 305116742Ssam break; 306116742Ssam } 307116742Ssam /* NB: we use the Prism2 format so we can return rate info */ 308116742Ssam p2 = (struct wi_scan_p2_hdr *)wreq.wi_val; 309116742Ssam res = (void *)&p2[1]; 310116742Ssam i = 0; 311116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 312116742Ssam if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1)) 313116742Ssam break; 314116742Ssam res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan); 315116742Ssam res->wi_noise = 0; 316116742Ssam res->wi_signal = ni->ni_rssi; 317116742Ssam IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid); 318116742Ssam res->wi_interval = ni->ni_intval; 319116742Ssam res->wi_capinfo = ni->ni_capinfo; 320116742Ssam res->wi_ssid_len = ni->ni_esslen; 321116742Ssam memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN); 322116742Ssam /* NB: assumes wi_srates holds <= ni->ni_rates */ 323116742Ssam memcpy(res->wi_srates, ni->ni_rates.rs_rates, 324116742Ssam sizeof(res->wi_srates)); 325116742Ssam if (ni->ni_rates.rs_nrates < 10) 326116742Ssam res->wi_srates[ni->ni_rates.rs_nrates] = 0; 327116742Ssam res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate]; 328116742Ssam res->wi_rsvd = 0; 329116742Ssam res++, i++; 330116742Ssam } 331116742Ssam p2->wi_rsvd = 0; 332116742Ssam p2->wi_reason = i; 333116742Ssam wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2; 334116742Ssam break; 335116742Ssam case WI_RID_READ_CACHE: 336116742Ssam i = 0; 337116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 338116742Ssam if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1) 339116742Ssam break; 340116742Ssam IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr); 341116742Ssam memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc)); 342116742Ssam wsc.signal = ni->ni_rssi; 343116742Ssam wsc.noise = 0; 344116742Ssam wsc.quality = 0; 345116742Ssam memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i, 346116742Ssam &wsc, sizeof(wsc)); 347116742Ssam i++; 348116742Ssam } 349116742Ssam wreq.wi_len = sizeof(wsc) * i / 2; 350116742Ssam break; 351116742Ssam case WI_RID_SCAN_APS: 352116742Ssam error = EINVAL; 353116742Ssam break; 354116742Ssam default: 355116742Ssam error = EINVAL; 356116742Ssam break; 357116742Ssam } 358116742Ssam if (error == 0) { 359116742Ssam wreq.wi_len++; 360116742Ssam error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 361116742Ssam } 362116742Ssam return error; 363116742Ssam} 364116742Ssam 365116742Ssamstatic int 366116742Ssamfindrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) 367116742Ssam{ 368116742Ssam#define IEEERATE(_ic,_m,_i) \ 369116742Ssam ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) 370116742Ssam int i, nrates = ic->ic_sup_rates[mode].rs_nrates; 371116742Ssam for (i = 0; i < nrates; i++) 372116742Ssam if (IEEERATE(ic, mode, i) == rate) 373116742Ssam return i; 374116742Ssam return -1; 375116742Ssam#undef IEEERATE 376116742Ssam} 377116742Ssam 378116742Ssamint 379116742Ssamieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data) 380116742Ssam{ 381116742Ssam struct ieee80211com *ic = (void *)ifp; 382116742Ssam int i, j, len, error, rate; 383116742Ssam struct ifreq *ifr = (struct ifreq *)data; 384116742Ssam struct wi_ltv_keys *keys; 385116742Ssam struct wi_req wreq; 386116742Ssam u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)]; 387116742Ssam 388116742Ssam error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 389116742Ssam if (error) 390116742Ssam return error; 391116742Ssam len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0; 392116742Ssam switch (wreq.wi_type) { 393116742Ssam case WI_RID_SERIALNO: 394116742Ssam case WI_RID_NODENAME: 395116742Ssam return EPERM; 396116742Ssam case WI_RID_CURRENT_SSID: 397116742Ssam return EPERM; 398116742Ssam case WI_RID_OWN_SSID: 399116742Ssam case WI_RID_DESIRED_SSID: 400116742Ssam if (le16toh(wreq.wi_val[0]) * 2 > len || 401116742Ssam le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) { 402116742Ssam error = ENOSPC; 403116742Ssam break; 404116742Ssam } 405116742Ssam memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid)); 406116742Ssam ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2; 407117040Ssam memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen); 408116742Ssam error = ENETRESET; 409116742Ssam break; 410116742Ssam case WI_RID_CURRENT_BSSID: 411116742Ssam return EPERM; 412116742Ssam case WI_RID_OWN_CHNL: 413116742Ssam if (len != 2) 414116742Ssam return EINVAL; 415116742Ssam i = le16toh(wreq.wi_val[0]); 416116742Ssam if (i < 0 || 417116742Ssam i > IEEE80211_CHAN_MAX || 418116742Ssam isclr(ic->ic_chan_active, i)) 419116742Ssam return EINVAL; 420116742Ssam ic->ic_ibss_chan = &ic->ic_channels[i]; 421116742Ssam if (ic->ic_flags & IEEE80211_F_SIBSS) 422116742Ssam error = ENETRESET; 423116742Ssam break; 424116742Ssam case WI_RID_CURRENT_CHAN: 425116742Ssam return EPERM; 426116742Ssam case WI_RID_COMMS_QUALITY: 427116742Ssam return EPERM; 428116742Ssam case WI_RID_PROMISC: 429116742Ssam if (len != 2) 430116742Ssam return EINVAL; 431116742Ssam if (ifp->if_flags & IFF_PROMISC) { 432116742Ssam if (wreq.wi_val[0] == 0) { 433116742Ssam ifp->if_flags &= ~IFF_PROMISC; 434116742Ssam error = ENETRESET; 435116742Ssam } 436116742Ssam } else { 437116742Ssam if (wreq.wi_val[0] != 0) { 438116742Ssam ifp->if_flags |= IFF_PROMISC; 439116742Ssam error = ENETRESET; 440116742Ssam } 441116742Ssam } 442116742Ssam break; 443116742Ssam case WI_RID_PORTTYPE: 444116742Ssam if (len != 2) 445116742Ssam return EINVAL; 446116742Ssam switch (le16toh(wreq.wi_val[0])) { 447116742Ssam case IEEE80211_M_STA: 448116742Ssam break; 449116742Ssam case IEEE80211_M_IBSS: 450116742Ssam if (!(ic->ic_caps & IEEE80211_C_IBSS)) 451116742Ssam return EINVAL; 452116742Ssam break; 453116742Ssam case IEEE80211_M_AHDEMO: 454116742Ssam if (ic->ic_phytype != IEEE80211_T_DS || 455116742Ssam !(ic->ic_caps & IEEE80211_C_AHDEMO)) 456116742Ssam return EINVAL; 457116742Ssam break; 458116742Ssam case IEEE80211_M_HOSTAP: 459116742Ssam if (!(ic->ic_caps & IEEE80211_C_HOSTAP)) 460116742Ssam return EINVAL; 461116742Ssam break; 462116742Ssam default: 463116742Ssam return EINVAL; 464116742Ssam } 465116742Ssam if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) { 466116742Ssam ic->ic_opmode = le16toh(wreq.wi_val[0]); 467116742Ssam error = ENETRESET; 468116742Ssam } 469116742Ssam break; 470116742Ssam#if 0 471116742Ssam case WI_RID_MAC_NODE: 472116742Ssam if (len != IEEE80211_ADDR_LEN) 473116742Ssam return EINVAL; 474116742Ssam IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val); 475116742Ssam /* if_init will copy lladdr into ic_myaddr */ 476116742Ssam error = ENETRESET; 477116742Ssam break; 478116742Ssam#endif 479116742Ssam case WI_RID_TX_RATE: 480116742Ssam if (len != 2) 481116742Ssam return EINVAL; 482116742Ssam if (wreq.wi_val[0] == 0) { 483116742Ssam /* auto */ 484116742Ssam ic->ic_fixed_rate = -1; 485116742Ssam break; 486116742Ssam } 487116742Ssam rate = 2 * le16toh(wreq.wi_val[0]); 488116742Ssam if (ic->ic_curmode == IEEE80211_MODE_AUTO) { 489116742Ssam /* 490116742Ssam * In autoselect mode search for the rate. We take 491116742Ssam * the first instance which may not be right, but we 492116742Ssam * are limited by the interface. Note that we also 493116742Ssam * lock the mode to insure the rate is meaningful 494116742Ssam * when it is used. 495116742Ssam */ 496116742Ssam for (j = IEEE80211_MODE_11A; 497116742Ssam j < IEEE80211_MODE_MAX; j++) { 498116742Ssam if ((ic->ic_modecaps & (1<<j)) == 0) 499116742Ssam continue; 500116742Ssam i = findrate(ic, j, rate); 501116742Ssam if (i != -1) { 502116742Ssam /* lock mode too */ 503116742Ssam ic->ic_curmode = j; 504116742Ssam goto setrate; 505116742Ssam } 506116742Ssam } 507116742Ssam } else { 508116742Ssam i = findrate(ic, ic->ic_curmode, rate); 509116742Ssam if (i != -1) 510116742Ssam goto setrate; 511116742Ssam } 512116742Ssam return EINVAL; 513116742Ssam setrate: 514116742Ssam ic->ic_fixed_rate = i; 515116742Ssam error = ENETRESET; 516116742Ssam break; 517116742Ssam case WI_RID_CUR_TX_RATE: 518116742Ssam return EPERM; 519116742Ssam case WI_RID_RTS_THRESH: 520116742Ssam if (len != 2) 521116742Ssam return EINVAL; 522116742Ssam if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN) 523116742Ssam return EINVAL; /* TODO: RTS */ 524116742Ssam break; 525116742Ssam case WI_RID_CREATE_IBSS: 526116742Ssam if (len != 2) 527116742Ssam return EINVAL; 528116742Ssam if (wreq.wi_val[0] != 0) { 529116742Ssam if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) 530116742Ssam return EINVAL; 531116742Ssam if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 532116742Ssam ic->ic_flags |= IEEE80211_F_IBSSON; 533116742Ssam if (ic->ic_opmode == IEEE80211_M_IBSS && 534116742Ssam ic->ic_state == IEEE80211_S_SCAN) 535116742Ssam error = ENETRESET; 536116742Ssam } 537116742Ssam } else { 538116742Ssam if (ic->ic_flags & IEEE80211_F_IBSSON) { 539116742Ssam ic->ic_flags &= ~IEEE80211_F_IBSSON; 540116742Ssam if (ic->ic_flags & IEEE80211_F_SIBSS) { 541116742Ssam ic->ic_flags &= ~IEEE80211_F_SIBSS; 542116742Ssam error = ENETRESET; 543116742Ssam } 544116742Ssam } 545116742Ssam } 546116742Ssam break; 547116742Ssam case WI_RID_MICROWAVE_OVEN: 548116742Ssam if (len != 2) 549116742Ssam return EINVAL; 550116742Ssam if (wreq.wi_val[0] != 0) 551116742Ssam return EINVAL; /* not supported */ 552116742Ssam break; 553116742Ssam case WI_RID_ROAMING_MODE: 554116742Ssam if (len != 2) 555116742Ssam return EINVAL; 556116742Ssam if (le16toh(wreq.wi_val[0]) != 1) 557116742Ssam return EINVAL; /* not supported */ 558116742Ssam break; 559116742Ssam case WI_RID_SYSTEM_SCALE: 560116742Ssam if (len != 2) 561116742Ssam return EINVAL; 562116742Ssam if (le16toh(wreq.wi_val[0]) != 1) 563116742Ssam return EINVAL; /* not supported */ 564116742Ssam break; 565116742Ssam case WI_RID_PM_ENABLED: 566116742Ssam if (len != 2) 567116742Ssam return EINVAL; 568116742Ssam if (wreq.wi_val[0] != 0) { 569116742Ssam if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 570116742Ssam return EINVAL; 571116742Ssam if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 572116742Ssam ic->ic_flags |= IEEE80211_F_PMGTON; 573116742Ssam error = ENETRESET; 574116742Ssam } 575116742Ssam } else { 576116742Ssam if (ic->ic_flags & IEEE80211_F_PMGTON) { 577116742Ssam ic->ic_flags &= ~IEEE80211_F_PMGTON; 578116742Ssam error = ENETRESET; 579116742Ssam } 580116742Ssam } 581116742Ssam break; 582116742Ssam case WI_RID_MAX_SLEEP: 583116742Ssam if (len != 2) 584116742Ssam return EINVAL; 585116742Ssam ic->ic_lintval = le16toh(wreq.wi_val[0]); 586116742Ssam if (ic->ic_flags & IEEE80211_F_PMGTON) 587116742Ssam error = ENETRESET; 588116742Ssam break; 589116742Ssam case WI_RID_CUR_BEACON_INT: 590116742Ssam return EPERM; 591116742Ssam case WI_RID_WEP_AVAIL: 592116742Ssam return EPERM; 593116742Ssam case WI_RID_CNFAUTHMODE: 594116742Ssam if (len != 2) 595116742Ssam return EINVAL; 596116742Ssam if (le16toh(wreq.wi_val[0]) != 1) 597116742Ssam return EINVAL; /* TODO: shared key auth */ 598116742Ssam break; 599116742Ssam case WI_RID_ENCRYPTION: 600116742Ssam if (len != 2) 601116742Ssam return EINVAL; 602116742Ssam if (wreq.wi_val[0] != 0) { 603116742Ssam if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 604116742Ssam return EINVAL; 605116742Ssam if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) { 606116742Ssam ic->ic_flags |= IEEE80211_F_WEPON; 607116742Ssam error = ENETRESET; 608116742Ssam } 609116742Ssam } else { 610116742Ssam if (ic->ic_flags & IEEE80211_F_WEPON) { 611116742Ssam ic->ic_flags &= ~IEEE80211_F_WEPON; 612116742Ssam error = ENETRESET; 613116742Ssam } 614116742Ssam } 615116742Ssam break; 616116742Ssam case WI_RID_TX_CRYPT_KEY: 617116742Ssam if (len != 2) 618116742Ssam return EINVAL; 619116742Ssam i = le16toh(wreq.wi_val[0]); 620116742Ssam if (i >= IEEE80211_WEP_NKID) 621116742Ssam return EINVAL; 622116742Ssam ic->ic_wep_txkey = i; 623116742Ssam break; 624116742Ssam case WI_RID_DEFLT_CRYPT_KEYS: 625116742Ssam if (len != sizeof(struct wi_ltv_keys)) 626116742Ssam return EINVAL; 627116742Ssam keys = (struct wi_ltv_keys *)&wreq; 628116742Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) { 629116742Ssam len = le16toh(keys->wi_keys[i].wi_keylen); 630116742Ssam if (len != 0 && len < IEEE80211_WEP_KEYLEN) 631116742Ssam return EINVAL; 632116742Ssam if (len > sizeof(ic->ic_nw_keys[i].wk_key)) 633116742Ssam return EINVAL; 634116742Ssam } 635116742Ssam memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys)); 636116742Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) { 637116742Ssam len = le16toh(keys->wi_keys[i].wi_keylen); 638116742Ssam ic->ic_nw_keys[i].wk_len = len; 639116742Ssam memcpy(ic->ic_nw_keys[i].wk_key, 640116742Ssam keys->wi_keys[i].wi_keydat, len); 641116742Ssam } 642116742Ssam error = ENETRESET; 643116742Ssam break; 644116742Ssam case WI_RID_MAX_DATALEN: 645116742Ssam if (len != 2) 646116742Ssam return EINVAL; 647116742Ssam len = le16toh(wreq.wi_val[0]); 648116742Ssam if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN) 649116742Ssam return EINVAL; 650116742Ssam if (len != IEEE80211_MAX_LEN) 651116742Ssam return EINVAL; /* TODO: fragment */ 652116742Ssam ic->ic_fragthreshold = len; 653116742Ssam error = ENETRESET; 654116742Ssam break; 655116742Ssam case WI_RID_IFACE_STATS: 656116742Ssam error = EPERM; 657116742Ssam break; 658116742Ssam case WI_RID_SCAN_REQ: /* XXX wicontrol */ 659116742Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP) 660116742Ssam break; 661116742Ssam /* NB: ignore channel list and tx rate parameters */ 662116742Ssam error = ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); 663116742Ssam break; 664116742Ssam case WI_RID_SCAN_APS: 665116742Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP) 666116742Ssam break; 667116742Ssam len--; /* XXX: tx rate? */ 668116742Ssam /* FALLTHRU */ 669116742Ssam case WI_RID_CHANNEL_LIST: 670116742Ssam memset(chanlist, 0, sizeof(chanlist)); 671116742Ssam /* 672116742Ssam * Since channel 0 is not available for DS, channel 1 673116742Ssam * is assigned to LSB on WaveLAN. 674116742Ssam */ 675116742Ssam if (ic->ic_phytype == IEEE80211_T_DS) 676116742Ssam i = 1; 677116742Ssam else 678116742Ssam i = 0; 679116742Ssam for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { 680116742Ssam if ((j / 8) >= len) 681116742Ssam break; 682116742Ssam if (isclr((u_int8_t *)wreq.wi_val, j)) 683116742Ssam continue; 684116742Ssam if (isclr(ic->ic_chan_active, i)) { 685116742Ssam if (wreq.wi_type != WI_RID_CHANNEL_LIST) 686116742Ssam continue; 687116742Ssam if (isclr(ic->ic_chan_avail, i)) 688116742Ssam return EPERM; 689116742Ssam } 690116742Ssam setbit(chanlist, i); 691116742Ssam } 692116742Ssam memcpy(ic->ic_chan_active, chanlist, 693116742Ssam sizeof(ic->ic_chan_active)); 694116742Ssam if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 695116742Ssam for (i = 0; i <= IEEE80211_CHAN_MAX; i++) 696116742Ssam if (isset(chanlist, i)) { 697116742Ssam ic->ic_ibss_chan = &ic->ic_channels[i]; 698116742Ssam break; 699116742Ssam } 700116742Ssam } 701116742Ssam if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan))) 702116742Ssam ic->ic_bss->ni_chan = ic->ic_ibss_chan; 703116742Ssam if (wreq.wi_type == WI_RID_CHANNEL_LIST) 704116742Ssam error = ENETRESET; 705116742Ssam else 706116742Ssam error = ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); 707116742Ssam break; 708116742Ssam default: 709116742Ssam error = EINVAL; 710116742Ssam break; 711116742Ssam } 712116742Ssam return error; 713116742Ssam} 714116742Ssam 715116742Ssamint 716116742Ssamieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 717116742Ssam{ 718116742Ssam struct ieee80211com *ic = (void *)ifp; 719116742Ssam int error = 0; 720116742Ssam u_int kid, len; 721116742Ssam struct ieee80211req *ireq; 722116742Ssam u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; 723116742Ssam char tmpssid[IEEE80211_NWID_LEN]; 724116742Ssam struct ieee80211_channel *chan; 725116742Ssam 726116742Ssam switch (cmd) { 727116742Ssam case SIOCSIFMEDIA: 728116742Ssam case SIOCGIFMEDIA: 729116742Ssam error = ifmedia_ioctl(ifp, (struct ifreq *) data, 730116742Ssam &ic->ic_media, cmd); 731116742Ssam break; 732116742Ssam case SIOCG80211: 733116742Ssam ireq = (struct ieee80211req *) data; 734116742Ssam switch (ireq->i_type) { 735116742Ssam case IEEE80211_IOC_SSID: 736116742Ssam switch (ic->ic_state) { 737116742Ssam case IEEE80211_S_INIT: 738116742Ssam case IEEE80211_S_SCAN: 739116742Ssam ireq->i_len = ic->ic_des_esslen; 740116742Ssam memcpy(tmpssid, ic->ic_des_essid, ireq->i_len); 741116742Ssam break; 742116742Ssam default: 743116742Ssam ireq->i_len = ic->ic_bss->ni_esslen; 744116742Ssam memcpy(tmpssid, ic->ic_bss->ni_essid, 745116742Ssam ireq->i_len); 746116742Ssam break; 747116742Ssam } 748116742Ssam error = copyout(tmpssid, ireq->i_data, ireq->i_len); 749116742Ssam break; 750116742Ssam case IEEE80211_IOC_NUMSSIDS: 751116742Ssam ireq->i_val = 1; 752116742Ssam break; 753116742Ssam case IEEE80211_IOC_WEP: 754116742Ssam if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 755116742Ssam ireq->i_val = IEEE80211_WEP_NOSUP; 756116742Ssam } else { 757116742Ssam if (ic->ic_flags & IEEE80211_F_WEPON) { 758116742Ssam ireq->i_val = 759116742Ssam IEEE80211_WEP_MIXED; 760116742Ssam } else { 761116742Ssam ireq->i_val = 762116742Ssam IEEE80211_WEP_OFF; 763116742Ssam } 764116742Ssam } 765116742Ssam break; 766116742Ssam case IEEE80211_IOC_WEPKEY: 767116742Ssam if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 768116742Ssam error = EINVAL; 769116742Ssam break; 770116742Ssam } 771116742Ssam kid = (u_int) ireq->i_val; 772116742Ssam if (kid >= IEEE80211_WEP_NKID) { 773116742Ssam error = EINVAL; 774116742Ssam break; 775116742Ssam } 776116742Ssam len = (u_int) ic->ic_nw_keys[kid].wk_len; 777116742Ssam /* NB: only root can read WEP keys */ 778116742Ssam if (suser(curthread)) { 779116742Ssam bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len); 780116742Ssam } else { 781116742Ssam bzero(tmpkey, len); 782116742Ssam } 783116742Ssam ireq->i_len = len; 784116742Ssam error = copyout(tmpkey, ireq->i_data, len); 785116742Ssam break; 786116742Ssam case IEEE80211_IOC_NUMWEPKEYS: 787116742Ssam if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 788116742Ssam error = EINVAL; 789116742Ssam else 790116742Ssam ireq->i_val = IEEE80211_WEP_NKID; 791116742Ssam break; 792116742Ssam case IEEE80211_IOC_WEPTXKEY: 793116742Ssam if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 794116742Ssam error = EINVAL; 795116742Ssam else 796116742Ssam ireq->i_val = ic->ic_wep_txkey; 797116742Ssam break; 798116742Ssam case IEEE80211_IOC_AUTHMODE: 799116742Ssam ireq->i_val = IEEE80211_AUTH_OPEN; 800116742Ssam break; 801116742Ssam case IEEE80211_IOC_CHANNEL: 802116742Ssam switch (ic->ic_state) { 803116742Ssam case IEEE80211_S_INIT: 804116742Ssam case IEEE80211_S_SCAN: 805116742Ssam if (ic->ic_opmode == IEEE80211_M_STA) 806116742Ssam chan = ic->ic_des_chan; 807116742Ssam else 808116742Ssam chan = ic->ic_ibss_chan; 809116742Ssam break; 810116742Ssam default: 811116742Ssam chan = ic->ic_bss->ni_chan; 812116742Ssam break; 813116742Ssam } 814116742Ssam ireq->i_val = ieee80211_chan2ieee(ic, chan); 815116742Ssam break; 816116742Ssam case IEEE80211_IOC_POWERSAVE: 817116742Ssam if (ic->ic_flags & IEEE80211_F_PMGTON) 818116742Ssam ireq->i_val = IEEE80211_POWERSAVE_ON; 819116742Ssam else 820116742Ssam ireq->i_val = IEEE80211_POWERSAVE_OFF; 821116742Ssam break; 822116742Ssam case IEEE80211_IOC_POWERSAVESLEEP: 823116742Ssam ireq->i_val = ic->ic_lintval; 824116742Ssam break; 825116742Ssam case IEEE80211_IOCT_RTSTHRESHOLD: 826116742Ssam ireq->i_val = ic->ic_rtsthreshold; 827116742Ssam break; 828116742Ssam default: 829116742Ssam error = EINVAL; 830116742Ssam } 831116742Ssam break; 832116742Ssam case SIOCS80211: 833116742Ssam error = suser(curthread); 834116742Ssam if (error) 835116742Ssam break; 836116742Ssam ireq = (struct ieee80211req *) data; 837116742Ssam switch (ireq->i_type) { 838116742Ssam case IEEE80211_IOC_SSID: 839116742Ssam if (ireq->i_val != 0 || 840116742Ssam ireq->i_len > IEEE80211_NWID_LEN) { 841116742Ssam error = EINVAL; 842116742Ssam break; 843116742Ssam } 844116742Ssam error = copyin(ireq->i_data, tmpssid, ireq->i_len); 845116742Ssam if (error) 846116742Ssam break; 847116742Ssam memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); 848116742Ssam ic->ic_des_esslen = ireq->i_len; 849116742Ssam memcpy(ic->ic_des_essid, tmpssid, ireq->i_len); 850116742Ssam error = ENETRESET; 851116742Ssam break; 852116742Ssam case IEEE80211_IOC_WEP: 853116742Ssam /* 854116742Ssam * These cards only support one mode so 855116742Ssam * we just turn wep on if what ever is 856116742Ssam * passed in is not OFF. 857116742Ssam */ 858116742Ssam if (ireq->i_val == IEEE80211_WEP_OFF) { 859116742Ssam ic->ic_flags &= ~IEEE80211_F_WEPON; 860116742Ssam } else { 861116742Ssam ic->ic_flags |= IEEE80211_F_WEPON; 862116742Ssam } 863116742Ssam error = ENETRESET; 864116742Ssam break; 865116742Ssam case IEEE80211_IOC_WEPKEY: 866116742Ssam if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 867116742Ssam error = EINVAL; 868116742Ssam break; 869116742Ssam } 870116742Ssam kid = (u_int) ireq->i_val; 871116742Ssam if (kid >= IEEE80211_WEP_NKID) { 872116742Ssam error = EINVAL; 873116742Ssam break; 874116742Ssam } 875116742Ssam if (ireq->i_len > sizeof(tmpkey)) { 876116742Ssam error = EINVAL; 877116742Ssam break; 878116742Ssam } 879116742Ssam memset(tmpkey, 0, sizeof(tmpkey)); 880116742Ssam error = copyin(ireq->i_data, tmpkey, ireq->i_len); 881116742Ssam if (error) 882116742Ssam break; 883116742Ssam memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey, 884116742Ssam sizeof(tmpkey)); 885116742Ssam ic->ic_nw_keys[kid].wk_len = ireq->i_len; 886116742Ssam error = ENETRESET; 887116742Ssam break; 888116742Ssam case IEEE80211_IOC_WEPTXKEY: 889116742Ssam kid = (u_int) ireq->i_val; 890116742Ssam if (kid >= IEEE80211_WEP_NKID) { 891116742Ssam error = EINVAL; 892116742Ssam break; 893116742Ssam } 894116742Ssam ic->ic_wep_txkey = kid; 895116742Ssam error = ENETRESET; 896116742Ssam break; 897116742Ssam#if 0 898116742Ssam case IEEE80211_IOC_AUTHMODE: 899116742Ssam sc->wi_authmode = ireq->i_val; 900116742Ssam break; 901116742Ssam#endif 902116742Ssam case IEEE80211_IOC_CHANNEL: 903116742Ssam /* XXX 0xffff overflows 16-bit signed */ 904116742Ssam if (ireq->i_val == 0 || 905116742Ssam ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) 906116742Ssam ic->ic_des_chan = IEEE80211_CHAN_ANYC; 907116742Ssam else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX || 908116742Ssam isclr(ic->ic_chan_active, ireq->i_val)) { 909116742Ssam error = EINVAL; 910116742Ssam break; 911116742Ssam } else 912116742Ssam ic->ic_ibss_chan = ic->ic_des_chan = 913116742Ssam &ic->ic_channels[ireq->i_val]; 914116742Ssam switch (ic->ic_state) { 915116742Ssam case IEEE80211_S_INIT: 916116742Ssam case IEEE80211_S_SCAN: 917116742Ssam error = ENETRESET; 918116742Ssam break; 919116742Ssam default: 920116742Ssam if (ic->ic_opmode == IEEE80211_M_STA) { 921116742Ssam if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 922116742Ssam ic->ic_bss->ni_chan != ic->ic_des_chan) 923116742Ssam error = ENETRESET; 924116742Ssam } else { 925116742Ssam if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) 926116742Ssam error = ENETRESET; 927116742Ssam } 928116742Ssam break; 929116742Ssam } 930116742Ssam break; 931116742Ssam case IEEE80211_IOC_POWERSAVE: 932116742Ssam switch (ireq->i_val) { 933116742Ssam case IEEE80211_POWERSAVE_OFF: 934116742Ssam if (ic->ic_flags & IEEE80211_F_PMGTON) { 935116742Ssam ic->ic_flags &= ~IEEE80211_F_PMGTON; 936116742Ssam error = ENETRESET; 937116742Ssam } 938116742Ssam break; 939116742Ssam case IEEE80211_POWERSAVE_ON: 940116742Ssam if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 941116742Ssam error = EINVAL; 942116742Ssam else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 943116742Ssam ic->ic_flags |= IEEE80211_F_PMGTON; 944116742Ssam error = ENETRESET; 945116742Ssam } 946116742Ssam break; 947116742Ssam default: 948116742Ssam error = EINVAL; 949116742Ssam break; 950116742Ssam } 951116742Ssam break; 952116742Ssam case IEEE80211_IOC_POWERSAVESLEEP: 953116742Ssam if (ireq->i_val < 0) { 954116742Ssam error = EINVAL; 955116742Ssam break; 956116742Ssam } 957116742Ssam ic->ic_lintval = ireq->i_val; 958116742Ssam error = ENETRESET; 959116742Ssam break; 960116742Ssam case IEEE80211_IOCT_RTSTHRESHOLD: 961116742Ssam if (!(IEEE80211_RTS_MIN < ireq->i_val && 962116742Ssam ireq->i_val < IEEE80211_RTS_MAX)) { 963116742Ssam error = EINVAL; 964116742Ssam break; 965116742Ssam } 966116742Ssam ic->ic_rtsthreshold = ireq->i_val; 967116742Ssam error = ENETRESET; 968116742Ssam break; 969116742Ssam default: 970116742Ssam error = EINVAL; 971116742Ssam break; 972116742Ssam } 973116742Ssam break; 974116742Ssam case SIOCGIFGENERIC: 975116742Ssam error = ieee80211_cfgget(ifp, cmd, data); 976116742Ssam break; 977116742Ssam case SIOCSIFGENERIC: 978116742Ssam error = suser(curthread); 979116742Ssam if (error) 980116742Ssam break; 981116742Ssam error = ieee80211_cfgset(ifp, cmd, data); 982116742Ssam break; 983116742Ssam default: 984116742Ssam error = ether_ioctl(ifp, cmd, data); 985116742Ssam break; 986116742Ssam } 987116742Ssam return error; 988116742Ssam} 989