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] = htole16(ic->ic_bss->ni_rssi); /* signal */ 144 wreq.wi_val[2] = 0; /* noise */ 145 wreq.wi_len = 3; 146 break; 147 case WI_RID_PROMISC: 148 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0); 149 wreq.wi_len = 1; 150 break; 151 case WI_RID_PORTTYPE: 152 wreq.wi_val[0] = htole16(ic->ic_opmode); 153 wreq.wi_len = 1; 154 break; 155 case WI_RID_MAC_NODE: 156 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr); 157 wreq.wi_len = IEEE80211_ADDR_LEN / 2; 158 break; 159 case WI_RID_TX_RATE: 160 if (ic->ic_fixed_rate == -1) 161 wreq.wi_val[0] = 0; /* auto */ 162 else 163 wreq.wi_val[0] = htole16( 164 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] & 165 IEEE80211_RATE_VAL) / 2); 166 wreq.wi_len = 1; 167 break; 168 case WI_RID_CUR_TX_RATE: 169 wreq.wi_val[0] = htole16( 170 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & 171 IEEE80211_RATE_VAL) / 2); 172 wreq.wi_len = 1; 173 break; 174 case WI_RID_RTS_THRESH: 175 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold); 176 wreq.wi_len = 1; 177 break; 178 case WI_RID_CREATE_IBSS: 179 wreq.wi_val[0] = 180 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0); 181 wreq.wi_len = 1; 182 break; 183 case WI_RID_MICROWAVE_OVEN: 184 wreq.wi_val[0] = 0; /* no ... not supported */ 185 wreq.wi_len = 1; 186 break; 187 case WI_RID_ROAMING_MODE: 188 wreq.wi_val[0] = htole16(1); /* enabled ... not supported */ 189 wreq.wi_len = 1; 190 break; 191 case WI_RID_SYSTEM_SCALE: 192 wreq.wi_val[0] = htole16(1); /* low density ... not supp */ 193 wreq.wi_len = 1; 194 break; 195 case WI_RID_PM_ENABLED: 196 wreq.wi_val[0] = 197 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); 198 wreq.wi_len = 1; 199 break; 200 case WI_RID_MAX_SLEEP: 201 wreq.wi_val[0] = htole16(ic->ic_lintval); 202 wreq.wi_len = 1; 203 break; 204 case WI_RID_CUR_BEACON_INT: 205 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval); 206 wreq.wi_len = 1; 207 break; 208 case WI_RID_WEP_AVAIL: 209 wreq.wi_val[0] = 210 htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0); 211 wreq.wi_len = 1; 212 break; 213 case WI_RID_CNFAUTHMODE: 214 wreq.wi_val[0] = htole16(1); /* TODO: open system only */ 215 wreq.wi_len = 1; 216 break; 217 case WI_RID_ENCRYPTION: 218 wreq.wi_val[0] = 219 htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0); 220 wreq.wi_len = 1; 221 break; 222 case WI_RID_TX_CRYPT_KEY: 223 wreq.wi_val[0] = htole16(ic->ic_wep_txkey); 224 wreq.wi_len = 1; 225 break; 226 case WI_RID_DEFLT_CRYPT_KEYS: 227 keys = (struct wi_ltv_keys *)&wreq; 228 /* do not show keys to non-root user */ 229 error = suser(curthread); 230 if (error) { 231 memset(keys, 0, sizeof(*keys)); 232 error = 0; 233 break; 234 } 235 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 236 keys->wi_keys[i].wi_keylen = 237 htole16(ic->ic_nw_keys[i].wk_len); 238 memcpy(keys->wi_keys[i].wi_keydat, 239 ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len); 240 } 241 wreq.wi_len = sizeof(*keys) / 2; 242 break; 243 case WI_RID_MAX_DATALEN: 244 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */ 245 wreq.wi_len = 1; 246 break; 247 case WI_RID_IFACE_STATS: 248 /* XXX: should be implemented in lower drivers */ 249 break; 250 case WI_RID_READ_APS: 251 if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 252 /* 253 * Don't return results until active scan completes. 254 */ 255 if (ic->ic_state == IEEE80211_S_SCAN && 256 (ic->ic_flags & IEEE80211_F_ASCAN)) { 257 error = EINPROGRESS; 258 break; 259 } 260 } 261 i = 0; 262 ap = (void *)((char *)wreq.wi_val + sizeof(i)); 263 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 264 if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1)) 265 break; 266 memset(ap, 0, sizeof(*ap)); 267 if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 268 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr); 269 ap->namelen = ic->ic_des_esslen; 270 if (ic->ic_des_esslen) 271 memcpy(ap->name, ic->ic_des_essid, 272 ic->ic_des_esslen); 273 } else { 274 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid); 275 ap->namelen = ni->ni_esslen; 276 if (ni->ni_esslen) 277 memcpy(ap->name, ni->ni_essid, 278 ni->ni_esslen); 279 } 280 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan); 281 ap->signal = ni->ni_rssi; 282 ap->capinfo = ni->ni_capinfo; 283 ap->interval = ni->ni_intval; 284 rs = &ni->ni_rates; 285 for (j = 0; j < rs->rs_nrates; j++) { 286 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) { 287 ap->rate = (rs->rs_rates[j] & 288 IEEE80211_RATE_VAL) * 5; /* XXX */ 289 } 290 } 291 i++; 292 ap++; 293 } 294 memcpy(wreq.wi_val, &i, sizeof(i)); 295 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2; 296 break; 297 case WI_RID_PRISM2: 298 wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */ 299 wreq.wi_len = sizeof(u_int16_t) / 2; 300 break; 301 case WI_RID_SCAN_RES: /* compatibility interface */ 302 if (ic->ic_opmode != IEEE80211_M_HOSTAP && 303 ic->ic_state == IEEE80211_S_SCAN) { 304 error = EINPROGRESS; 305 break; 306 } 307 /* NB: we use the Prism2 format so we can return rate info */ 308 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val; 309 res = (void *)&p2[1]; 310 i = 0; 311 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 312 if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1)) 313 break; 314 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan); 315 res->wi_noise = 0; 316 res->wi_signal = ni->ni_rssi; 317 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid); 318 res->wi_interval = ni->ni_intval; 319 res->wi_capinfo = ni->ni_capinfo; 320 res->wi_ssid_len = ni->ni_esslen; 321 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN); 322 /* NB: assumes wi_srates holds <= ni->ni_rates */ 323 memcpy(res->wi_srates, ni->ni_rates.rs_rates, 324 sizeof(res->wi_srates)); 325 if (ni->ni_rates.rs_nrates < 10) 326 res->wi_srates[ni->ni_rates.rs_nrates] = 0; 327 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate]; 328 res->wi_rsvd = 0; 329 res++, i++; 330 } 331 p2->wi_rsvd = 0; 332 p2->wi_reason = i; 333 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2; 334 break; 335 case WI_RID_READ_CACHE: 336 i = 0; 337 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 338 if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1) 339 break; 340 IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr); 341 memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc)); 342 wsc.signal = ni->ni_rssi; 343 wsc.noise = 0; 344 wsc.quality = 0; 345 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i, 346 &wsc, sizeof(wsc)); 347 i++; 348 } 349 wreq.wi_len = sizeof(wsc) * i / 2; 350 break; 351 case WI_RID_SCAN_APS: 352 error = EINVAL; 353 break; 354 default: 355 error = EINVAL; 356 break; 357 } 358 if (error == 0) { 359 wreq.wi_len++; 360 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 361 } 362 return error; 363 } 364 365 static int 366 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) 367 { 368 #define IEEERATE(_ic,_m,_i) \ 369 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) 370 int i, nrates = ic->ic_sup_rates[mode].rs_nrates; 371 for (i = 0; i < nrates; i++) 372 if (IEEERATE(ic, mode, i) == rate) 373 return i; 374 return -1; 375 #undef IEEERATE 376 } 377 378 int 379 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data) 380 { 381 struct ieee80211com *ic = (void *)ifp; 382 int i, j, len, error, rate; 383 struct ifreq *ifr = (struct ifreq *)data; 384 struct wi_ltv_keys *keys; 385 struct wi_req wreq; 386 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)]; 387 388 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 389 if (error) 390 return error; 391 len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0; 392 switch (wreq.wi_type) { 393 case WI_RID_SERIALNO: 394 case WI_RID_NODENAME: 395 return EPERM; 396 case WI_RID_CURRENT_SSID: 397 return EPERM; 398 case WI_RID_OWN_SSID: 399 case WI_RID_DESIRED_SSID: 400 if (le16toh(wreq.wi_val[0]) * 2 > len || 401 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) { 402 error = ENOSPC; 403 break; 404 } 405 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid)); 406 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2; 407 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen); 408 error = ENETRESET; 409 break; 410 case WI_RID_CURRENT_BSSID: 411 return EPERM; 412 case WI_RID_OWN_CHNL: 413 if (len != 2) 414 return EINVAL; 415 i = le16toh(wreq.wi_val[0]); 416 if (i < 0 || 417 i > IEEE80211_CHAN_MAX || 418 isclr(ic->ic_chan_active, i)) 419 return EINVAL; 420 ic->ic_ibss_chan = &ic->ic_channels[i]; 421 if (ic->ic_flags & IEEE80211_F_SIBSS) 422 error = ENETRESET; 423 break; 424 case WI_RID_CURRENT_CHAN: 425 return EPERM; 426 case WI_RID_COMMS_QUALITY: 427 return EPERM; 428 case WI_RID_PROMISC: 429 if (len != 2) 430 return EINVAL; 431 if (ifp->if_flags & IFF_PROMISC) { 432 if (wreq.wi_val[0] == 0) { 433 ifp->if_flags &= ~IFF_PROMISC; 434 error = ENETRESET; 435 } 436 } else { 437 if (wreq.wi_val[0] != 0) { 438 ifp->if_flags |= IFF_PROMISC; 439 error = ENETRESET; 440 } 441 } 442 break; 443 case WI_RID_PORTTYPE: 444 if (len != 2) 445 return EINVAL; 446 switch (le16toh(wreq.wi_val[0])) { 447 case IEEE80211_M_STA: 448 break; 449 case IEEE80211_M_IBSS: 450 if (!(ic->ic_caps & IEEE80211_C_IBSS)) 451 return EINVAL; 452 break; 453 case IEEE80211_M_AHDEMO: 454 if (ic->ic_phytype != IEEE80211_T_DS || 455 !(ic->ic_caps & IEEE80211_C_AHDEMO)) 456 return EINVAL; 457 break; 458 case IEEE80211_M_HOSTAP: 459 if (!(ic->ic_caps & IEEE80211_C_HOSTAP)) 460 return EINVAL; 461 break; 462 default: 463 return EINVAL; 464 } 465 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) { 466 ic->ic_opmode = le16toh(wreq.wi_val[0]); 467 error = ENETRESET; 468 } 469 break; 470 #if 0 471 case WI_RID_MAC_NODE: 472 if (len != IEEE80211_ADDR_LEN) 473 return EINVAL; 474 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val); 475 /* if_init will copy lladdr into ic_myaddr */ 476 error = ENETRESET; 477 break; 478 #endif 479 case WI_RID_TX_RATE: 480 if (len != 2) 481 return EINVAL; 482 if (wreq.wi_val[0] == 0) { 483 /* auto */ 484 ic->ic_fixed_rate = -1; 485 break; 486 } 487 rate = 2 * le16toh(wreq.wi_val[0]); 488 if (ic->ic_curmode == IEEE80211_MODE_AUTO) { 489 /* 490 * In autoselect mode search for the rate. We take 491 * the first instance which may not be right, but we 492 * are limited by the interface. Note that we also 493 * lock the mode to insure the rate is meaningful 494 * when it is used. 495 */ 496 for (j = IEEE80211_MODE_11A; 497 j < IEEE80211_MODE_MAX; j++) { 498 if ((ic->ic_modecaps & (1<<j)) == 0) 499 continue; 500 i = findrate(ic, j, rate); 501 if (i != -1) { 502 /* lock mode too */ 503 ic->ic_curmode = j; 504 goto setrate; 505 } 506 } 507 } else { 508 i = findrate(ic, ic->ic_curmode, rate); 509 if (i != -1) 510 goto setrate; 511 } 512 return EINVAL; 513 setrate: 514 ic->ic_fixed_rate = i; 515 error = ENETRESET; 516 break; 517 case WI_RID_CUR_TX_RATE: 518 return EPERM; 519 case WI_RID_RTS_THRESH: 520 if (len != 2) 521 return EINVAL; 522 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN) 523 return EINVAL; /* TODO: RTS */ 524 break; 525 case WI_RID_CREATE_IBSS: 526 if (len != 2) 527 return EINVAL; 528 if (wreq.wi_val[0] != 0) { 529 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) 530 return EINVAL; 531 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 532 ic->ic_flags |= IEEE80211_F_IBSSON; 533 if (ic->ic_opmode == IEEE80211_M_IBSS && 534 ic->ic_state == IEEE80211_S_SCAN) 535 error = ENETRESET; 536 } 537 } else { 538 if (ic->ic_flags & IEEE80211_F_IBSSON) { 539 ic->ic_flags &= ~IEEE80211_F_IBSSON; 540 if (ic->ic_flags & IEEE80211_F_SIBSS) { 541 ic->ic_flags &= ~IEEE80211_F_SIBSS; 542 error = ENETRESET; 543 } 544 } 545 } 546 break; 547 case WI_RID_MICROWAVE_OVEN: 548 if (len != 2) 549 return EINVAL; 550 if (wreq.wi_val[0] != 0) 551 return EINVAL; /* not supported */ 552 break; 553 case WI_RID_ROAMING_MODE: 554 if (len != 2) 555 return EINVAL; 556 if (le16toh(wreq.wi_val[0]) != 1) 557 return EINVAL; /* not supported */ 558 break; 559 case WI_RID_SYSTEM_SCALE: 560 if (len != 2) 561 return EINVAL; 562 if (le16toh(wreq.wi_val[0]) != 1) 563 return EINVAL; /* not supported */ 564 break; 565 case WI_RID_PM_ENABLED: 566 if (len != 2) 567 return EINVAL; 568 if (wreq.wi_val[0] != 0) { 569 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 570 return EINVAL; 571 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 572 ic->ic_flags |= IEEE80211_F_PMGTON; 573 error = ENETRESET; 574 } 575 } else { 576 if (ic->ic_flags & IEEE80211_F_PMGTON) { 577 ic->ic_flags &= ~IEEE80211_F_PMGTON; 578 error = ENETRESET; 579 } 580 } 581 break; 582 case WI_RID_MAX_SLEEP: 583 if (len != 2) 584 return EINVAL; 585 ic->ic_lintval = le16toh(wreq.wi_val[0]); 586 if (ic->ic_flags & IEEE80211_F_PMGTON) 587 error = ENETRESET; 588 break; 589 case WI_RID_CUR_BEACON_INT: 590 return EPERM; 591 case WI_RID_WEP_AVAIL: 592 return EPERM; 593 case WI_RID_CNFAUTHMODE: 594 if (len != 2) 595 return EINVAL; 596 if (le16toh(wreq.wi_val[0]) != 1) 597 return EINVAL; /* TODO: shared key auth */ 598 break; 599 case WI_RID_ENCRYPTION: 600 if (len != 2) 601 return EINVAL; 602 if (wreq.wi_val[0] != 0) { 603 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 604 return EINVAL; 605 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) { 606 ic->ic_flags |= IEEE80211_F_WEPON; 607 error = ENETRESET; 608 } 609 } else { 610 if (ic->ic_flags & IEEE80211_F_WEPON) { 611 ic->ic_flags &= ~IEEE80211_F_WEPON; 612 error = ENETRESET; 613 } 614 } 615 break; 616 case WI_RID_TX_CRYPT_KEY: 617 if (len != 2) 618 return EINVAL; 619 i = le16toh(wreq.wi_val[0]); 620 if (i >= IEEE80211_WEP_NKID) 621 return EINVAL; 622 ic->ic_wep_txkey = i; 623 break; 624 case WI_RID_DEFLT_CRYPT_KEYS: 625 if (len != sizeof(struct wi_ltv_keys)) 626 return EINVAL; 627 keys = (struct wi_ltv_keys *)&wreq; 628 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 629 len = le16toh(keys->wi_keys[i].wi_keylen); 630 if (len != 0 && len < IEEE80211_WEP_KEYLEN) 631 return EINVAL; 632 if (len > sizeof(ic->ic_nw_keys[i].wk_key)) 633 return EINVAL; 634 } 635 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys)); 636 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 637 len = le16toh(keys->wi_keys[i].wi_keylen); 638 ic->ic_nw_keys[i].wk_len = len; 639 memcpy(ic->ic_nw_keys[i].wk_key, 640 keys->wi_keys[i].wi_keydat, len); 641 } 642 error = ENETRESET; 643 break; 644 case WI_RID_MAX_DATALEN: 645 if (len != 2) 646 return EINVAL; 647 len = le16toh(wreq.wi_val[0]); 648 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN) 649 return EINVAL; 650 if (len != IEEE80211_MAX_LEN) 651 return EINVAL; /* TODO: fragment */ 652 ic->ic_fragthreshold = len; 653 error = ENETRESET; 654 break; 655 case WI_RID_IFACE_STATS: 656 error = EPERM; 657 break; 658 case WI_RID_SCAN_REQ: /* XXX wicontrol */ 659 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 660 break; 661 /* NB: ignore channel list and tx rate parameters */ 662 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 663 break; 664 case WI_RID_SCAN_APS: 665 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 666 break; 667 len--; /* XXX: tx rate? */ 668 /* FALLTHRU */ 669 case WI_RID_CHANNEL_LIST: 670 memset(chanlist, 0, sizeof(chanlist)); 671 /* 672 * Since channel 0 is not available for DS, channel 1 673 * is assigned to LSB on WaveLAN. 674 */ 675 if (ic->ic_phytype == IEEE80211_T_DS) 676 i = 1; 677 else 678 i = 0; 679 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { 680 if ((j / 8) >= len) 681 break; 682 if (isclr((u_int8_t *)wreq.wi_val, j)) 683 continue; 684 if (isclr(ic->ic_chan_active, i)) { 685 if (wreq.wi_type != WI_RID_CHANNEL_LIST) 686 continue; 687 if (isclr(ic->ic_chan_avail, i)) 688 return EPERM; 689 } 690 setbit(chanlist, i); 691 } 692 memcpy(ic->ic_chan_active, chanlist, 693 sizeof(ic->ic_chan_active)); 694 if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 695 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) 696 if (isset(chanlist, i)) { 697 ic->ic_ibss_chan = &ic->ic_channels[i]; 698 break; 699 } 700 } 701 if (isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan))) 702 ic->ic_bss->ni_chan = ic->ic_ibss_chan; 703 if (wreq.wi_type == WI_RID_CHANNEL_LIST) 704 error = ENETRESET; 705 else 706 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 707 break; 708 default: 709 error = EINVAL; 710 break; 711 } 712 return error; 713 } 714 715 int 716 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 717 { 718 struct ieee80211com *ic = (void *)ifp; 719 int error = 0; 720 u_int kid, len; 721 struct ieee80211req *ireq; 722 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; 723 char tmpssid[IEEE80211_NWID_LEN]; 724 struct ieee80211_channel *chan; 725 726 switch (cmd) { 727 case SIOCSIFMEDIA: 728 case SIOCGIFMEDIA: 729 error = ifmedia_ioctl(ifp, (struct ifreq *) data, 730 &ic->ic_media, cmd); 731 break; 732 case SIOCG80211: 733 ireq = (struct ieee80211req *) data; 734 switch (ireq->i_type) { 735 case IEEE80211_IOC_SSID: 736 switch (ic->ic_state) { 737 case IEEE80211_S_INIT: 738 case IEEE80211_S_SCAN: 739 ireq->i_len = ic->ic_des_esslen; 740 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len); 741 break; 742 default: 743 ireq->i_len = ic->ic_bss->ni_esslen; 744 memcpy(tmpssid, ic->ic_bss->ni_essid, 745 ireq->i_len); 746 break; 747 } 748 error = copyout(tmpssid, ireq->i_data, ireq->i_len); 749 break; 750 case IEEE80211_IOC_NUMSSIDS: 751 ireq->i_val = 1; 752 break; 753 case IEEE80211_IOC_WEP: 754 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 755 ireq->i_val = IEEE80211_WEP_NOSUP; 756 } else { 757 if (ic->ic_flags & IEEE80211_F_WEPON) { 758 ireq->i_val = 759 IEEE80211_WEP_MIXED; 760 } else { 761 ireq->i_val = 762 IEEE80211_WEP_OFF; 763 } 764 } 765 break; 766 case IEEE80211_IOC_WEPKEY: 767 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 768 error = EINVAL; 769 break; 770 } 771 kid = (u_int) ireq->i_val; 772 if (kid >= IEEE80211_WEP_NKID) { 773 error = EINVAL; 774 break; 775 } 776 len = (u_int) ic->ic_nw_keys[kid].wk_len; 777 /* NB: only root can read WEP keys */ 778 if (suser(curthread)) { 779 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len); 780 } else { 781 bzero(tmpkey, len); 782 } 783 ireq->i_len = len; 784 error = copyout(tmpkey, ireq->i_data, len); 785 break; 786 case IEEE80211_IOC_NUMWEPKEYS: 787 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 788 error = EINVAL; 789 else 790 ireq->i_val = IEEE80211_WEP_NKID; 791 break; 792 case IEEE80211_IOC_WEPTXKEY: 793 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 794 error = EINVAL; 795 else 796 ireq->i_val = ic->ic_wep_txkey; 797 break; 798 case IEEE80211_IOC_AUTHMODE: 799 ireq->i_val = IEEE80211_AUTH_OPEN; 800 break; 801 case IEEE80211_IOC_CHANNEL: 802 switch (ic->ic_state) { 803 case IEEE80211_S_INIT: 804 case IEEE80211_S_SCAN: 805 if (ic->ic_opmode == IEEE80211_M_STA) 806 chan = ic->ic_des_chan; 807 else 808 chan = ic->ic_ibss_chan; 809 break; 810 default: 811 chan = ic->ic_bss->ni_chan; 812 break; 813 } 814 ireq->i_val = ieee80211_chan2ieee(ic, chan); 815 break; 816 case IEEE80211_IOC_POWERSAVE: 817 if (ic->ic_flags & IEEE80211_F_PMGTON) 818 ireq->i_val = IEEE80211_POWERSAVE_ON; 819 else 820 ireq->i_val = IEEE80211_POWERSAVE_OFF; 821 break; 822 case IEEE80211_IOC_POWERSAVESLEEP: 823 ireq->i_val = ic->ic_lintval; 824 break; 825 case IEEE80211_IOCT_RTSTHRESHOLD: 826 ireq->i_val = ic->ic_rtsthreshold; 827 break; 828 default: 829 error = EINVAL; 830 } 831 break; 832 case SIOCS80211: 833 error = suser(curthread); 834 if (error) 835 break; 836 ireq = (struct ieee80211req *) data; 837 switch (ireq->i_type) { 838 case IEEE80211_IOC_SSID: 839 if (ireq->i_val != 0 || 840 ireq->i_len > IEEE80211_NWID_LEN) { 841 error = EINVAL; 842 break; 843 } 844 error = copyin(ireq->i_data, tmpssid, ireq->i_len); 845 if (error) 846 break; 847 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); 848 ic->ic_des_esslen = ireq->i_len; 849 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len); 850 error = ENETRESET; 851 break; 852 case IEEE80211_IOC_WEP: 853 /* 854 * These cards only support one mode so 855 * we just turn wep on if what ever is 856 * passed in is not OFF. 857 */ 858 if (ireq->i_val == IEEE80211_WEP_OFF) { 859 ic->ic_flags &= ~IEEE80211_F_WEPON; 860 } else { 861 ic->ic_flags |= IEEE80211_F_WEPON; 862 } 863 error = ENETRESET; 864 break; 865 case IEEE80211_IOC_WEPKEY: 866 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { 867 error = EINVAL; 868 break; 869 } 870 kid = (u_int) ireq->i_val; 871 if (kid >= IEEE80211_WEP_NKID) { 872 error = EINVAL; 873 break; 874 } 875 if (ireq->i_len > sizeof(tmpkey)) { 876 error = EINVAL; 877 break; 878 } 879 memset(tmpkey, 0, sizeof(tmpkey)); 880 error = copyin(ireq->i_data, tmpkey, ireq->i_len); 881 if (error) 882 break; 883 memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey, 884 sizeof(tmpkey)); 885 ic->ic_nw_keys[kid].wk_len = ireq->i_len; 886 error = ENETRESET; 887 break; 888 case IEEE80211_IOC_WEPTXKEY: 889 kid = (u_int) ireq->i_val; 890 if (kid >= IEEE80211_WEP_NKID) { 891 error = EINVAL; 892 break; 893 } 894 ic->ic_wep_txkey = kid; 895 error = ENETRESET; 896 break; 897 #if 0 898 case IEEE80211_IOC_AUTHMODE: 899 sc->wi_authmode = ireq->i_val; 900 break; 901 #endif 902 case IEEE80211_IOC_CHANNEL: 903 /* XXX 0xffff overflows 16-bit signed */ 904 if (ireq->i_val == 0 || 905 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) 906 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 907 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX || 908 isclr(ic->ic_chan_active, ireq->i_val)) { 909 error = EINVAL; 910 break; 911 } else 912 ic->ic_ibss_chan = ic->ic_des_chan = 913 &ic->ic_channels[ireq->i_val]; 914 switch (ic->ic_state) { 915 case IEEE80211_S_INIT: 916 case IEEE80211_S_SCAN: 917 error = ENETRESET; 918 break; 919 default: 920 if (ic->ic_opmode == IEEE80211_M_STA) { 921 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 922 ic->ic_bss->ni_chan != ic->ic_des_chan) 923 error = ENETRESET; 924 } else { 925 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) 926 error = ENETRESET; 927 } 928 break; 929 } 930 break; 931 case IEEE80211_IOC_POWERSAVE: 932 switch (ireq->i_val) { 933 case IEEE80211_POWERSAVE_OFF: 934 if (ic->ic_flags & IEEE80211_F_PMGTON) { 935 ic->ic_flags &= ~IEEE80211_F_PMGTON; 936 error = ENETRESET; 937 } 938 break; 939 case IEEE80211_POWERSAVE_ON: 940 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 941 error = EINVAL; 942 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 943 ic->ic_flags |= IEEE80211_F_PMGTON; 944 error = ENETRESET; 945 } 946 break; 947 default: 948 error = EINVAL; 949 break; 950 } 951 break; 952 case IEEE80211_IOC_POWERSAVESLEEP: 953 if (ireq->i_val < 0) { 954 error = EINVAL; 955 break; 956 } 957 ic->ic_lintval = ireq->i_val; 958 error = ENETRESET; 959 break; 960 case IEEE80211_IOCT_RTSTHRESHOLD: 961 if (!(IEEE80211_RTS_MIN < ireq->i_val && 962 ireq->i_val < IEEE80211_RTS_MAX)) { 963 error = EINVAL; 964 break; 965 } 966 ic->ic_rtsthreshold = ireq->i_val; 967 error = ENETRESET; 968 break; 969 default: 970 error = EINVAL; 971 break; 972 } 973 break; 974 case SIOCGIFGENERIC: 975 error = ieee80211_cfgget(ifp, cmd, data); 976 break; 977 case SIOCSIFGENERIC: 978 error = suser(curthread); 979 if (error) 980 break; 981 error = ieee80211_cfgset(ifp, cmd, data); 982 break; 983 default: 984 error = ether_ioctl(ifp, cmd, data); 985 break; 986 } 987 return error; 988 } 989