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$"); 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 63 int 64 ieee80211_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 366 static int 367 findrate(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 int 380 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data) 381 { 382 struct ieee80211com *ic = (void *)ifp; 383 int i, j, len, error, rate; 384 struct ifreq *ifr = (struct ifreq *)data; 385 struct wi_ltv_keys *keys; 386 struct wi_req wreq; 387 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)]; 388 389 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 390 if (error) 391 return error; 392 len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0; 393 switch (wreq.wi_type) { 394 case WI_RID_SERIALNO: 395 case WI_RID_NODENAME: 396 return EPERM; 397 case WI_RID_CURRENT_SSID: 398 return EPERM; 399 case WI_RID_OWN_SSID: 400 case WI_RID_DESIRED_SSID: 401 if (le16toh(wreq.wi_val[0]) * 2 > len || 402 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) { 403 error = ENOSPC; 404 break; 405 } 406 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid)); 407 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2; 408 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen); 409 error = ENETRESET; 410 break; 411 case WI_RID_CURRENT_BSSID: 412 return EPERM; 413 case WI_RID_OWN_CHNL: 414 if (len != 2) 415 return EINVAL; 416 i = le16toh(wreq.wi_val[0]); 417 if (i < 0 || 418 i > IEEE80211_CHAN_MAX || 419 isclr(ic->ic_chan_active, i)) 420 return EINVAL; 421 ic->ic_ibss_chan = &ic->ic_channels[i]; 422 if (ic->ic_flags & IEEE80211_F_SIBSS) 423 error = ENETRESET; 424 break; 425 case WI_RID_CURRENT_CHAN: 426 return EPERM; 427 case WI_RID_COMMS_QUALITY: 428 return EPERM; 429 case WI_RID_PROMISC: 430 if (len != 2) 431 return EINVAL; 432 if (ifp->if_flags & IFF_PROMISC) { 433 if (wreq.wi_val[0] == 0) { 434 ifp->if_flags &= ~IFF_PROMISC; 435 error = ENETRESET; 436 } 437 } else { 438 if (wreq.wi_val[0] != 0) { 439 ifp->if_flags |= IFF_PROMISC; 440 error = ENETRESET; 441 } 442 } 443 break; 444 case WI_RID_PORTTYPE: 445 if (len != 2) 446 return EINVAL; 447 switch (le16toh(wreq.wi_val[0])) { 448 case IEEE80211_M_STA: 449 break; 450 case IEEE80211_M_IBSS: 451 if (!(ic->ic_caps & IEEE80211_C_IBSS)) 452 return EINVAL; 453 break; 454 case IEEE80211_M_AHDEMO: 455 if (ic->ic_phytype != IEEE80211_T_DS || 456 !(ic->ic_caps & IEEE80211_C_AHDEMO)) 457 return EINVAL; 458 break; 459 case IEEE80211_M_HOSTAP: 460 if (!(ic->ic_caps & IEEE80211_C_HOSTAP)) 461 return EINVAL; 462 break; 463 default: 464 return EINVAL; 465 } 466 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) { 467 ic->ic_opmode = le16toh(wreq.wi_val[0]); 468 error = ENETRESET; 469 } 470 break; 471 #if 0 472 case WI_RID_MAC_NODE: 473 if (len != IEEE80211_ADDR_LEN) 474 return EINVAL; 475 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val); 476 /* if_init will copy lladdr into ic_myaddr */ 477 error = ENETRESET; 478 break; 479 #endif 480 case WI_RID_TX_RATE: 481 if (len != 2) 482 return EINVAL; 483 if (wreq.wi_val[0] == 0) { 484 /* auto */ 485 ic->ic_fixed_rate = -1; 486 break; 487 } 488 rate = 2 * le16toh(wreq.wi_val[0]); 489 if (ic->ic_curmode == IEEE80211_MODE_AUTO) { 490 /* 491 * In autoselect mode search for the rate. We take 492 * the first instance which may not be right, but we 493 * are limited by the interface. Note that we also 494 * lock the mode to insure the rate is meaningful 495 * when it is used. 496 */ 497 for (j = IEEE80211_MODE_11A; 498 j < IEEE80211_MODE_MAX; j++) { 499 if ((ic->ic_modecaps & (1<<j)) == 0) 500 continue; 501 i = findrate(ic, j, rate); 502 if (i != -1) { 503 /* lock mode too */ 504 ic->ic_curmode = j; 505 goto setrate; 506 } 507 } 508 } else { 509 i = findrate(ic, ic->ic_curmode, rate); 510 if (i != -1) 511 goto setrate; 512 } 513 return EINVAL; 514 setrate: 515 ic->ic_fixed_rate = i; 516 error = ENETRESET; 517 break; 518 case WI_RID_CUR_TX_RATE: 519 return EPERM; 520 case WI_RID_RTS_THRESH: 521 if (len != 2) 522 return EINVAL; 523 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN) 524 return EINVAL; /* TODO: RTS */ 525 break; 526 case WI_RID_CREATE_IBSS: 527 if (len != 2) 528 return EINVAL; 529 if (wreq.wi_val[0] != 0) { 530 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) 531 return EINVAL; 532 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 533 ic->ic_flags |= IEEE80211_F_IBSSON; 534 if (ic->ic_opmode == IEEE80211_M_IBSS && 535 ic->ic_state == IEEE80211_S_SCAN) 536 error = ENETRESET; 537 } 538 } else { 539 if (ic->ic_flags & IEEE80211_F_IBSSON) { 540 ic->ic_flags &= ~IEEE80211_F_IBSSON; 541 if (ic->ic_flags & IEEE80211_F_SIBSS) { 542 ic->ic_flags &= ~IEEE80211_F_SIBSS; 543 error = ENETRESET; 544 } 545 } 546 } 547 break; 548 case WI_RID_MICROWAVE_OVEN: 549 if (len != 2) 550 return EINVAL; 551 if (wreq.wi_val[0] != 0) 552 return EINVAL; /* not supported */ 553 break; 554 case WI_RID_ROAMING_MODE: 555 if (len != 2) 556 return EINVAL; 557 if (le16toh(wreq.wi_val[0]) != 1) 558 return EINVAL; /* not supported */ 559 break; 560 case WI_RID_SYSTEM_SCALE: 561 if (len != 2) 562 return EINVAL; 563 if (le16toh(wreq.wi_val[0]) != 1) 564 return EINVAL; /* not supported */ 565 break; 566 case WI_RID_PM_ENABLED: 567 if (len != 2) 568 return EINVAL; 569 if (wreq.wi_val[0] != 0) { 570 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 571 return EINVAL; 572 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 573 ic->ic_flags |= IEEE80211_F_PMGTON; 574 error = ENETRESET; 575 } 576 } else { 577 if (ic->ic_flags & IEEE80211_F_PMGTON) { 578 ic->ic_flags &= ~IEEE80211_F_PMGTON; 579 error = ENETRESET; 580 } 581 } 582 break; 583 case WI_RID_MAX_SLEEP: 584 if (len != 2) 585 return EINVAL; 586 ic->ic_lintval = le16toh(wreq.wi_val[0]); 587 if (ic->ic_flags & IEEE80211_F_PMGTON) 588 error = ENETRESET; 589 break; 590 case WI_RID_CUR_BEACON_INT: 591 return EPERM; 592 case WI_RID_WEP_AVAIL: 593 return EPERM; 594 case WI_RID_CNFAUTHMODE: 595 if (len != 2) 596 return EINVAL; 597 if (le16toh(wreq.wi_val[0]) != 1) 598 return EINVAL; /* TODO: shared key auth */ 599 break; 600 case WI_RID_ENCRYPTION: 601 if (len != 2) 602 return EINVAL; 603 if (wreq.wi_val[0] != 0) { 604 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 605 return EINVAL; 606 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) { 607 ic->ic_flags |= IEEE80211_F_WEPON; 608 error = ENETRESET; 609 } 610 } else { 611 if (ic->ic_flags & IEEE80211_F_WEPON) { 612 ic->ic_flags &= ~IEEE80211_F_WEPON; 613 error = ENETRESET; 614 } 615 } 616 break; 617 case WI_RID_TX_CRYPT_KEY: 618 if (len != 2) 619 return EINVAL; 620 i = le16toh(wreq.wi_val[0]); 621 if (i >= IEEE80211_WEP_NKID) 622 return EINVAL; 623 ic->ic_wep_txkey = i; 624 break; 625 case WI_RID_DEFLT_CRYPT_KEYS: 626 if (len != sizeof(struct wi_ltv_keys)) 627 return EINVAL; 628 keys = (struct wi_ltv_keys *)&wreq; 629 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 630 len = le16toh(keys->wi_keys[i].wi_keylen); 631 if (len != 0 && len < IEEE80211_WEP_KEYLEN) 632 return EINVAL; 633 if (len > sizeof(ic->ic_nw_keys[i].wk_key)) 634 return EINVAL; 635 } 636 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys)); 637 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 638 len = le16toh(keys->wi_keys[i].wi_keylen); 639 ic->ic_nw_keys[i].wk_len = len; 640 memcpy(ic->ic_nw_keys[i].wk_key, 641 keys->wi_keys[i].wi_keydat, len); 642 } 643 error = ENETRESET; 644 break; 645 case WI_RID_MAX_DATALEN: 646 if (len != 2) 647 return EINVAL; 648 len = le16toh(wreq.wi_val[0]); 649 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN) 650 return EINVAL; 651 if (len != IEEE80211_MAX_LEN) 652 return EINVAL; /* TODO: fragment */ 653 ic->ic_fragthreshold = len; 654 error = ENETRESET; 655 break; 656 case WI_RID_IFACE_STATS: 657 error = EPERM; 658 break; 659 case WI_RID_SCAN_REQ: /* XXX wicontrol */ 660 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 661 break; 662 /* NB: ignore channel list and tx rate parameters */ 663 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 664 break; 665 case WI_RID_SCAN_APS: 666 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 667 break; 668 len--; /* XXX: tx rate? */ 669 /* FALLTHRU */ 670 case WI_RID_CHANNEL_LIST: 671 memset(chanlist, 0, sizeof(chanlist)); 672 /* 673 * Since channel 0 is not available for DS, channel 1 674 * is assigned to LSB on WaveLAN. 675 */ 676 if (ic->ic_phytype == IEEE80211_T_DS) 677 i = 1; 678 else 679 i = 0; 680 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { 681 if ((j / 8) >= len) 682 break; 683 if (isclr((u_int8_t *)wreq.wi_val, j)) 684 continue; 685 if (isclr(ic->ic_chan_active, i)) { 686 if (wreq.wi_type != WI_RID_CHANNEL_LIST) 687 continue; 688 if (isclr(ic->ic_chan_avail, i)) 689 return EPERM; 690 } 691 setbit(chanlist, i); 692 } 693 memcpy(ic->ic_chan_active, chanlist, 694 sizeof(ic->ic_chan_active)); 695 if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 696 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) 697 if (isset(chanlist, i)) { 698 ic->ic_ibss_chan = &ic->ic_channels[i]; 699 break; 700 } 701 } 702 if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan))) 703 ic->ic_bss->ni_chan = ic->ic_ibss_chan; 704 if (wreq.wi_type == WI_RID_CHANNEL_LIST) 705 error = ENETRESET; 706 else 707 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 708 break; 709 default: 710 error = EINVAL; 711 break; 712 } 713 return error; 714 } 715 716 int 717 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 718 { 719 struct ieee80211com *ic = (void *)ifp; 720 int error = 0; 721 u_int kid, len; 722 struct ieee80211req *ireq; 723 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; 724 char tmpssid[IEEE80211_NWID_LEN]; 725 struct ieee80211_channel *chan; 726 727 switch (cmd) { 728 case SIOCSIFMEDIA: 729 case SIOCGIFMEDIA: 730 error = ifmedia_ioctl(ifp, (struct ifreq *) data, 731 &ic->ic_media, cmd); 732 break; 733 case SIOCG80211: 734 ireq = (struct ieee80211req *) data; 735 switch (ireq->i_type) { 736 case IEEE80211_IOC_SSID: 737 switch (ic->ic_state) { 738 case IEEE80211_S_INIT: 739 case IEEE80211_S_SCAN: 740 ireq->i_len = ic->ic_des_esslen; 741 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len); 742 break; 743 default: 744 ireq->i_len = ic->ic_bss->ni_esslen; 745 memcpy(tmpssid, ic->ic_bss->ni_essid, 746 ireq->i_len); 747 break; 748 } 749 error = copyout(tmpssid, ireq->i_data, ireq->i_len); 750 break; 751 case IEEE80211_IOC_NUMSSIDS: 752 ireq->i_val = 1; 753 break; 754 case IEEE80211_IOC_WEP: 755 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 756 ireq->i_val = IEEE80211_WEP_NOSUP; 757 } else { 758 if (ic->ic_flags & IEEE80211_F_WEPON) { 759 ireq->i_val = 760 IEEE80211_WEP_MIXED; 761 } else { 762 ireq->i_val = 763 IEEE80211_WEP_OFF; 764 } 765 } 766 break; 767 case IEEE80211_IOC_WEPKEY: 768 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 769 error = EINVAL; 770 break; 771 } 772 kid = (u_int) ireq->i_val; 773 if (kid >= IEEE80211_WEP_NKID) { 774 error = EINVAL; 775 break; 776 } 777 len = (u_int) ic->ic_nw_keys[kid].wk_len; 778 /* NB: only root can read WEP keys */ 779 if (suser(curthread)) { 780 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len); 781 } else { 782 bzero(tmpkey, len); 783 } 784 ireq->i_len = len; 785 error = copyout(tmpkey, ireq->i_data, len); 786 break; 787 case IEEE80211_IOC_NUMWEPKEYS: 788 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 789 error = EINVAL; 790 else 791 ireq->i_val = IEEE80211_WEP_NKID; 792 break; 793 case IEEE80211_IOC_WEPTXKEY: 794 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 795 error = EINVAL; 796 else 797 ireq->i_val = ic->ic_wep_txkey; 798 break; 799 case IEEE80211_IOC_AUTHMODE: 800 ireq->i_val = IEEE80211_AUTH_OPEN; 801 break; 802 case IEEE80211_IOC_CHANNEL: 803 switch (ic->ic_state) { 804 case IEEE80211_S_INIT: 805 case IEEE80211_S_SCAN: 806 if (ic->ic_opmode == IEEE80211_M_STA) 807 chan = ic->ic_des_chan; 808 else 809 chan = ic->ic_ibss_chan; 810 break; 811 default: 812 chan = ic->ic_bss->ni_chan; 813 break; 814 } 815 ireq->i_val = ieee80211_chan2ieee(ic, chan); 816 break; 817 case IEEE80211_IOC_POWERSAVE: 818 if (ic->ic_flags & IEEE80211_F_PMGTON) 819 ireq->i_val = IEEE80211_POWERSAVE_ON; 820 else 821 ireq->i_val = IEEE80211_POWERSAVE_OFF; 822 break; 823 case IEEE80211_IOC_POWERSAVESLEEP: 824 ireq->i_val = ic->ic_lintval; 825 break; 826 case IEEE80211_IOCT_RTSTHRESHOLD: 827 ireq->i_val = ic->ic_rtsthreshold; 828 break; 829 default: 830 error = EINVAL; 831 } 832 break; 833 case SIOCS80211: 834 error = suser(curthread); 835 if (error) 836 break; 837 ireq = (struct ieee80211req *) data; 838 switch (ireq->i_type) { 839 case IEEE80211_IOC_SSID: 840 if (ireq->i_val != 0 || 841 ireq->i_len > IEEE80211_NWID_LEN) { 842 error = EINVAL; 843 break; 844 } 845 error = copyin(ireq->i_data, tmpssid, ireq->i_len); 846 if (error) 847 break; 848 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); 849 ic->ic_des_esslen = ireq->i_len; 850 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len); 851 error = ENETRESET; 852 break; 853 case IEEE80211_IOC_WEP: 854 /* 855 * These cards only support one mode so 856 * we just turn wep on if what ever is 857 * passed in is not OFF. 858 */ 859 if (ireq->i_val == IEEE80211_WEP_OFF) { 860 ic->ic_flags &= ~IEEE80211_F_WEPON; 861 } else { 862 ic->ic_flags |= IEEE80211_F_WEPON; 863 } 864 error = ENETRESET; 865 break; 866 case IEEE80211_IOC_WEPKEY: 867 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 868 error = EINVAL; 869 break; 870 } 871 kid = (u_int) ireq->i_val; 872 if (kid >= IEEE80211_WEP_NKID) { 873 error = EINVAL; 874 break; 875 } 876 if (ireq->i_len > sizeof(tmpkey)) { 877 error = EINVAL; 878 break; 879 } 880 memset(tmpkey, 0, sizeof(tmpkey)); 881 error = copyin(ireq->i_data, tmpkey, ireq->i_len); 882 if (error) 883 break; 884 memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey, 885 sizeof(tmpkey)); 886 ic->ic_nw_keys[kid].wk_len = ireq->i_len; 887 error = ENETRESET; 888 break; 889 case IEEE80211_IOC_WEPTXKEY: 890 kid = (u_int) ireq->i_val; 891 if (kid >= IEEE80211_WEP_NKID) { 892 error = EINVAL; 893 break; 894 } 895 ic->ic_wep_txkey = kid; 896 error = ENETRESET; 897 break; 898 #if 0 899 case IEEE80211_IOC_AUTHMODE: 900 sc->wi_authmode = ireq->i_val; 901 break; 902 #endif 903 case IEEE80211_IOC_CHANNEL: 904 /* XXX 0xffff overflows 16-bit signed */ 905 if (ireq->i_val == 0 || 906 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) 907 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 908 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX || 909 isclr(ic->ic_chan_active, ireq->i_val)) { 910 error = EINVAL; 911 break; 912 } else 913 ic->ic_ibss_chan = ic->ic_des_chan = 914 &ic->ic_channels[ireq->i_val]; 915 switch (ic->ic_state) { 916 case IEEE80211_S_INIT: 917 case IEEE80211_S_SCAN: 918 error = ENETRESET; 919 break; 920 default: 921 if (ic->ic_opmode == IEEE80211_M_STA) { 922 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 923 ic->ic_bss->ni_chan != ic->ic_des_chan) 924 error = ENETRESET; 925 } else { 926 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) 927 error = ENETRESET; 928 } 929 break; 930 } 931 break; 932 case IEEE80211_IOC_POWERSAVE: 933 switch (ireq->i_val) { 934 case IEEE80211_POWERSAVE_OFF: 935 if (ic->ic_flags & IEEE80211_F_PMGTON) { 936 ic->ic_flags &= ~IEEE80211_F_PMGTON; 937 error = ENETRESET; 938 } 939 break; 940 case IEEE80211_POWERSAVE_ON: 941 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 942 error = EINVAL; 943 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 944 ic->ic_flags |= IEEE80211_F_PMGTON; 945 error = ENETRESET; 946 } 947 break; 948 default: 949 error = EINVAL; 950 break; 951 } 952 break; 953 case IEEE80211_IOC_POWERSAVESLEEP: 954 if (ireq->i_val < 0) { 955 error = EINVAL; 956 break; 957 } 958 ic->ic_lintval = ireq->i_val; 959 error = ENETRESET; 960 break; 961 case IEEE80211_IOCT_RTSTHRESHOLD: 962 if (!(IEEE80211_RTS_MIN < ireq->i_val && 963 ireq->i_val < IEEE80211_RTS_MAX)) { 964 error = EINVAL; 965 break; 966 } 967 ic->ic_rtsthreshold = ireq->i_val; 968 error = ENETRESET; 969 break; 970 default: 971 error = EINVAL; 972 break; 973 } 974 break; 975 case SIOCGIFGENERIC: 976 error = ieee80211_cfgget(ifp, cmd, data); 977 break; 978 case SIOCSIFGENERIC: 979 error = suser(curthread); 980 if (error) 981 break; 982 error = ieee80211_cfgset(ifp, cmd, data); 983 break; 984 default: 985 error = ether_ioctl(ifp, cmd, data); 986 break; 987 } 988 return error; 989 } 990