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