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