ieee80211_ioctl.c revision 124457
1/*- 2 * Copyright (c) 2001 Atsushi Onoe 3 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * Alternatively, this software may be distributed under the terms of the 18 * GNU General Public License ("GPL") version 2 as published by the Free 19 * Software Foundation. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ioctl.c 124457 2004-01-13 06:22:55Z sam $"); 35 36/* 37 * IEEE 802.11 ioctl support (FreeBSD-specific) 38 */ 39 40#include <sys/endian.h> 41#include <sys/param.h> 42#include <sys/kernel.h> 43#include <sys/socket.h> 44#include <sys/sockio.h> 45#include <sys/systm.h> 46 47#include <net/if.h> 48#include <net/if_arp.h> 49#include <net/if_media.h> 50#include <net/ethernet.h> 51 52#include <net80211/ieee80211_var.h> 53#include <net80211/ieee80211_ioctl.h> 54 55#include <dev/wi/if_wavelan_ieee.h> 56 57/* 58 * XXX 59 * Wireless LAN specific configuration interface, which is compatible 60 * with wicontrol(8). 61 */ 62 63int 64ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data) 65{ 66 struct ieee80211com *ic = (void *)ifp; 67 int i, j, error; 68 struct ifreq *ifr = (struct ifreq *)data; 69 struct wi_req wreq; 70 struct wi_ltv_keys *keys; 71 struct wi_apinfo *ap; 72 struct ieee80211_node *ni; 73 struct ieee80211_rateset *rs; 74 struct wi_sigcache wsc; 75 struct wi_scan_p2_hdr *p2; 76 struct wi_scan_res *res; 77 78 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 79 if (error) 80 return error; 81 wreq.wi_len = 0; 82 switch (wreq.wi_type) { 83 case WI_RID_SERIALNO: 84 /* nothing appropriate */ 85 break; 86 case WI_RID_NODENAME: 87 strcpy((char *)&wreq.wi_val[1], hostname); 88 wreq.wi_val[0] = htole16(strlen(hostname)); 89 wreq.wi_len = (1 + strlen(hostname) + 1) / 2; 90 break; 91 case WI_RID_CURRENT_SSID: 92 if (ic->ic_state != IEEE80211_S_RUN) { 93 wreq.wi_val[0] = 0; 94 wreq.wi_len = 1; 95 break; 96 } 97 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen); 98 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid, 99 ic->ic_bss->ni_esslen); 100 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2; 101 break; 102 case WI_RID_OWN_SSID: 103 case WI_RID_DESIRED_SSID: 104 wreq.wi_val[0] = htole16(ic->ic_des_esslen); 105 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen); 106 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2; 107 break; 108 case WI_RID_CURRENT_BSSID: 109 if (ic->ic_state == IEEE80211_S_RUN) 110 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid); 111 else 112 memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN); 113 wreq.wi_len = IEEE80211_ADDR_LEN / 2; 114 break; 115 case WI_RID_CHANNEL_LIST: 116 memset(wreq.wi_val, 0, sizeof(wreq.wi_val)); 117 /* 118 * Since channel 0 is not available for DS, channel 1 119 * is assigned to LSB on WaveLAN. 120 */ 121 if (ic->ic_phytype == IEEE80211_T_DS) 122 i = 1; 123 else 124 i = 0; 125 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) 126 if (isset(ic->ic_chan_active, i)) { 127 setbit((u_int8_t *)wreq.wi_val, j); 128 wreq.wi_len = j / 16 + 1; 129 } 130 break; 131 case WI_RID_OWN_CHNL: 132 wreq.wi_val[0] = htole16( 133 ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); 134 wreq.wi_len = 1; 135 break; 136 case WI_RID_CURRENT_CHAN: 137 wreq.wi_val[0] = htole16( 138 ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)); 139 wreq.wi_len = 1; 140 break; 141 case WI_RID_COMMS_QUALITY: 142 wreq.wi_val[0] = 0; /* quality */ 143 wreq.wi_val[1] = 144 htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss)); 145 wreq.wi_val[2] = 0; /* noise */ 146 wreq.wi_len = 3; 147 break; 148 case WI_RID_PROMISC: 149 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0); 150 wreq.wi_len = 1; 151 break; 152 case WI_RID_PORTTYPE: 153 wreq.wi_val[0] = htole16(ic->ic_opmode); 154 wreq.wi_len = 1; 155 break; 156 case WI_RID_MAC_NODE: 157 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr); 158 wreq.wi_len = IEEE80211_ADDR_LEN / 2; 159 break; 160 case WI_RID_TX_RATE: 161 if (ic->ic_fixed_rate == -1) 162 wreq.wi_val[0] = 0; /* auto */ 163 else 164 wreq.wi_val[0] = htole16( 165 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] & 166 IEEE80211_RATE_VAL) / 2); 167 wreq.wi_len = 1; 168 break; 169 case WI_RID_CUR_TX_RATE: 170 wreq.wi_val[0] = htole16( 171 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & 172 IEEE80211_RATE_VAL) / 2); 173 wreq.wi_len = 1; 174 break; 175 case WI_RID_RTS_THRESH: 176 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold); 177 wreq.wi_len = 1; 178 break; 179 case WI_RID_CREATE_IBSS: 180 wreq.wi_val[0] = 181 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0); 182 wreq.wi_len = 1; 183 break; 184 case WI_RID_MICROWAVE_OVEN: 185 wreq.wi_val[0] = 0; /* no ... not supported */ 186 wreq.wi_len = 1; 187 break; 188 case WI_RID_ROAMING_MODE: 189 wreq.wi_val[0] = htole16(1); /* enabled ... not supported */ 190 wreq.wi_len = 1; 191 break; 192 case WI_RID_SYSTEM_SCALE: 193 wreq.wi_val[0] = htole16(1); /* low density ... not supp */ 194 wreq.wi_len = 1; 195 break; 196 case WI_RID_PM_ENABLED: 197 wreq.wi_val[0] = 198 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); 199 wreq.wi_len = 1; 200 break; 201 case WI_RID_MAX_SLEEP: 202 wreq.wi_val[0] = htole16(ic->ic_lintval); 203 wreq.wi_len = 1; 204 break; 205 case WI_RID_CUR_BEACON_INT: 206 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval); 207 wreq.wi_len = 1; 208 break; 209 case WI_RID_WEP_AVAIL: 210 wreq.wi_val[0] = 211 htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0); 212 wreq.wi_len = 1; 213 break; 214 case WI_RID_CNFAUTHMODE: 215 wreq.wi_val[0] = htole16(1); /* TODO: open system only */ 216 wreq.wi_len = 1; 217 break; 218 case WI_RID_ENCRYPTION: 219 wreq.wi_val[0] = 220 htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0); 221 wreq.wi_len = 1; 222 break; 223 case WI_RID_TX_CRYPT_KEY: 224 wreq.wi_val[0] = htole16(ic->ic_wep_txkey); 225 wreq.wi_len = 1; 226 break; 227 case WI_RID_DEFLT_CRYPT_KEYS: 228 keys = (struct wi_ltv_keys *)&wreq; 229 /* do not show keys to non-root user */ 230 error = suser(curthread); 231 if (error) { 232 memset(keys, 0, sizeof(*keys)); 233 error = 0; 234 break; 235 } 236 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 237 keys->wi_keys[i].wi_keylen = 238 htole16(ic->ic_nw_keys[i].wk_len); 239 memcpy(keys->wi_keys[i].wi_keydat, 240 ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len); 241 } 242 wreq.wi_len = sizeof(*keys) / 2; 243 break; 244 case WI_RID_MAX_DATALEN: 245 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */ 246 wreq.wi_len = 1; 247 break; 248 case WI_RID_IFACE_STATS: 249 /* XXX: should be implemented in lower drivers */ 250 break; 251 case WI_RID_READ_APS: 252 if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 253 /* 254 * Don't return results until active scan completes. 255 */ 256 if (ic->ic_state == IEEE80211_S_SCAN && 257 (ic->ic_flags & IEEE80211_F_ASCAN)) { 258 error = EINPROGRESS; 259 break; 260 } 261 } 262 i = 0; 263 ap = (void *)((char *)wreq.wi_val + sizeof(i)); 264 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 265 if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1)) 266 break; 267 memset(ap, 0, sizeof(*ap)); 268 if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 269 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr); 270 ap->namelen = ic->ic_des_esslen; 271 if (ic->ic_des_esslen) 272 memcpy(ap->name, ic->ic_des_essid, 273 ic->ic_des_esslen); 274 } else { 275 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid); 276 ap->namelen = ni->ni_esslen; 277 if (ni->ni_esslen) 278 memcpy(ap->name, ni->ni_essid, 279 ni->ni_esslen); 280 } 281 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan); 282 ap->signal = (*ic->ic_node_getrssi)(ic, ni); 283 ap->capinfo = ni->ni_capinfo; 284 ap->interval = ni->ni_intval; 285 rs = &ni->ni_rates; 286 for (j = 0; j < rs->rs_nrates; j++) { 287 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) { 288 ap->rate = (rs->rs_rates[j] & 289 IEEE80211_RATE_VAL) * 5; /* XXX */ 290 } 291 } 292 i++; 293 ap++; 294 } 295 memcpy(wreq.wi_val, &i, sizeof(i)); 296 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2; 297 break; 298 case WI_RID_PRISM2: 299 wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */ 300 wreq.wi_len = sizeof(u_int16_t) / 2; 301 break; 302 case WI_RID_SCAN_RES: /* compatibility interface */ 303 if (ic->ic_opmode != IEEE80211_M_HOSTAP && 304 ic->ic_state == IEEE80211_S_SCAN) { 305 error = EINPROGRESS; 306 break; 307 } 308 /* NB: we use the Prism2 format so we can return rate info */ 309 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val; 310 res = (void *)&p2[1]; 311 i = 0; 312 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 313 if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1)) 314 break; 315 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan); 316 res->wi_noise = 0; 317 res->wi_signal = (*ic->ic_node_getrssi)(ic, ni); 318 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid); 319 res->wi_interval = ni->ni_intval; 320 res->wi_capinfo = ni->ni_capinfo; 321 res->wi_ssid_len = ni->ni_esslen; 322 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN); 323 /* NB: assumes wi_srates holds <= ni->ni_rates */ 324 memcpy(res->wi_srates, ni->ni_rates.rs_rates, 325 sizeof(res->wi_srates)); 326 if (ni->ni_rates.rs_nrates < 10) 327 res->wi_srates[ni->ni_rates.rs_nrates] = 0; 328 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate]; 329 res->wi_rsvd = 0; 330 res++, i++; 331 } 332 p2->wi_rsvd = 0; 333 p2->wi_reason = i; 334 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2; 335 break; 336 case WI_RID_READ_CACHE: 337 i = 0; 338 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 339 if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1) 340 break; 341 IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr); 342 memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc)); 343 wsc.signal = (*ic->ic_node_getrssi)(ic, ni); 344 wsc.noise = 0; 345 wsc.quality = 0; 346 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i, 347 &wsc, sizeof(wsc)); 348 i++; 349 } 350 wreq.wi_len = sizeof(wsc) * i / 2; 351 break; 352 case WI_RID_SCAN_APS: 353 error = EINVAL; 354 break; 355 default: 356 error = EINVAL; 357 break; 358 } 359 if (error == 0) { 360 wreq.wi_len++; 361 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 362 } 363 return error; 364} 365 366static int 367findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) 368{ 369#define IEEERATE(_ic,_m,_i) \ 370 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) 371 int i, nrates = ic->ic_sup_rates[mode].rs_nrates; 372 for (i = 0; i < nrates; i++) 373 if (IEEERATE(ic, mode, i) == rate) 374 return i; 375 return -1; 376#undef IEEERATE 377} 378 379/* 380 * Prepare to do a user-initiated scan for AP's. If no 381 * current/default channel is setup or the current channel 382 * is invalid then pick the first available channel from 383 * the active list as the place to start the scan. 384 */ 385static int 386ieee80211_setupscan(struct ieee80211com *ic) 387{ 388 u_char *chanlist = ic->ic_chan_active; 389 int i; 390 391 if (ic->ic_ibss_chan == NULL || 392 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 393 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) 394 if (isset(chanlist, i)) { 395 ic->ic_ibss_chan = &ic->ic_channels[i]; 396 goto found; 397 } 398 return EINVAL; /* no active channels */ 399found: 400 ; 401 } 402 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC || 403 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan))) 404 ic->ic_bss->ni_chan = ic->ic_ibss_chan; 405 /* 406 * XXX don't permit a scan to be started unless we 407 * know the device is ready. For the moment this means 408 * the device is marked up as this is the required to 409 * initialize the hardware. It would be better to permit 410 * scanning prior to being up but that'll require some 411 * changes to the infrastructure. 412 */ 413 return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET; 414} 415 416int 417ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data) 418{ 419 struct ieee80211com *ic = (void *)ifp; 420 int i, j, len, error, rate; 421 struct ifreq *ifr = (struct ifreq *)data; 422 struct wi_ltv_keys *keys; 423 struct wi_req wreq; 424 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)]; 425 426 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 427 if (error) 428 return error; 429 len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0; 430 switch (wreq.wi_type) { 431 case WI_RID_SERIALNO: 432 case WI_RID_NODENAME: 433 return EPERM; 434 case WI_RID_CURRENT_SSID: 435 return EPERM; 436 case WI_RID_OWN_SSID: 437 case WI_RID_DESIRED_SSID: 438 if (le16toh(wreq.wi_val[0]) * 2 > len || 439 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) { 440 error = ENOSPC; 441 break; 442 } 443 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid)); 444 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2; 445 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen); 446 error = ENETRESET; 447 break; 448 case WI_RID_CURRENT_BSSID: 449 return EPERM; 450 case WI_RID_OWN_CHNL: 451 if (len != 2) 452 return EINVAL; 453 i = le16toh(wreq.wi_val[0]); 454 if (i < 0 || 455 i > IEEE80211_CHAN_MAX || 456 isclr(ic->ic_chan_active, i)) 457 return EINVAL; 458 ic->ic_ibss_chan = &ic->ic_channels[i]; 459 if (ic->ic_flags & IEEE80211_F_SIBSS) 460 error = ENETRESET; 461 break; 462 case WI_RID_CURRENT_CHAN: 463 return EPERM; 464 case WI_RID_COMMS_QUALITY: 465 return EPERM; 466 case WI_RID_PROMISC: 467 if (len != 2) 468 return EINVAL; 469 if (ifp->if_flags & IFF_PROMISC) { 470 if (wreq.wi_val[0] == 0) { 471 ifp->if_flags &= ~IFF_PROMISC; 472 error = ENETRESET; 473 } 474 } else { 475 if (wreq.wi_val[0] != 0) { 476 ifp->if_flags |= IFF_PROMISC; 477 error = ENETRESET; 478 } 479 } 480 break; 481 case WI_RID_PORTTYPE: 482 if (len != 2) 483 return EINVAL; 484 switch (le16toh(wreq.wi_val[0])) { 485 case IEEE80211_M_STA: 486 break; 487 case IEEE80211_M_IBSS: 488 if (!(ic->ic_caps & IEEE80211_C_IBSS)) 489 return EINVAL; 490 break; 491 case IEEE80211_M_AHDEMO: 492 if (ic->ic_phytype != IEEE80211_T_DS || 493 !(ic->ic_caps & IEEE80211_C_AHDEMO)) 494 return EINVAL; 495 break; 496 case IEEE80211_M_HOSTAP: 497 if (!(ic->ic_caps & IEEE80211_C_HOSTAP)) 498 return EINVAL; 499 break; 500 default: 501 return EINVAL; 502 } 503 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) { 504 ic->ic_opmode = le16toh(wreq.wi_val[0]); 505 error = ENETRESET; 506 } 507 break; 508#if 0 509 case WI_RID_MAC_NODE: 510 if (len != IEEE80211_ADDR_LEN) 511 return EINVAL; 512 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val); 513 /* if_init will copy lladdr into ic_myaddr */ 514 error = ENETRESET; 515 break; 516#endif 517 case WI_RID_TX_RATE: 518 if (len != 2) 519 return EINVAL; 520 if (wreq.wi_val[0] == 0) { 521 /* auto */ 522 ic->ic_fixed_rate = -1; 523 break; 524 } 525 rate = 2 * le16toh(wreq.wi_val[0]); 526 if (ic->ic_curmode == IEEE80211_MODE_AUTO) { 527 /* 528 * In autoselect mode search for the rate. We take 529 * the first instance which may not be right, but we 530 * are limited by the interface. Note that we also 531 * lock the mode to insure the rate is meaningful 532 * when it is used. 533 */ 534 for (j = IEEE80211_MODE_11A; 535 j < IEEE80211_MODE_MAX; j++) { 536 if ((ic->ic_modecaps & (1<<j)) == 0) 537 continue; 538 i = findrate(ic, j, rate); 539 if (i != -1) { 540 /* lock mode too */ 541 ic->ic_curmode = j; 542 goto setrate; 543 } 544 } 545 } else { 546 i = findrate(ic, ic->ic_curmode, rate); 547 if (i != -1) 548 goto setrate; 549 } 550 return EINVAL; 551 setrate: 552 ic->ic_fixed_rate = i; 553 error = ENETRESET; 554 break; 555 case WI_RID_CUR_TX_RATE: 556 return EPERM; 557 case WI_RID_RTS_THRESH: 558 if (len != 2) 559 return EINVAL; 560 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN) 561 return EINVAL; /* TODO: RTS */ 562 break; 563 case WI_RID_CREATE_IBSS: 564 if (len != 2) 565 return EINVAL; 566 if (wreq.wi_val[0] != 0) { 567 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) 568 return EINVAL; 569 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 570 ic->ic_flags |= IEEE80211_F_IBSSON; 571 if (ic->ic_opmode == IEEE80211_M_IBSS && 572 ic->ic_state == IEEE80211_S_SCAN) 573 error = ENETRESET; 574 } 575 } else { 576 if (ic->ic_flags & IEEE80211_F_IBSSON) { 577 ic->ic_flags &= ~IEEE80211_F_IBSSON; 578 if (ic->ic_flags & IEEE80211_F_SIBSS) { 579 ic->ic_flags &= ~IEEE80211_F_SIBSS; 580 error = ENETRESET; 581 } 582 } 583 } 584 break; 585 case WI_RID_MICROWAVE_OVEN: 586 if (len != 2) 587 return EINVAL; 588 if (wreq.wi_val[0] != 0) 589 return EINVAL; /* not supported */ 590 break; 591 case WI_RID_ROAMING_MODE: 592 if (len != 2) 593 return EINVAL; 594 if (le16toh(wreq.wi_val[0]) != 1) 595 return EINVAL; /* not supported */ 596 break; 597 case WI_RID_SYSTEM_SCALE: 598 if (len != 2) 599 return EINVAL; 600 if (le16toh(wreq.wi_val[0]) != 1) 601 return EINVAL; /* not supported */ 602 break; 603 case WI_RID_PM_ENABLED: 604 if (len != 2) 605 return EINVAL; 606 if (wreq.wi_val[0] != 0) { 607 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 608 return EINVAL; 609 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 610 ic->ic_flags |= IEEE80211_F_PMGTON; 611 error = ENETRESET; 612 } 613 } else { 614 if (ic->ic_flags & IEEE80211_F_PMGTON) { 615 ic->ic_flags &= ~IEEE80211_F_PMGTON; 616 error = ENETRESET; 617 } 618 } 619 break; 620 case WI_RID_MAX_SLEEP: 621 if (len != 2) 622 return EINVAL; 623 ic->ic_lintval = le16toh(wreq.wi_val[0]); 624 if (ic->ic_flags & IEEE80211_F_PMGTON) 625 error = ENETRESET; 626 break; 627 case WI_RID_CUR_BEACON_INT: 628 return EPERM; 629 case WI_RID_WEP_AVAIL: 630 return EPERM; 631 case WI_RID_CNFAUTHMODE: 632 if (len != 2) 633 return EINVAL; 634 if (le16toh(wreq.wi_val[0]) != 1) 635 return EINVAL; /* TODO: shared key auth */ 636 break; 637 case WI_RID_ENCRYPTION: 638 if (len != 2) 639 return EINVAL; 640 if (wreq.wi_val[0] != 0) { 641 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 642 return EINVAL; 643 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) { 644 ic->ic_flags |= IEEE80211_F_WEPON; 645 error = ENETRESET; 646 } 647 } else { 648 if (ic->ic_flags & IEEE80211_F_WEPON) { 649 ic->ic_flags &= ~IEEE80211_F_WEPON; 650 error = ENETRESET; 651 } 652 } 653 break; 654 case WI_RID_TX_CRYPT_KEY: 655 if (len != 2) 656 return EINVAL; 657 i = le16toh(wreq.wi_val[0]); 658 if (i >= IEEE80211_WEP_NKID) 659 return EINVAL; 660 ic->ic_wep_txkey = i; 661 break; 662 case WI_RID_DEFLT_CRYPT_KEYS: 663 if (len != sizeof(struct wi_ltv_keys)) 664 return EINVAL; 665 keys = (struct wi_ltv_keys *)&wreq; 666 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 667 len = le16toh(keys->wi_keys[i].wi_keylen); 668 if (len != 0 && len < IEEE80211_WEP_KEYLEN) 669 return EINVAL; 670 if (len > sizeof(ic->ic_nw_keys[i].wk_key)) 671 return EINVAL; 672 } 673 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys)); 674 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 675 len = le16toh(keys->wi_keys[i].wi_keylen); 676 ic->ic_nw_keys[i].wk_len = len; 677 memcpy(ic->ic_nw_keys[i].wk_key, 678 keys->wi_keys[i].wi_keydat, len); 679 } 680 error = ENETRESET; 681 break; 682 case WI_RID_MAX_DATALEN: 683 if (len != 2) 684 return EINVAL; 685 len = le16toh(wreq.wi_val[0]); 686 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN) 687 return EINVAL; 688 if (len != IEEE80211_MAX_LEN) 689 return EINVAL; /* TODO: fragment */ 690 ic->ic_fragthreshold = len; 691 error = ENETRESET; 692 break; 693 case WI_RID_IFACE_STATS: 694 error = EPERM; 695 break; 696 case WI_RID_SCAN_REQ: /* XXX wicontrol */ 697 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 698 break; 699 error = ieee80211_setupscan(ic); 700 if (error == 0) 701 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 702 break; 703 case WI_RID_SCAN_APS: 704 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 705 break; 706 len--; /* XXX: tx rate? */ 707 /* FALLTHRU */ 708 case WI_RID_CHANNEL_LIST: 709 memset(chanlist, 0, sizeof(chanlist)); 710 /* 711 * Since channel 0 is not available for DS, channel 1 712 * is assigned to LSB on WaveLAN. 713 */ 714 if (ic->ic_phytype == IEEE80211_T_DS) 715 i = 1; 716 else 717 i = 0; 718 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { 719 if ((j / 8) >= len) 720 break; 721 if (isclr((u_int8_t *)wreq.wi_val, j)) 722 continue; 723 if (isclr(ic->ic_chan_active, i)) { 724 if (wreq.wi_type != WI_RID_CHANNEL_LIST) 725 continue; 726 if (isclr(ic->ic_chan_avail, i)) 727 return EPERM; 728 } 729 setbit(chanlist, i); 730 } 731 memcpy(ic->ic_chan_active, chanlist, 732 sizeof(ic->ic_chan_active)); 733 error = ieee80211_setupscan(ic); 734 if (wreq.wi_type == WI_RID_CHANNEL_LIST) { 735 /* NB: ignore error from ieee80211_setupscan */ 736 error = ENETRESET; 737 } else if (error == 0) 738 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 739 break; 740 default: 741 error = EINVAL; 742 break; 743 } 744 return error; 745} 746 747int 748ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 749{ 750 struct ieee80211com *ic = (void *)ifp; 751 int error = 0; 752 u_int kid, len; 753 struct ieee80211req *ireq; 754 struct ifreq *ifr; 755 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; 756 char tmpssid[IEEE80211_NWID_LEN]; 757 struct ieee80211_channel *chan; 758 759 switch (cmd) { 760 case SIOCSIFMEDIA: 761 case SIOCGIFMEDIA: 762 error = ifmedia_ioctl(ifp, (struct ifreq *) data, 763 &ic->ic_media, cmd); 764 break; 765 case SIOCG80211: 766 ireq = (struct ieee80211req *) data; 767 switch (ireq->i_type) { 768 case IEEE80211_IOC_SSID: 769 switch (ic->ic_state) { 770 case IEEE80211_S_INIT: 771 case IEEE80211_S_SCAN: 772 ireq->i_len = ic->ic_des_esslen; 773 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len); 774 break; 775 default: 776 ireq->i_len = ic->ic_bss->ni_esslen; 777 memcpy(tmpssid, ic->ic_bss->ni_essid, 778 ireq->i_len); 779 break; 780 } 781 error = copyout(tmpssid, ireq->i_data, ireq->i_len); 782 break; 783 case IEEE80211_IOC_NUMSSIDS: 784 ireq->i_val = 1; 785 break; 786 case IEEE80211_IOC_WEP: 787 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 788 ireq->i_val = IEEE80211_WEP_NOSUP; 789 } else { 790 if (ic->ic_flags & IEEE80211_F_WEPON) { 791 ireq->i_val = 792 IEEE80211_WEP_MIXED; 793 } else { 794 ireq->i_val = 795 IEEE80211_WEP_OFF; 796 } 797 } 798 break; 799 case IEEE80211_IOC_WEPKEY: 800 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 801 error = EINVAL; 802 break; 803 } 804 kid = (u_int) ireq->i_val; 805 if (kid >= IEEE80211_WEP_NKID) { 806 error = EINVAL; 807 break; 808 } 809 len = (u_int) ic->ic_nw_keys[kid].wk_len; 810 /* NB: only root can read WEP keys */ 811 if (suser(curthread) == 0) { 812 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len); 813 } else { 814 bzero(tmpkey, len); 815 } 816 ireq->i_len = len; 817 error = copyout(tmpkey, ireq->i_data, len); 818 break; 819 case IEEE80211_IOC_NUMWEPKEYS: 820 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 821 error = EINVAL; 822 else 823 ireq->i_val = IEEE80211_WEP_NKID; 824 break; 825 case IEEE80211_IOC_WEPTXKEY: 826 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 827 error = EINVAL; 828 else 829 ireq->i_val = ic->ic_wep_txkey; 830 break; 831 case IEEE80211_IOC_AUTHMODE: 832 ireq->i_val = IEEE80211_AUTH_OPEN; 833 break; 834 case IEEE80211_IOC_CHANNEL: 835 switch (ic->ic_state) { 836 case IEEE80211_S_INIT: 837 case IEEE80211_S_SCAN: 838 if (ic->ic_opmode == IEEE80211_M_STA) 839 chan = ic->ic_des_chan; 840 else 841 chan = ic->ic_ibss_chan; 842 break; 843 default: 844 chan = ic->ic_bss->ni_chan; 845 break; 846 } 847 ireq->i_val = ieee80211_chan2ieee(ic, chan); 848 break; 849 case IEEE80211_IOC_POWERSAVE: 850 if (ic->ic_flags & IEEE80211_F_PMGTON) 851 ireq->i_val = IEEE80211_POWERSAVE_ON; 852 else 853 ireq->i_val = IEEE80211_POWERSAVE_OFF; 854 break; 855 case IEEE80211_IOC_POWERSAVESLEEP: 856 ireq->i_val = ic->ic_lintval; 857 break; 858 case IEEE80211_IOC_RTSTHRESHOLD: 859 ireq->i_val = ic->ic_rtsthreshold; 860 break; 861 default: 862 error = EINVAL; 863 } 864 break; 865 case SIOCS80211: 866 error = suser(curthread); 867 if (error) 868 break; 869 ireq = (struct ieee80211req *) data; 870 switch (ireq->i_type) { 871 case IEEE80211_IOC_SSID: 872 if (ireq->i_val != 0 || 873 ireq->i_len > IEEE80211_NWID_LEN) { 874 error = EINVAL; 875 break; 876 } 877 error = copyin(ireq->i_data, tmpssid, ireq->i_len); 878 if (error) 879 break; 880 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); 881 ic->ic_des_esslen = ireq->i_len; 882 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len); 883 error = ENETRESET; 884 break; 885 case IEEE80211_IOC_WEP: 886 /* 887 * These cards only support one mode so 888 * we just turn wep on if what ever is 889 * passed in is not OFF. 890 */ 891 if (ireq->i_val == IEEE80211_WEP_OFF) { 892 ic->ic_flags &= ~IEEE80211_F_WEPON; 893 } else { 894 ic->ic_flags |= IEEE80211_F_WEPON; 895 } 896 error = ENETRESET; 897 break; 898 case IEEE80211_IOC_WEPKEY: 899 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 900 error = EINVAL; 901 break; 902 } 903 kid = (u_int) ireq->i_val; 904 if (kid >= IEEE80211_WEP_NKID) { 905 error = EINVAL; 906 break; 907 } 908 if (ireq->i_len > sizeof(tmpkey)) { 909 error = EINVAL; 910 break; 911 } 912 memset(tmpkey, 0, sizeof(tmpkey)); 913 error = copyin(ireq->i_data, tmpkey, ireq->i_len); 914 if (error) 915 break; 916 memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey, 917 sizeof(tmpkey)); 918 ic->ic_nw_keys[kid].wk_len = ireq->i_len; 919 error = ENETRESET; 920 break; 921 case IEEE80211_IOC_WEPTXKEY: 922 kid = (u_int) ireq->i_val; 923 if (kid >= IEEE80211_WEP_NKID) { 924 error = EINVAL; 925 break; 926 } 927 ic->ic_wep_txkey = kid; 928 error = ENETRESET; 929 break; 930#if 0 931 case IEEE80211_IOC_AUTHMODE: 932 sc->wi_authmode = ireq->i_val; 933 break; 934#endif 935 case IEEE80211_IOC_CHANNEL: 936 /* XXX 0xffff overflows 16-bit signed */ 937 if (ireq->i_val == 0 || 938 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) 939 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 940 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX || 941 isclr(ic->ic_chan_active, ireq->i_val)) { 942 error = EINVAL; 943 break; 944 } else 945 ic->ic_ibss_chan = ic->ic_des_chan = 946 &ic->ic_channels[ireq->i_val]; 947 switch (ic->ic_state) { 948 case IEEE80211_S_INIT: 949 case IEEE80211_S_SCAN: 950 error = ENETRESET; 951 break; 952 default: 953 if (ic->ic_opmode == IEEE80211_M_STA) { 954 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 955 ic->ic_bss->ni_chan != ic->ic_des_chan) 956 error = ENETRESET; 957 } else { 958 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) 959 error = ENETRESET; 960 } 961 break; 962 } 963 break; 964 case IEEE80211_IOC_POWERSAVE: 965 switch (ireq->i_val) { 966 case IEEE80211_POWERSAVE_OFF: 967 if (ic->ic_flags & IEEE80211_F_PMGTON) { 968 ic->ic_flags &= ~IEEE80211_F_PMGTON; 969 error = ENETRESET; 970 } 971 break; 972 case IEEE80211_POWERSAVE_ON: 973 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 974 error = EINVAL; 975 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 976 ic->ic_flags |= IEEE80211_F_PMGTON; 977 error = ENETRESET; 978 } 979 break; 980 default: 981 error = EINVAL; 982 break; 983 } 984 break; 985 case IEEE80211_IOC_POWERSAVESLEEP: 986 if (ireq->i_val < 0) { 987 error = EINVAL; 988 break; 989 } 990 ic->ic_lintval = ireq->i_val; 991 error = ENETRESET; 992 break; 993 case IEEE80211_IOC_RTSTHRESHOLD: 994 if (!(IEEE80211_RTS_MIN < ireq->i_val && 995 ireq->i_val < IEEE80211_RTS_MAX)) { 996 error = EINVAL; 997 break; 998 } 999 ic->ic_rtsthreshold = ireq->i_val; 1000 error = ENETRESET; 1001 break; 1002 default: 1003 error = EINVAL; 1004 break; 1005 } 1006 break; 1007 case SIOCGIFGENERIC: 1008 error = ieee80211_cfgget(ifp, cmd, data); 1009 break; 1010 case SIOCSIFGENERIC: 1011 error = suser(curthread); 1012 if (error) 1013 break; 1014 error = ieee80211_cfgset(ifp, cmd, data); 1015 break; 1016 case SIOCG80211STATS: 1017 ifr = (struct ifreq *)data; 1018 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats)); 1019 break; 1020 case SIOCSIFMTU: 1021 ifr = (struct ifreq *)data; 1022 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu && 1023 ifr->ifr_mtu <= IEEE80211_MTU_MAX)) 1024 error = EINVAL; 1025 else 1026 ifp->if_mtu = ifr->ifr_mtu; 1027 break; 1028 default: 1029 error = ether_ioctl(ifp, cmd, data); 1030 break; 1031 } 1032 return error; 1033} 1034