1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 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 35 #include <sys/param.h> 36 #include <sys/types.h> 37 #include <sys/errno.h> 38 #include <sys/strsun.h> 39 #include <sys/policy.h> 40 #include <inet/common.h> 41 #include <inet/nd.h> 42 #include <inet/mi.h> 43 #include <sys/note.h> 44 #include <sys/mac_provider.h> 45 #include <inet/wifi_ioctl.h> 46 #include "net80211_impl.h" 47 48 static int wl_set_essid(struct ieee80211com *, const void *); 49 static void wl_get_essid(struct ieee80211com *, void *); 50 static int wl_set_bssid(struct ieee80211com *, const void *); 51 static void wl_get_bssid(struct ieee80211com *, void *); 52 static int wl_set_bsstype(struct ieee80211com *, const void *); 53 static void wl_get_bsstype(struct ieee80211com *, void *); 54 static void wl_get_linkstatus(struct ieee80211com *, void *); 55 static int wl_set_desrates(struct ieee80211com *, const void *); 56 static void wl_get_desrates(struct ieee80211com *, void *); 57 static int wl_set_authmode(struct ieee80211com *, const void *); 58 static void wl_get_authmode(struct ieee80211com *, void *); 59 static int wl_set_encrypt(struct ieee80211com *, const void *); 60 static void wl_get_encrypt(struct ieee80211com *, void *); 61 static void wl_get_rssi(struct ieee80211com *, void *); 62 static int wl_set_phy(struct ieee80211com *, const void *); 63 static int wl_get_phy(struct ieee80211com *, void *); 64 static void wl_get_capability(struct ieee80211com *, void *); 65 static int wl_set_wpa(struct ieee80211com *, const void *); 66 static void wl_get_wpa(struct ieee80211com *, void *); 67 static void wl_get_scanresults(struct ieee80211com *, void *); 68 static void wl_get_esslist(struct ieee80211com *, void *); 69 static int wl_set_wepkey(struct ieee80211com *, const void *); 70 static int wl_set_optie(struct ieee80211com *, const void *); 71 static int wl_set_delkey(struct ieee80211com *, const void *); 72 static int wl_set_mlme(struct ieee80211com *, const void *); 73 static int wl_set_wpakey(struct ieee80211com *, const void *); 74 static void wl_get_suprates(struct ieee80211com *, void *); 75 static int wl_set_createibss(struct ieee80211com *, const void *); 76 static void wl_get_createibss(struct ieee80211com *, void *); 77 78 static size_t 79 wifi_strnlen(const char *s, size_t n) 80 { 81 size_t i; 82 83 for (i = 0; i < n && s[i] != '\0'; i++) 84 /* noop */; 85 return (i); 86 } 87 88 /* 89 * Initialize an output message block by copying from an 90 * input message block. The message is of type wldp_t. 91 * mp input message block 92 * buflen length of wldp_buf 93 */ 94 static void 95 wifi_setupoutmsg(mblk_t *mp, int buflen) 96 { 97 wldp_t *wp; 98 99 wp = (wldp_t *)mp->b_rptr; 100 wp->wldp_length = WIFI_BUF_OFFSET + buflen; 101 wp->wldp_result = WL_SUCCESS; 102 mp->b_wptr = mp->b_rptr + wp->wldp_length; 103 } 104 105 /* 106 * Allocate and initialize an output message. 107 */ 108 static mblk_t * 109 wifi_getoutmsg(mblk_t *mp, uint32_t cmd, int buflen) 110 { 111 mblk_t *mp1; 112 int size; 113 114 size = WIFI_BUF_OFFSET; 115 if (cmd == WLAN_GET_PARAM) 116 size += buflen; /* to hold output parameters */ 117 mp1 = allocb(size, BPRI_HI); 118 if (mp1 == NULL) { 119 ieee80211_err("wifi_getoutbuf: allocb %d bytes failed!\n", 120 size); 121 return (NULL); 122 } 123 124 bzero(mp1->b_rptr, size); 125 bcopy(mp->b_rptr, mp1->b_rptr, WIFI_BUF_OFFSET); 126 wifi_setupoutmsg(mp1, size - WIFI_BUF_OFFSET); 127 128 return (mp1); 129 } 130 131 static int 132 wifi_cfg_essid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 133 { 134 mblk_t *omp; 135 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 136 wldp_t *outp; 137 wl_essid_t *iw_essid = (wl_essid_t *)inp->wldp_buf; 138 wl_essid_t *ow_essid; 139 int err = 0; 140 141 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_essid_t))) == NULL) 142 return (ENOMEM); 143 outp = (wldp_t *)omp->b_rptr; 144 ow_essid = (wl_essid_t *)outp->wldp_buf; 145 146 switch (cmd) { 147 case WLAN_GET_PARAM: 148 wl_get_essid(ic, ow_essid); 149 break; 150 case WLAN_SET_PARAM: 151 err = wl_set_essid(ic, iw_essid); 152 break; 153 default: 154 ieee80211_err("wifi_cfg_essid: unknown command %x\n", cmd); 155 outp->wldp_result = WL_NOTSUPPORTED; 156 err = EINVAL; 157 break; 158 } 159 160 freemsg(*mp); 161 *mp = omp; 162 return (err); 163 } 164 165 static int 166 wifi_cfg_bssid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 167 { 168 mblk_t *omp; 169 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 170 wldp_t *outp; 171 int err = 0; 172 173 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bssid_t))) == NULL) 174 return (ENOMEM); 175 outp = (wldp_t *)omp->b_rptr; 176 177 switch (cmd) { 178 case WLAN_GET_PARAM: 179 wl_get_bssid(ic, outp->wldp_buf); 180 break; 181 case WLAN_SET_PARAM: 182 err = wl_set_bssid(ic, inp->wldp_buf); 183 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_bssid: " 184 "set bssid=%s\n", 185 ieee80211_macaddr_sprintf(inp->wldp_buf)); 186 break; 187 default: 188 ieee80211_err("wifi_cfg_bssid: unknown command %x\n", cmd); 189 outp->wldp_result = WL_NOTSUPPORTED; 190 err = EINVAL; 191 break; 192 } 193 194 freemsg(*mp); 195 *mp = omp; 196 return (err); 197 } 198 199 static int 200 wifi_cfg_nodename(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 201 { 202 mblk_t *omp; 203 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 204 wldp_t *outp; 205 wl_nodename_t *iw_name = (wl_nodename_t *)inp->wldp_buf; 206 wl_nodename_t *ow_name; 207 char *nodename; 208 int len, err; 209 210 err = 0; 211 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_nodename_t))) == NULL) 212 return (ENOMEM); 213 outp = (wldp_t *)omp->b_rptr; 214 ow_name = (wl_nodename_t *)outp->wldp_buf; 215 216 switch (cmd) { 217 case WLAN_GET_PARAM: 218 len = wifi_strnlen((const char *)ic->ic_nickname, 219 IEEE80211_NWID_LEN); 220 ow_name->wl_nodename_length = len; 221 bcopy(ic->ic_nickname, ow_name->wl_nodename_name, len); 222 break; 223 case WLAN_SET_PARAM: 224 if (iw_name->wl_nodename_length > IEEE80211_NWID_LEN) { 225 ieee80211_err("wifi_cfg_nodename: " 226 "node name too long, %u\n", 227 iw_name->wl_nodename_length); 228 outp->wldp_result = WL_NOTSUPPORTED; 229 err = EINVAL; 230 break; 231 } 232 nodename = iw_name->wl_nodename_name; 233 nodename[IEEE80211_NWID_LEN] = 0; 234 ieee80211_dbg(IEEE80211_MSG_CONFIG, 235 "wifi_cfg_nodename: set nodename %s, len=%d\n", 236 nodename, iw_name->wl_nodename_length); 237 238 len = iw_name->wl_nodename_length; 239 if (len > 0) 240 bcopy(nodename, ic->ic_nickname, len); 241 if (len < IEEE80211_NWID_LEN) 242 ic->ic_nickname[len] = 0; 243 break; 244 default: 245 ieee80211_err("wifi_cfg_nodename: unknown command %x\n", cmd); 246 outp->wldp_result = WL_NOTSUPPORTED; 247 err = EINVAL; 248 break; 249 } 250 251 freemsg(*mp); 252 *mp = omp; 253 return (err); 254 } 255 256 static int 257 wifi_cfg_phy(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 258 { 259 mblk_t *omp; 260 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 261 wldp_t *outp; 262 wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)inp->wldp_buf; 263 wl_phy_conf_t *ow_phy; 264 int err = 0; 265 266 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_phy_conf_t))) == NULL) 267 return (ENOMEM); 268 outp = (wldp_t *)omp->b_rptr; 269 ow_phy = (wl_phy_conf_t *)outp->wldp_buf; 270 271 switch (cmd) { 272 case WLAN_GET_PARAM: 273 err = wl_get_phy(ic, ow_phy); 274 break; 275 276 case WLAN_SET_PARAM: 277 err = wl_set_phy(ic, iw_phy); 278 break; 279 280 default: 281 ieee80211_err("wifi_cfg_phy: unknown command %x\n", cmd); 282 outp->wldp_result = WL_NOTSUPPORTED; 283 err = EINVAL; 284 break; 285 } /* switch (cmd) */ 286 287 freemsg(*mp); 288 *mp = omp; 289 return (err); 290 } 291 292 static int 293 wifi_cfg_wepkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 294 { 295 mblk_t *omp; 296 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 297 wldp_t *outp; 298 wl_wep_key_t *iw_wepkey = (wl_wep_key_t *)inp->wldp_buf; 299 int err = 0; 300 301 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 302 return (ENOMEM); 303 outp = (wldp_t *)omp->b_rptr; 304 305 switch (cmd) { 306 case WLAN_GET_PARAM: 307 outp->wldp_result = WL_WRITEONLY; 308 err = EINVAL; 309 break; 310 case WLAN_SET_PARAM: 311 if (inp->wldp_length < sizeof (wl_wep_key_tab_t)) { 312 ieee80211_err("wifi_cfg_wepkey: " 313 "parameter too short, %d, expected %d\n", 314 inp->wldp_length, sizeof (wl_wep_key_tab_t)); 315 outp->wldp_result = WL_NOTSUPPORTED; 316 err = EINVAL; 317 break; 318 } 319 320 err = wl_set_wepkey(ic, iw_wepkey); 321 break; 322 default: 323 ieee80211_err("wifi_cfg_wepkey: unknown command %x\n", cmd); 324 outp->wldp_result = WL_NOTSUPPORTED; 325 err = EINVAL; 326 break; 327 } 328 329 freemsg(*mp); 330 *mp = omp; 331 return (err); 332 } 333 334 static int 335 wifi_cfg_keyid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 336 { 337 mblk_t *omp; 338 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 339 wldp_t *outp; 340 wl_wep_key_id_t *iw_kid = (wl_wep_key_id_t *)inp->wldp_buf; 341 wl_wep_key_id_t *ow_kid; 342 int err = 0; 343 344 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wep_key_id_t))) == NULL) 345 return (ENOMEM); 346 outp = (wldp_t *)omp->b_rptr; 347 ow_kid = (wl_wep_key_id_t *)outp->wldp_buf; 348 349 switch (cmd) { 350 case WLAN_GET_PARAM: 351 *ow_kid = (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) ? 352 0 : ic->ic_def_txkey; 353 break; 354 case WLAN_SET_PARAM: 355 if (*iw_kid >= MAX_NWEPKEYS) { 356 ieee80211_err("wifi_cfg_keyid: " 357 "keyid too large, %u\n", *iw_kid); 358 outp->wldp_result = WL_NOTSUPPORTED; 359 err = EINVAL; 360 } else { 361 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_keyid: " 362 "set keyid=%u\n", *iw_kid); 363 ic->ic_def_txkey = *iw_kid; 364 err = ENETRESET; 365 } 366 break; 367 default: 368 ieee80211_err("wifi_cfg_keyid: unknown command %x\n", cmd); 369 outp->wldp_result = WL_NOTSUPPORTED; 370 err = EINVAL; 371 break; 372 } 373 374 freemsg(*mp); 375 *mp = omp; 376 return (err); 377 } 378 379 static int 380 wifi_cfg_authmode(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 381 { 382 mblk_t *omp; 383 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 384 wldp_t *outp; 385 wl_authmode_t *iw_auth = (wl_authmode_t *)inp->wldp_buf; 386 wl_authmode_t *ow_auth; 387 int err = 0; 388 389 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_authmode_t))) == NULL) 390 return (ENOMEM); 391 outp = (wldp_t *)omp->b_rptr; 392 ow_auth = (wl_authmode_t *)outp->wldp_buf; 393 394 switch (cmd) { 395 case WLAN_GET_PARAM: 396 wl_get_authmode(ic, ow_auth); 397 break; 398 case WLAN_SET_PARAM: 399 err = wl_set_authmode(ic, iw_auth); 400 break; 401 default: 402 ieee80211_err("wifi_cfg_authmode: unknown command %x\n", cmd); 403 outp->wldp_result = WL_NOTSUPPORTED; 404 err = EINVAL; 405 break; 406 } 407 408 freemsg(*mp); 409 *mp = omp; 410 return (err); 411 } 412 413 static int 414 wifi_cfg_encrypt(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 415 { 416 mblk_t *omp; 417 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 418 wldp_t *outp; 419 wl_encryption_t *iw_encryp = (wl_encryption_t *)inp->wldp_buf; 420 wl_encryption_t *ow_encryp; 421 int err = 0; 422 423 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_encryption_t))) == NULL) 424 return (ENOMEM); 425 outp = (wldp_t *)omp->b_rptr; 426 ow_encryp = (wl_encryption_t *)outp->wldp_buf; 427 428 switch (cmd) { 429 case WLAN_GET_PARAM: 430 wl_get_encrypt(ic, ow_encryp); 431 break; 432 case WLAN_SET_PARAM: 433 err = wl_set_encrypt(ic, iw_encryp); 434 break; 435 default: 436 ieee80211_err("wifi_cfg_encrypt: unknown command %x\n", cmd); 437 outp->wldp_result = WL_NOTSUPPORTED; 438 err = EINVAL; 439 break; 440 } 441 442 freemsg(*mp); 443 *mp = omp; 444 return (err); 445 } 446 447 static int 448 wifi_cfg_bsstype(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 449 { 450 mblk_t *omp; 451 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 452 wldp_t *outp; 453 wl_bss_type_t *iw_opmode = (wl_bss_type_t *)inp->wldp_buf; 454 wl_bss_type_t *ow_opmode; 455 int err = 0; 456 457 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bss_type_t))) == NULL) 458 return (ENOMEM); 459 outp = (wldp_t *)omp->b_rptr; 460 ow_opmode = (wl_bss_type_t *)outp->wldp_buf; 461 462 switch (cmd) { 463 case WLAN_GET_PARAM: 464 wl_get_bsstype(ic, ow_opmode); 465 break; 466 case WLAN_SET_PARAM: 467 if (*iw_opmode == ic->ic_opmode) 468 break; 469 470 err = wl_set_bsstype(ic, iw_opmode); 471 break; 472 default: 473 ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd); 474 outp->wldp_result = WL_NOTSUPPORTED; 475 err = EINVAL; 476 break; 477 } 478 479 freemsg(*mp); 480 *mp = omp; 481 return (err); 482 } 483 484 static int 485 wifi_cfg_createibss(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 486 { 487 mblk_t *omp; 488 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 489 wldp_t *outp; 490 wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)inp->wldp_buf; 491 wl_create_ibss_t *ow_ibss; 492 int err = 0; 493 494 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_create_ibss_t))) == NULL) 495 return (ENOMEM); 496 outp = (wldp_t *)omp->b_rptr; 497 ow_ibss = (wl_create_ibss_t *)outp->wldp_buf; 498 499 switch (cmd) { 500 case WLAN_GET_PARAM: 501 wl_get_createibss(ic, ow_ibss); 502 break; 503 case WLAN_SET_PARAM: 504 err = wl_set_createibss(ic, iw_ibss); 505 break; 506 default: 507 ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd); 508 outp->wldp_result = WL_NOTSUPPORTED; 509 err = EINVAL; 510 break; 511 } 512 513 freemsg(*mp); 514 *mp = omp; 515 return (err); 516 } 517 518 static int 519 wifi_cfg_linkstatus(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 520 { 521 mblk_t *omp; 522 wldp_t *outp; 523 wl_linkstatus_t *ow_linkstat; 524 int err = 0; 525 526 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_linkstatus_t))) == NULL) 527 return (ENOMEM); 528 outp = (wldp_t *)omp->b_rptr; 529 ow_linkstat = (wl_linkstatus_t *)outp->wldp_buf; 530 531 switch (cmd) { 532 case WLAN_GET_PARAM: 533 wl_get_linkstatus(ic, ow_linkstat); 534 break; 535 case WLAN_SET_PARAM: 536 outp->wldp_result = WL_READONLY; 537 err = EINVAL; 538 break; 539 default: 540 ieee80211_err("wifi_cfg_linkstatus: unknown command %x\n", cmd); 541 outp->wldp_result = WL_NOTSUPPORTED; 542 err = EINVAL; 543 break; 544 } 545 546 freemsg(*mp); 547 *mp = omp; 548 return (err); 549 } 550 551 static int 552 wifi_cfg_suprates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 553 { 554 mblk_t *omp; 555 wldp_t *outp; 556 wl_rates_t *ow_rates; 557 int err, buflen; 558 559 err = 0; 560 /* rate value (wl_rates_rates) is of type char */ 561 buflen = offsetof(wl_rates_t, wl_rates_rates) + 562 sizeof (char) * IEEE80211_MODE_MAX * IEEE80211_RATE_MAXSIZE; 563 if ((omp = wifi_getoutmsg(*mp, cmd, buflen)) == NULL) 564 return (ENOMEM); 565 outp = (wldp_t *)omp->b_rptr; 566 ow_rates = (wl_rates_t *)outp->wldp_buf; 567 568 switch (cmd) { 569 case WLAN_GET_PARAM: 570 (void) wl_get_suprates(ic, ow_rates); 571 break; 572 case WLAN_SET_PARAM: 573 outp->wldp_result = WL_READONLY; 574 err = EINVAL; 575 break; 576 default: 577 ieee80211_err("wifi_cfg_suprates: unknown command %x\n", cmd); 578 outp->wldp_result = WL_NOTSUPPORTED; 579 err = EINVAL; 580 break; 581 } 582 583 freemsg(*mp); 584 *mp = omp; 585 return (err); 586 } 587 588 static int 589 wifi_cfg_desrates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 590 { 591 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 592 wl_rates_t *iw_rates = (wl_rates_t *)inp->wldp_buf; 593 mblk_t *omp; 594 wldp_t *outp; 595 wl_rates_t *ow_rates; 596 int err; 597 598 err = 0; 599 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rates_t))) == NULL) 600 return (ENOMEM); 601 outp = (wldp_t *)omp->b_rptr; 602 ow_rates = (wl_rates_t *)outp->wldp_buf; 603 604 switch (cmd) { 605 case WLAN_GET_PARAM: 606 wl_get_desrates(ic, ow_rates); 607 break; 608 case WLAN_SET_PARAM: 609 err = wl_set_desrates(ic, iw_rates); 610 break; 611 default: 612 ieee80211_err("wifi_cfg_desrates: unknown command %x\n", cmd); 613 outp->wldp_result = WL_NOTSUPPORTED; 614 err = EINVAL; 615 break; 616 } 617 618 freemsg(*mp); 619 *mp = omp; 620 return (err); 621 } 622 623 /* 624 * Rescale device's RSSI value to (0, 15) as required by WiFi 625 * driver IOCTLs (PSARC/2003/722) 626 */ 627 static wl_rssi_t 628 wifi_getrssi(struct ieee80211_node *in) 629 { 630 struct ieee80211com *ic = in->in_ic; 631 wl_rssi_t rssi, max_rssi; 632 633 rssi = ic->ic_node_getrssi(in); 634 max_rssi = (ic->ic_maxrssi == 0) ? IEEE80211_MAXRSSI : ic->ic_maxrssi; 635 if (rssi == 0) 636 rssi = 0; 637 else if (rssi >= max_rssi) 638 rssi = MAX_RSSI; 639 else 640 rssi = rssi * MAX_RSSI / max_rssi + 1; 641 642 return (rssi); 643 } 644 645 static int 646 wifi_cfg_rssi(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 647 { 648 mblk_t *omp; 649 wldp_t *outp; 650 wl_rssi_t *ow_rssi; 651 int err = 0; 652 653 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rssi_t))) == NULL) 654 return (ENOMEM); 655 outp = (wldp_t *)omp->b_rptr; 656 ow_rssi = (wl_rssi_t *)outp->wldp_buf; 657 658 switch (cmd) { 659 case WLAN_GET_PARAM: 660 *ow_rssi = wifi_getrssi(ic->ic_bss); 661 break; 662 case WLAN_SET_PARAM: 663 outp->wldp_result = WL_READONLY; 664 err = EINVAL; 665 break; 666 default: 667 ieee80211_err("wifi_cfg_rssi: unknown command %x\n", cmd); 668 outp->wldp_result = WL_NOTSUPPORTED; 669 return (EINVAL); 670 } 671 672 freemsg(*mp); 673 *mp = omp; 674 return (err); 675 } 676 677 /* 678 * maximum scan wait time in second. 679 * Time spent on scaning one channel is usually 100~200ms. The maximum 680 * number of channels defined in wifi_ioctl.h is 99 (MAX_CHANNEL_NUM). 681 * As a result the maximum total scan time is defined as below in ms. 682 */ 683 #define WAIT_SCAN_MAX (200 * MAX_CHANNEL_NUM) 684 685 static void 686 wifi_wait_scan(struct ieee80211com *ic) 687 { 688 ieee80211_impl_t *im = ic->ic_private; 689 clock_t delta = drv_usectohz(WAIT_SCAN_MAX * 1000); 690 691 while ((ic->ic_flags & (IEEE80211_F_SCAN | IEEE80211_F_ASCAN)) != 0) { 692 if (cv_reltimedwait_sig(&im->im_scan_cv, &ic->ic_genlock, 693 delta, TR_CLOCK_TICK) != 0) { 694 break; 695 } 696 } 697 } 698 699 #define WIFI_HAVE_CAP(in, flag) (((in)->in_capinfo & (flag)) ? 1 : 0) 700 #define WIFI_HAVE_HTCAP(in) (((in)->in_htcap != 0) ? 1 : 0) 701 702 /* 703 * Callback function used by ieee80211_iterate_nodes() in 704 * wifi_cfg_esslist() to get info of each node in a node table 705 * arg output buffer, pointer to wl_ess_list_t 706 * in each node in the node table 707 */ 708 static void 709 wifi_read_ap(void *arg, struct ieee80211_node *in) 710 { 711 wl_ess_list_t *aps = arg; 712 ieee80211com_t *ic = in->in_ic; 713 struct ieee80211_channel *chan = in->in_chan; 714 struct ieee80211_rateset *rates = &(in->in_rates); 715 wl_ess_conf_t *conf; 716 uint8_t *end; 717 uint_t i, nrates; 718 719 end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN - 720 sizeof (wl_ess_list_t); 721 conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num]; 722 if ((uint8_t *)conf > end) 723 return; 724 725 conf->wl_ess_conf_length = sizeof (struct wl_ess_conf); 726 727 /* skip newly allocated NULL bss node */ 728 if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr)) 729 return; 730 731 conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen; 732 bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid, 733 in->in_esslen); 734 bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN); 735 conf->wl_ess_conf_wepenabled = 736 (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ? 737 WL_ENC_WEP : WL_NOENCRYPTION); 738 conf->wl_ess_conf_bsstype = 739 (in->in_capinfo & IEEE80211_CAPINFO_ESS ? 740 WL_BSS_BSS : WL_BSS_IBSS); 741 conf->wl_ess_conf_sl = wifi_getrssi(in); 742 conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1); 743 744 /* physical (FH, DS, ERP) parameters */ 745 if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) { 746 wl_ofdm_t *ofdm = 747 (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf); 748 ofdm->wl_ofdm_subtype = WL_OFDM; 749 ofdm->wl_ofdm_frequency = chan->ich_freq; 750 ofdm->wl_ofdm_ht_enabled = WIFI_HAVE_HTCAP(in); 751 } else { 752 switch (in->in_phytype) { 753 case IEEE80211_T_FH: { 754 wl_fhss_t *fhss = (wl_fhss_t *) 755 &((conf->wl_phy_conf).wl_phy_fhss_conf); 756 757 fhss->wl_fhss_subtype = WL_FHSS; 758 fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan); 759 fhss->wl_fhss_dwelltime = in->in_fhdwell; 760 break; 761 } 762 case IEEE80211_T_DS: { 763 wl_dsss_t *dsss = (wl_dsss_t *) 764 &((conf->wl_phy_conf).wl_phy_dsss_conf); 765 766 dsss->wl_dsss_subtype = WL_DSSS; 767 dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan); 768 dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in, 769 IEEE80211_CAPINFO_SHORT_PREAMBLE); 770 dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in, 771 IEEE80211_CAPINFO_CHNL_AGILITY); 772 dsss->wl_dsss_have_pbcc = dsss->wl_dsss_pbcc_enable = 773 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 774 break; 775 } 776 case IEEE80211_T_OFDM: { 777 wl_erp_t *erp = (wl_erp_t *) 778 &((conf->wl_phy_conf).wl_phy_erp_conf); 779 780 erp->wl_erp_subtype = WL_ERP; 781 erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan); 782 erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in, 783 IEEE80211_CAPINFO_SHORT_PREAMBLE); 784 erp->wl_erp_have_agility = erp->wl_erp_agility_enabled = 785 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_CHNL_AGILITY); 786 erp->wl_erp_have_pbcc = erp->wl_erp_pbcc_enabled = 787 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 788 erp->wl_erp_dsss_ofdm_enabled = 789 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_DSSSOFDM); 790 erp->wl_erp_sst_enabled = WIFI_HAVE_CAP(in, 791 IEEE80211_CAPINFO_SHORT_SLOTTIME); 792 erp->wl_erp_ht_enabled = WIFI_HAVE_HTCAP(in); 793 break; 794 } /* case IEEE80211_T_OFDM */ 795 } /* switch in->in_phytype */ 796 } 797 798 /* supported rates */ 799 nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES); 800 /* 801 * The number of supported rates might exceed 802 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates 803 * first so userland command could properly show 804 * maximum speed of AP 805 */ 806 for (i = 0; i < nrates; i++) { 807 conf->wl_supported_rates[i] = 808 rates->ir_rates[rates->ir_nrates - i - 1]; 809 } 810 811 aps->wl_ess_list_num++; 812 } 813 814 static int 815 wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 816 { 817 mblk_t *omp; 818 wldp_t *outp; 819 wl_ess_list_t *ow_aps; 820 int err = 0; 821 822 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 823 NULL) { 824 return (ENOMEM); 825 } 826 outp = (wldp_t *)omp->b_rptr; 827 ow_aps = (wl_ess_list_t *)outp->wldp_buf; 828 829 switch (cmd) { 830 case WLAN_GET_PARAM: 831 ow_aps->wl_ess_list_num = 0; 832 ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps); 833 outp->wldp_length = WIFI_BUF_OFFSET + 834 offsetof(wl_ess_list_t, wl_ess_list_ess) + 835 ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t); 836 omp->b_wptr = omp->b_rptr + outp->wldp_length; 837 break; 838 case WLAN_SET_PARAM: 839 outp->wldp_result = WL_READONLY; 840 err = EINVAL; 841 break; 842 default: 843 ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd); 844 outp->wldp_result = WL_NOTSUPPORTED; 845 err = EINVAL; 846 break; 847 } 848 849 freemsg(*mp); 850 *mp = omp; 851 return (err); 852 } 853 854 /* 855 * Scan the network for all available ESSs. 856 * IEEE80211_F_SCANONLY is set when current state is INIT. And 857 * with this flag, after scan the state will be changed back to 858 * INIT. The reason is at the end of SCAN stage, the STA will 859 * consequently connect to an AP. Then it looks unreasonable that 860 * for a disconnected device, A SCAN command causes it connected. 861 * So the state is changed back to INIT. 862 */ 863 static int 864 wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp) 865 { 866 int ostate = ic->ic_state; 867 868 /* 869 * Do not scan when current state is RUN. The reason is 870 * when connected, STA is on the same channel as AP. But 871 * to do scan, STA have to switch to each available channel, 872 * send probe request and wait certian time for probe 873 * response/beacon. Then when the STA switches to a channel 874 * different than AP's, as a result it cannot send/receive 875 * data packets to/from the connected WLAN. This eventually 876 * will cause data loss. 877 */ 878 if (ostate == IEEE80211_S_RUN) 879 return (0); 880 881 IEEE80211_UNLOCK(ic); 882 883 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 884 IEEE80211_LOCK(ic); 885 if (ostate == IEEE80211_S_INIT) 886 ic->ic_flags |= IEEE80211_F_SCANONLY; 887 888 /* Don't wait on WPA mode */ 889 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) { 890 /* wait scan complete */ 891 wifi_wait_scan(ic); 892 } 893 894 wifi_setupoutmsg(mp, 0); 895 return (0); 896 } 897 898 static void 899 wifi_loaddefdata(struct ieee80211com *ic) 900 { 901 struct ieee80211_node *in = ic->ic_bss; 902 int i; 903 904 ic->ic_des_esslen = 0; 905 bzero(ic->ic_des_essid, IEEE80211_NWID_LEN); 906 ic->ic_flags &= ~IEEE80211_F_DESBSSID; 907 bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN); 908 bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN); 909 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 910 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 911 bzero(ic->ic_nickname, IEEE80211_NWID_LEN); 912 in->in_authmode = IEEE80211_AUTH_OPEN; 913 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 914 ic->ic_flags &= ~IEEE80211_F_WPA; /* mask WPA mode */ 915 ic->ic_evq_head = ic->ic_evq_tail = 0; /* reset Queue */ 916 ic->ic_def_txkey = 0; 917 for (i = 0; i < MAX_NWEPKEYS; i++) { 918 ic->ic_nw_keys[i].wk_keylen = 0; 919 bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE); 920 } 921 ic->ic_curmode = IEEE80211_MODE_AUTO; 922 ic->ic_flags &= ~IEEE80211_F_IBSSON; 923 ic->ic_opmode = IEEE80211_M_STA; 924 } 925 926 static int 927 wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp) 928 { 929 wifi_loaddefdata(ic); 930 wifi_setupoutmsg(mp, 0); 931 return (ENETRESET); 932 } 933 934 static int 935 wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp) 936 { 937 if (ic->ic_state != IEEE80211_S_INIT) { 938 IEEE80211_UNLOCK(ic); 939 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 940 IEEE80211_LOCK(ic); 941 } 942 wifi_loaddefdata(ic); 943 wifi_setupoutmsg(mp, 0); 944 return (0); 945 } 946 947 /* 948 * Get the capabilities of drivers. 949 */ 950 static int 951 wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 952 { 953 mblk_t *omp; 954 wldp_t *outp; 955 wl_capability_t *o_caps; 956 int err = 0; 957 958 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL) 959 return (ENOMEM); 960 outp = (wldp_t *)omp->b_rptr; 961 o_caps = (wl_capability_t *)outp->wldp_buf; 962 963 switch (cmd) { 964 case WLAN_GET_PARAM: 965 wl_get_capability(ic, o_caps); 966 break; 967 case WLAN_SET_PARAM: 968 outp->wldp_result = WL_READONLY; 969 err = EINVAL; 970 break; 971 default: 972 ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd); 973 outp->wldp_result = WL_NOTSUPPORTED; 974 err = EINVAL; 975 break; 976 } 977 978 freemsg(*mp); 979 *mp = omp; 980 return (err); 981 } 982 983 /* 984 * Operating on WPA mode. 985 */ 986 static int 987 wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 988 { 989 mblk_t *omp; 990 wldp_t *outp; 991 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 992 wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf; 993 wl_wpa_t *o_wpa; 994 int err = 0; 995 996 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL) 997 return (ENOMEM); 998 outp = (wldp_t *)omp->b_rptr; 999 o_wpa = (wl_wpa_t *)outp->wldp_buf; 1000 1001 switch (cmd) { 1002 case WLAN_GET_PARAM: 1003 wl_get_wpa(ic, o_wpa); 1004 break; 1005 case WLAN_SET_PARAM: 1006 err = wl_set_wpa(ic, wpa); 1007 break; 1008 default: 1009 ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd); 1010 outp->wldp_result = WL_NOTSUPPORTED; 1011 err = EINVAL; 1012 break; 1013 } 1014 1015 freemsg(*mp); 1016 *mp = omp; 1017 return (err); 1018 } 1019 1020 /* 1021 * WPA daemon set the WPA keys. 1022 * The WPA keys are negotiated with APs through wpa service. 1023 */ 1024 static int 1025 wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1026 { 1027 mblk_t *omp; 1028 wldp_t *outp; 1029 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1030 wl_key_t *ik = (wl_key_t *)(inp->wldp_buf); 1031 int err = 0; 1032 1033 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1034 return (ENOMEM); 1035 outp = (wldp_t *)omp->b_rptr; 1036 1037 switch (cmd) { 1038 case WLAN_GET_PARAM: 1039 outp->wldp_result = WL_WRITEONLY; 1040 err = EINVAL; 1041 break; 1042 case WLAN_SET_PARAM: 1043 err = wl_set_wpakey(ic, ik); 1044 break; 1045 default: 1046 ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd); 1047 outp->wldp_result = WL_NOTSUPPORTED; 1048 err = EINVAL; 1049 break; 1050 } 1051 1052 freemsg(*mp); 1053 *mp = omp; 1054 return (err); 1055 } 1056 1057 /* 1058 * Delete obsolete keys - keys are dynamically exchanged between APs 1059 * and wpa daemon. 1060 */ 1061 static int 1062 wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1063 { 1064 mblk_t *omp; 1065 wldp_t *outp; 1066 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1067 wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf; 1068 int err = 0; 1069 1070 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1071 return (ENOMEM); 1072 outp = (wldp_t *)omp->b_rptr; 1073 1074 switch (cmd) { 1075 case WLAN_GET_PARAM: 1076 outp->wldp_result = WL_WRITEONLY; 1077 err = EINVAL; 1078 break; 1079 case WLAN_SET_PARAM: 1080 err = wl_set_delkey(ic, dk); 1081 break; 1082 default: 1083 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1084 outp->wldp_result = WL_NOTSUPPORTED; 1085 err = EINVAL; 1086 break; 1087 } 1088 1089 freemsg(*mp); 1090 *mp = omp; 1091 return (err); 1092 } 1093 1094 /* 1095 * The OPTIE will be used in the association request. 1096 */ 1097 static int 1098 wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1099 { 1100 mblk_t *omp; 1101 wldp_t *outp; 1102 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1103 wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf; 1104 int err = 0; 1105 1106 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1107 return (ENOMEM); 1108 outp = (wldp_t *)omp->b_rptr; 1109 1110 switch (cmd) { 1111 case WLAN_GET_PARAM: 1112 outp->wldp_result = WL_WRITEONLY; 1113 err = EINVAL; 1114 break; 1115 case WLAN_SET_PARAM: 1116 if ((err = wl_set_optie(ic, ie_in)) == EINVAL) 1117 outp->wldp_result = WL_NOTSUPPORTED; 1118 break; 1119 default: 1120 ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd); 1121 outp->wldp_result = WL_NOTSUPPORTED; 1122 err = EINVAL; 1123 break; 1124 } 1125 1126 freemsg(*mp); 1127 *mp = omp; 1128 return (err); 1129 } 1130 1131 /* 1132 * To be compatible with drivers/tools of OpenSolaris.org, 1133 * we use a different ID to filter out those APs of WPA mode. 1134 */ 1135 static int 1136 wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1137 { 1138 mblk_t *omp; 1139 wldp_t *outp; 1140 wl_wpa_ess_t *sr; 1141 ieee80211_node_t *in; 1142 ieee80211_node_table_t *nt; 1143 int len, ap_num = 0; 1144 int err = 0; 1145 1146 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 1147 NULL) { 1148 return (ENOMEM); 1149 } 1150 outp = (wldp_t *)omp->b_rptr; 1151 sr = (wl_wpa_ess_t *)outp->wldp_buf; 1152 sr->count = 0; 1153 1154 switch (cmd) { 1155 case WLAN_GET_PARAM: 1156 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n"); 1157 nt = &ic->ic_scan; 1158 IEEE80211_NODE_LOCK(nt); 1159 in = list_head(&nt->nt_node); 1160 while (in != NULL) { 1161 /* filter out non-WPA APs */ 1162 if (in->in_wpa_ie == NULL) { 1163 in = list_next(&nt->nt_node, in); 1164 continue; 1165 } 1166 bcopy(in->in_bssid, sr->ess[ap_num].bssid, 1167 IEEE80211_ADDR_LEN); 1168 sr->ess[ap_num].ssid_len = in->in_esslen; 1169 bcopy(in->in_essid, sr->ess[ap_num].ssid, 1170 in->in_esslen); 1171 sr->ess[ap_num].freq = in->in_chan->ich_freq; 1172 1173 len = in->in_wpa_ie[1] + 2; 1174 bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len); 1175 sr->ess[ap_num].wpa_ie_len = len; 1176 1177 ap_num ++; 1178 in = list_next(&nt->nt_node, in); 1179 } 1180 IEEE80211_NODE_UNLOCK(nt); 1181 sr->count = ap_num; 1182 outp->wldp_length = WIFI_BUF_OFFSET + 1183 offsetof(wl_wpa_ess_t, ess) + 1184 sr->count * sizeof (struct wpa_ess); 1185 omp->b_wptr = omp->b_rptr + outp->wldp_length; 1186 break; 1187 case WLAN_SET_PARAM: 1188 outp->wldp_result = WL_READONLY; 1189 err = EINVAL; 1190 break; 1191 default: 1192 ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd); 1193 outp->wldp_result = WL_NOTSUPPORTED; 1194 err = EINVAL; 1195 break; 1196 } 1197 1198 freemsg(*mp); 1199 *mp = omp; 1200 return (err); 1201 } 1202 1203 /* 1204 * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC 1205 */ 1206 static int 1207 wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1208 { 1209 mblk_t *omp; 1210 wldp_t *outp; 1211 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1212 wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf; 1213 int err = 0; 1214 1215 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1216 return (ENOMEM); 1217 outp = (wldp_t *)omp->b_rptr; 1218 1219 switch (cmd) { 1220 case WLAN_GET_PARAM: 1221 outp->wldp_result = WL_WRITEONLY; 1222 err = EINVAL; 1223 break; 1224 case WLAN_SET_PARAM: 1225 err = wl_set_mlme(ic, mlme); 1226 break; 1227 default: 1228 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1229 outp->wldp_result = WL_NOTSUPPORTED; 1230 err = EINVAL; 1231 break; 1232 } 1233 1234 freemsg(*mp); 1235 *mp = omp; 1236 return (err); 1237 } 1238 1239 static int 1240 wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd) 1241 { 1242 mblk_t *mp1 = *mp; 1243 wldp_t *wp = (wldp_t *)mp1->b_rptr; 1244 int err = 0; 1245 1246 ASSERT(ic != NULL && mp1 != NULL); 1247 IEEE80211_LOCK_ASSERT(ic); 1248 if (MBLKL(mp1) < WIFI_BUF_OFFSET) { 1249 ieee80211_err("wifi_cfg_getset: " 1250 "invalid input buffer, size=%d\n", MBLKL(mp1)); 1251 return (EINVAL); 1252 } 1253 1254 switch (wp->wldp_id) { 1255 /* Commands */ 1256 case WL_SCAN: 1257 err = wifi_cmd_scan(ic, mp1); 1258 break; 1259 case WL_LOAD_DEFAULTS: 1260 err = wifi_cmd_loaddefaults(ic, mp1); 1261 break; 1262 case WL_DISASSOCIATE: 1263 err = wifi_cmd_disassoc(ic, mp1); 1264 break; 1265 /* Parameters */ 1266 case WL_ESSID: 1267 err = wifi_cfg_essid(ic, cmd, mp); 1268 break; 1269 case WL_BSSID: 1270 err = wifi_cfg_bssid(ic, cmd, mp); 1271 break; 1272 case WL_NODE_NAME: 1273 err = wifi_cfg_nodename(ic, cmd, mp); 1274 break; 1275 case WL_PHY_CONFIG: 1276 err = wifi_cfg_phy(ic, cmd, mp); 1277 break; 1278 case WL_WEP_KEY_TAB: 1279 err = wifi_cfg_wepkey(ic, cmd, mp); 1280 break; 1281 case WL_WEP_KEY_ID: 1282 err = wifi_cfg_keyid(ic, cmd, mp); 1283 break; 1284 case WL_AUTH_MODE: 1285 err = wifi_cfg_authmode(ic, cmd, mp); 1286 break; 1287 case WL_ENCRYPTION: 1288 err = wifi_cfg_encrypt(ic, cmd, mp); 1289 break; 1290 case WL_BSS_TYPE: 1291 err = wifi_cfg_bsstype(ic, cmd, mp); 1292 break; 1293 case WL_CREATE_IBSS: 1294 err = wifi_cfg_createibss(ic, cmd, mp); 1295 break; 1296 case WL_DESIRED_RATES: 1297 err = wifi_cfg_desrates(ic, cmd, mp); 1298 break; 1299 case WL_LINKSTATUS: 1300 err = wifi_cfg_linkstatus(ic, cmd, mp); 1301 break; 1302 case WL_ESS_LIST: 1303 err = wifi_cfg_esslist(ic, cmd, mp); 1304 break; 1305 case WL_SUPPORTED_RATES: 1306 err = wifi_cfg_suprates(ic, cmd, mp); 1307 break; 1308 case WL_RSSI: 1309 err = wifi_cfg_rssi(ic, cmd, mp); 1310 break; 1311 /* 1312 * WPA IOCTLs 1313 */ 1314 case WL_CAPABILITY: 1315 err = wifi_cfg_caps(ic, cmd, mp); 1316 break; 1317 case WL_WPA: 1318 err = wifi_cfg_wpa(ic, cmd, mp); 1319 break; 1320 case WL_KEY: 1321 err = wifi_cfg_wpakey(ic, cmd, mp); 1322 break; 1323 case WL_DELKEY: 1324 err = wifi_cfg_delkey(ic, cmd, mp); 1325 break; 1326 case WL_SETOPTIE: 1327 err = wifi_cfg_setoptie(ic, cmd, mp); 1328 break; 1329 case WL_SCANRESULTS: 1330 err = wifi_cfg_scanresults(ic, cmd, mp); 1331 break; 1332 case WL_MLME: 1333 err = wifi_cfg_setmlme(ic, cmd, mp); 1334 break; 1335 default: 1336 wifi_setupoutmsg(mp1, 0); 1337 wp->wldp_result = WL_LACK_FEATURE; 1338 err = ENOTSUP; 1339 break; 1340 } 1341 1342 return (err); 1343 } 1344 1345 /* 1346 * Typically invoked by drivers in response to requests for 1347 * information or to change settings from the userland. 1348 * 1349 * Return value should be checked by WiFi drivers. Return 0 1350 * on success. Otherwise, return non-zero value to indicate 1351 * the error. Driver should operate as below when the return 1352 * error is: 1353 * ENETRESET Reset wireless network and re-start to join a 1354 * WLAN. ENETRESET is returned when a configuration 1355 * parameter has been changed. 1356 * When acknowledge a M_IOCTL message, thie error 1357 * is ignored. 1358 */ 1359 int 1360 ieee80211_ioctl(struct ieee80211com *ic, queue_t *wq, mblk_t *mp) 1361 { 1362 struct iocblk *iocp; 1363 int32_t cmd, err, len; 1364 boolean_t need_privilege; 1365 mblk_t *mp1; 1366 1367 if (MBLKL(mp) < sizeof (struct iocblk)) { 1368 ieee80211_err("ieee80211_ioctl: ioctl buffer too short, %u\n", 1369 MBLKL(mp)); 1370 miocnak(wq, mp, 0, EINVAL); 1371 return (EINVAL); 1372 } 1373 1374 /* 1375 * Validate the command 1376 */ 1377 iocp = (struct iocblk *)mp->b_rptr; 1378 iocp->ioc_error = 0; 1379 cmd = iocp->ioc_cmd; 1380 need_privilege = B_TRUE; 1381 switch (cmd) { 1382 case WLAN_SET_PARAM: 1383 case WLAN_COMMAND: 1384 break; 1385 case WLAN_GET_PARAM: 1386 need_privilege = B_FALSE; 1387 break; 1388 default: 1389 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): " 1390 "unknown cmd 0x%x\n", cmd); 1391 miocnak(wq, mp, 0, EINVAL); 1392 return (EINVAL); 1393 } 1394 1395 if (need_privilege && (err = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 1396 miocnak(wq, mp, 0, err); 1397 return (err); 1398 } 1399 1400 IEEE80211_LOCK(ic); 1401 1402 /* sanity check */ 1403 mp1 = mp->b_cont; 1404 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 1405 mp1 == NULL) { 1406 miocnak(wq, mp, 0, EINVAL); 1407 IEEE80211_UNLOCK(ic); 1408 return (EINVAL); 1409 } 1410 1411 /* assuming single data block */ 1412 if (mp1->b_cont != NULL) { 1413 freemsg(mp1->b_cont); 1414 mp1->b_cont = NULL; 1415 } 1416 1417 err = wifi_cfg_getset(ic, &mp1, cmd); 1418 mp->b_cont = mp1; 1419 IEEE80211_UNLOCK(ic); 1420 1421 len = msgdsize(mp1); 1422 /* ignore ENETRESET when acknowledge the M_IOCTL message */ 1423 if (err == 0 || err == ENETRESET) 1424 miocack(wq, mp, len, 0); 1425 else 1426 miocack(wq, mp, len, err); 1427 1428 return (err); 1429 } 1430 1431 /* 1432 * The following routines are for brussels support 1433 */ 1434 1435 /* 1436 * MAC_PROP_WL_ESSID 1437 */ 1438 static int 1439 wl_set_essid(struct ieee80211com *ic, const void *wldp_buf) 1440 { 1441 int err = 0; 1442 char *essid; 1443 wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf; 1444 1445 if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN) { 1446 ieee80211_err("wl_set_essid: " 1447 "essid too long, %u, max %u\n", 1448 iw_essid->wl_essid_length, IEEE80211_NWID_LEN); 1449 1450 err = EINVAL; 1451 return (err); 1452 } 1453 1454 essid = iw_essid->wl_essid_essid; 1455 essid[IEEE80211_NWID_LEN] = 0; 1456 1457 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_essid: " 1458 "set essid=%s length=%d\n", 1459 essid, iw_essid->wl_essid_length); 1460 1461 ic->ic_des_esslen = iw_essid->wl_essid_length; 1462 if (ic->ic_des_esslen != 0) 1463 bcopy(essid, ic->ic_des_essid, ic->ic_des_esslen); 1464 if (ic->ic_des_esslen < IEEE80211_NWID_LEN) 1465 ic->ic_des_essid[ic->ic_des_esslen] = 0; 1466 1467 err = ENETRESET; 1468 1469 return (err); 1470 } 1471 1472 static void 1473 wl_get_essid(struct ieee80211com *ic, void *wldp_buf) 1474 { 1475 char *essid; 1476 wl_essid_t ow_essid; 1477 1478 essid = (char *)ic->ic_des_essid; 1479 if (essid[0] == '\0') 1480 essid = (char *)ic->ic_bss->in_essid; 1481 1482 bzero(&ow_essid, sizeof (wl_essid_t)); 1483 ow_essid.wl_essid_length = wifi_strnlen((const char *)essid, 1484 IEEE80211_NWID_LEN); 1485 bcopy(essid, ow_essid.wl_essid_essid, 1486 ow_essid.wl_essid_length); 1487 bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t)); 1488 1489 } 1490 1491 /* 1492 * MAC_PROP_WL_BSSID 1493 */ 1494 static int 1495 wl_set_bssid(struct ieee80211com *ic, const void* wldp_buf) 1496 { 1497 1498 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bssid: " 1499 "set bssid=%s\n", 1500 ieee80211_macaddr_sprintf(wldp_buf)); 1501 1502 bcopy(wldp_buf, ic->ic_des_bssid, sizeof (wl_bssid_t)); 1503 ic->ic_flags |= IEEE80211_F_DESBSSID; 1504 1505 return (ENETRESET); 1506 } 1507 1508 static void 1509 wl_get_bssid(struct ieee80211com *ic, void *wldp_buf) 1510 { 1511 uint8_t *bssid; 1512 1513 if (ic->ic_flags & IEEE80211_F_DESBSSID) 1514 bssid = ic->ic_des_bssid; 1515 else 1516 bssid = ic->ic_bss->in_bssid; 1517 bcopy(bssid, wldp_buf, sizeof (wl_bssid_t)); 1518 1519 } 1520 1521 /* 1522 * MAC_PROP_WL_BSSTYP 1523 */ 1524 static int 1525 wl_set_bsstype(struct ieee80211com *ic, const void *wldp_buf) 1526 { 1527 int err = 0; 1528 wl_bss_type_t *iw_opmode = (wl_bss_type_t *)wldp_buf; 1529 1530 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bsstype: " 1531 "set bsstype=%u\n", *iw_opmode); 1532 1533 switch (*iw_opmode) { 1534 case WL_BSS_BSS: 1535 ic->ic_flags &= ~IEEE80211_F_IBSSON; 1536 ic->ic_opmode = IEEE80211_M_STA; 1537 err = ENETRESET; 1538 break; 1539 case WL_BSS_IBSS: 1540 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) { 1541 err = ENOTSUP; 1542 break; 1543 } 1544 1545 ic->ic_opmode = IEEE80211_M_IBSS; 1546 err = ENETRESET; 1547 break; 1548 default: 1549 ieee80211_err("wl_set_bsstype: " 1550 "unknown opmode\n"); 1551 err = EINVAL; 1552 break; 1553 } 1554 return (err); 1555 } 1556 1557 static void 1558 wl_get_bsstype(struct ieee80211com *ic, void *wldp_buf) 1559 { 1560 wl_bss_type_t ow_opmode; 1561 1562 switch (ic->ic_opmode) { 1563 case IEEE80211_M_STA: 1564 ow_opmode = WL_BSS_BSS; 1565 break; 1566 case IEEE80211_M_IBSS: 1567 ow_opmode = WL_BSS_IBSS; 1568 break; 1569 default: 1570 ow_opmode = WL_BSS_ANY; 1571 break; 1572 } 1573 1574 bcopy(&ow_opmode, wldp_buf, sizeof (wl_bss_type_t)); 1575 } 1576 1577 /* 1578 * MAC_PROP_WL_LINKSTATUS 1579 */ 1580 static void 1581 wl_get_linkstatus(struct ieee80211com *ic, void *wldp_buf) 1582 { 1583 wl_linkstatus_t ow_linkstat; 1584 1585 ow_linkstat = (ic->ic_state == IEEE80211_S_RUN) ? 1586 WL_CONNECTED : WL_NOTCONNECTED; 1587 if ((ic->ic_flags & IEEE80211_F_WPA) && 1588 (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA)) { 1589 ow_linkstat = WL_NOTCONNECTED; 1590 } 1591 1592 bcopy(&ow_linkstat, wldp_buf, sizeof (wl_linkstatus_t)); 1593 } 1594 1595 /* 1596 * MAC_PROP_WL_DESIRED_RATESa 1597 */ 1598 static int 1599 wl_set_desrates(struct ieee80211com *ic, const void *wldp_buf) 1600 { 1601 int err = 0; 1602 int i, j; 1603 uint8_t drate; 1604 boolean_t isfound; 1605 wl_rates_t *iw_rates = (wl_rates_t *)wldp_buf; 1606 struct ieee80211_node *in = ic->ic_bss; 1607 struct ieee80211_rateset *rs = &in->in_rates; 1608 1609 drate = iw_rates->wl_rates_rates[0]; 1610 if (ic->ic_fixed_rate == drate) 1611 return (err); 1612 1613 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_desrates: " 1614 "set desired rate=%u\n", drate); 1615 1616 if (drate == 0) { 1617 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 1618 if (ic->ic_state == IEEE80211_S_RUN) { 1619 IEEE80211_UNLOCK(ic); 1620 ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0); 1621 IEEE80211_LOCK(ic); 1622 } 1623 return (err); 1624 } 1625 1626 /* 1627 * Set desired rate. The desired rate is for data transfer 1628 * and usally is checked and used when driver changes to 1629 * RUN state. 1630 * If the driver is in AUTH | ASSOC | RUN state, desired 1631 * rate is checked anainst rates supported by current ESS. 1632 * If it's supported and current state is AUTH|ASSOC, nothing 1633 * needs to be done by driver since the desired rate will 1634 * be enabled when the device changes to RUN state. And 1635 * when current state is RUN, Re-associate with the ESS to 1636 * enable the desired rate. 1637 */ 1638 1639 if (ic->ic_state != IEEE80211_S_INIT && 1640 ic->ic_state != IEEE80211_S_SCAN) { 1641 for (i = 0; i < rs->ir_nrates; i++) { 1642 if (drate == IEEE80211_RV(rs->ir_rates[i])) 1643 break; 1644 } 1645 /* supported */ 1646 if (i < rs->ir_nrates) { 1647 ic->ic_fixed_rate = drate; 1648 if (ic->ic_state == IEEE80211_S_RUN) { 1649 IEEE80211_UNLOCK(ic); 1650 ieee80211_new_state(ic, 1651 IEEE80211_S_ASSOC, 0); 1652 IEEE80211_LOCK(ic); 1653 } 1654 return (err); 1655 } 1656 } 1657 1658 /* 1659 * In INIT or SCAN state 1660 * check if the desired rate is supported by device 1661 */ 1662 isfound = B_FALSE; 1663 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 1664 rs = &ic->ic_sup_rates[i]; 1665 for (j = 0; j < rs->ir_nrates; j++) { 1666 if (drate == IEEE80211_RV(rs->ir_rates[j])) { 1667 isfound = B_TRUE; 1668 break; 1669 } 1670 } 1671 if (isfound) 1672 break; 1673 } 1674 if (!isfound) { 1675 ieee80211_err("wl_set_desrates: " 1676 "invald rate %d\n", drate); 1677 err = EINVAL; 1678 return (err); 1679 } 1680 ic->ic_fixed_rate = drate; 1681 if (ic->ic_state != IEEE80211_S_SCAN) 1682 err = ENETRESET; 1683 1684 return (err); 1685 } 1686 1687 static void 1688 wl_get_desrates(struct ieee80211com *ic, void *wldp_buf) 1689 { 1690 uint8_t srate; 1691 wl_rates_t ow_rates; 1692 struct ieee80211_node *in = ic->ic_bss; 1693 struct ieee80211_rateset *rs = &in->in_rates; 1694 1695 srate = rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL; 1696 ow_rates.wl_rates_num = 1; 1697 ow_rates.wl_rates_rates[0] = 1698 (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 1699 srate : ic->ic_fixed_rate; 1700 bcopy(&ow_rates, wldp_buf, sizeof (wl_rates_t)); 1701 1702 } 1703 1704 /* 1705 * MAC_PROP_AUTH_MODE 1706 */ 1707 static int 1708 wl_set_authmode(struct ieee80211com *ic, const void *wldp_buf) 1709 { 1710 int err = 0; 1711 wl_authmode_t *iw_auth = (wl_authmode_t *)wldp_buf; 1712 1713 if (*iw_auth == ic->ic_bss->in_authmode) 1714 return (err); 1715 1716 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_authmode: " 1717 "set authmode=%u\n", *iw_auth); 1718 1719 switch (*iw_auth) { 1720 case WL_OPENSYSTEM: 1721 case WL_SHAREDKEY: 1722 ic->ic_bss->in_authmode = *iw_auth; 1723 err = ENETRESET; 1724 break; 1725 default: 1726 ieee80211_err("wl_set_authmode: " 1727 "unknown authmode %u\n", *iw_auth); 1728 err = EINVAL; 1729 break; 1730 } 1731 1732 return (err); 1733 } 1734 1735 static void 1736 wl_get_authmode(struct ieee80211com *ic, void *wldp_buf) 1737 { 1738 wl_authmode_t ow_auth; 1739 1740 ow_auth = ic->ic_bss->in_authmode; 1741 bcopy(&ow_auth, wldp_buf, sizeof (wl_authmode_t)); 1742 1743 } 1744 1745 /* 1746 * MAC_PROP_WL_ENCRYPTION 1747 */ 1748 static int 1749 wl_set_encrypt(struct ieee80211com *ic, const void *wldp_buf) 1750 { 1751 int err = 0; 1752 uint32_t flags; 1753 wl_encryption_t *iw_encryp = (wl_encryption_t *)wldp_buf; 1754 1755 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_encrypt: " 1756 "set encryption=%u\n", *iw_encryp); 1757 1758 flags = ic->ic_flags; 1759 if (*iw_encryp == WL_NOENCRYPTION) 1760 flags &= ~IEEE80211_F_PRIVACY; 1761 else 1762 flags |= IEEE80211_F_PRIVACY; 1763 1764 if (ic->ic_flags != flags) { 1765 ic->ic_flags = flags; 1766 err = ENETRESET; 1767 } 1768 1769 return (err); 1770 } 1771 1772 static void 1773 wl_get_encrypt(struct ieee80211com *ic, void *wldp_buf) 1774 { 1775 wl_encryption_t *ow_encryp; 1776 1777 ow_encryp = (wl_encryption_t *)wldp_buf; 1778 *ow_encryp = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0; 1779 if (ic->ic_flags & IEEE80211_F_WPA) 1780 *ow_encryp = WL_ENC_WPA; 1781 1782 } 1783 1784 /* 1785 * MAC_PROP_WL_RSSI 1786 */ 1787 static void 1788 wl_get_rssi(struct ieee80211com *ic, void *wldp_buf) 1789 { 1790 wl_rssi_t *ow_rssi; 1791 1792 ow_rssi = (wl_rssi_t *)wldp_buf; 1793 *ow_rssi = wifi_getrssi(ic->ic_bss); 1794 1795 } 1796 1797 /* 1798 * MAC_PROP_WL_PHY_CONFIG 1799 */ 1800 1801 static int 1802 wl_set_phy(struct ieee80211com *ic, const void* wldp_buf) 1803 { 1804 int err = 0; 1805 int16_t ch; 1806 wl_dsss_t *dsss; 1807 wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)wldp_buf; 1808 1809 dsss = (wl_dsss_t *)iw_phy; 1810 ch = dsss->wl_dsss_channel; 1811 1812 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_phy: " 1813 "set channel=%d\n", ch); 1814 1815 if (ch == 0 || ch == (int16_t)IEEE80211_CHAN_ANY) { 1816 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 1817 } else if ((uint_t)ch > IEEE80211_CHAN_MAX || 1818 ieee80211_isclr(ic->ic_chan_active, ch)) { 1819 err = EINVAL; 1820 return (err); 1821 } else { 1822 ic->ic_des_chan = ic->ic_ibss_chan = 1823 &ic->ic_sup_channels[ch]; 1824 } 1825 1826 switch (ic->ic_state) { 1827 case IEEE80211_S_INIT: 1828 case IEEE80211_S_SCAN: 1829 err = ENETRESET; 1830 break; 1831 default: 1832 /* 1833 * If hte desired channel has changed (to something 1834 * other than any) and we're not already scanning, 1835 * then kick the state machine. 1836 */ 1837 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 1838 ic->ic_bss->in_chan != ic->ic_des_chan && 1839 (ic->ic_flags & IEEE80211_F_SCAN) == 0) 1840 err = ENETRESET; 1841 break; 1842 } 1843 1844 return (err); 1845 } 1846 1847 #define WIFI_HT_MODE(in) (((in)->in_flags & IEEE80211_NODE_HT) ? 1 : 0) 1848 1849 static int 1850 wl_get_phy(struct ieee80211com *ic, void *wldp_buf) 1851 { 1852 int err = 0; 1853 wl_phy_conf_t *ow_phy; 1854 struct ieee80211_channel *ch = ic->ic_curchan; 1855 struct ieee80211_node *in = ic->ic_bss; 1856 1857 ow_phy = (wl_phy_conf_t *)wldp_buf; 1858 bzero(wldp_buf, sizeof (wl_phy_conf_t)); 1859 1860 /* get current phy parameters: FH|DS|ERP */ 1861 if (IEEE80211_IS_CHAN_A(ch) || IEEE80211_IS_CHAN_T(ch)) { 1862 wl_ofdm_t *ofdm = (wl_ofdm_t *)ow_phy; 1863 ofdm->wl_ofdm_subtype = WL_OFDM; 1864 ofdm->wl_ofdm_frequency = ch->ich_freq; 1865 ofdm->wl_ofdm_ht_enabled = WIFI_HT_MODE(in); 1866 } else { 1867 switch (ic->ic_phytype) { 1868 case IEEE80211_T_FH: { 1869 wl_fhss_t *fhss = (wl_fhss_t *)ow_phy; 1870 fhss->wl_fhss_subtype = WL_FHSS; 1871 fhss->wl_fhss_channel = 1872 ieee80211_chan2ieee(ic, ch); 1873 break; 1874 } 1875 case IEEE80211_T_DS: { 1876 wl_dsss_t *dsss = (wl_dsss_t *)ow_phy; 1877 dsss->wl_dsss_subtype = WL_DSSS; 1878 dsss->wl_dsss_channel = 1879 ieee80211_chan2ieee(ic, ch); 1880 break; 1881 } 1882 case IEEE80211_T_OFDM: { 1883 wl_erp_t *erp = (wl_erp_t *)ow_phy; 1884 erp->wl_erp_subtype = WL_ERP; 1885 erp->wl_erp_channel = 1886 ieee80211_chan2ieee(ic, ch); 1887 erp->wl_erp_ht_enabled = WIFI_HT_MODE(in); 1888 break; 1889 } 1890 default: 1891 ieee80211_err("wl_get_phy: " 1892 "unknown phy type, %x\n", ic->ic_phytype); 1893 err = EIO; 1894 break; 1895 } 1896 } 1897 1898 return (err); 1899 } 1900 1901 /* 1902 * MAC_PROP_WL_CAPABILITY 1903 */ 1904 static void 1905 wl_get_capability(struct ieee80211com *ic, void *wldp_buf) 1906 { 1907 wl_capability_t ow_caps; 1908 1909 ow_caps.caps = ic->ic_caps; 1910 bcopy(&ow_caps, wldp_buf, sizeof (wl_capability_t)); 1911 1912 } 1913 1914 /* 1915 * MAC_PROP_WL_WPA 1916 */ 1917 static int 1918 wl_set_wpa(struct ieee80211com *ic, const void *wldp_buf) 1919 { 1920 int err = 0; 1921 wl_wpa_t *wpa = (wl_wpa_t *)wldp_buf; 1922 1923 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpa: " 1924 "set wpa=%u\n", wpa->wpa_flag); 1925 1926 if (wpa->wpa_flag > 0) { 1927 /* enable wpa mode */ 1928 ic->ic_flags |= IEEE80211_F_PRIVACY; 1929 ic->ic_flags |= IEEE80211_F_WPA; 1930 } else { 1931 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 1932 ic->ic_flags &= ~IEEE80211_F_WPA; 1933 } 1934 1935 return (err); 1936 } 1937 1938 static void 1939 wl_get_wpa(struct ieee80211com *ic, void *wldp_buf) 1940 { 1941 wl_wpa_t *wpa; 1942 1943 wpa = (wl_wpa_t *)wldp_buf; 1944 wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA) ? 1 : 0); 1945 1946 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_get_wpa: " 1947 "get wpa=%u\n", wpa->wpa_flag); 1948 1949 } 1950 1951 /* 1952 * MAC_PROP_WL_SCANRESULTS 1953 */ 1954 1955 static void 1956 wl_get_scanresults(struct ieee80211com *ic, void *wldp_buf) 1957 { 1958 wl_wpa_ess_t *sr; 1959 ieee80211_node_t *in; 1960 ieee80211_node_table_t *nt; 1961 int ap_num; 1962 int len; 1963 1964 sr = (wl_wpa_ess_t *)wldp_buf; 1965 sr->count = 0; 1966 ap_num = 0; 1967 1968 ieee80211_dbg(IEEE80211_MSG_WPA, "wl_get_scanrelults\n"); 1969 1970 nt = &ic->ic_scan; 1971 IEEE80211_NODE_LOCK(nt); 1972 in = list_head(&nt->nt_node); 1973 1974 while (in != NULL) { 1975 /* filter out non-wpa APs */ 1976 if (in->in_wpa_ie == NULL) { 1977 in = list_next(&nt->nt_node, in); 1978 continue; 1979 } 1980 bcopy(in->in_bssid, sr->ess[ap_num].bssid, 1981 IEEE80211_ADDR_LEN); 1982 sr->ess[ap_num].ssid_len = in->in_esslen; 1983 bcopy(in->in_essid, sr->ess[ap_num].ssid, 1984 in->in_esslen); 1985 sr->ess[ap_num].freq = in->in_chan->ich_freq; 1986 1987 len = in->in_wpa_ie[1] + 2; 1988 bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len); 1989 sr->ess[ap_num].wpa_ie_len = len; 1990 1991 ap_num++; 1992 in = list_next(&nt->nt_node, in); 1993 } 1994 IEEE80211_NODE_UNLOCK(nt); 1995 sr->count = ap_num; 1996 1997 } 1998 1999 /* 2000 * MAC_PROP_WL_ESS_LIST 2001 */ 2002 static void 2003 wl_get_esslist(struct ieee80211com *ic, void *wldp_buf) 2004 { 2005 wl_ess_list_t *ess_list; 2006 2007 ess_list = (wl_ess_list_t *)wldp_buf; 2008 2009 ess_list->wl_ess_list_num = 0; 2010 ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ess_list); 2011 2012 } 2013 2014 /* 2015 * MAC_PROP_WL_WEP_KEY 2016 */ 2017 static int 2018 wl_set_wepkey(struct ieee80211com *ic, const void *wldp_buf) 2019 { 2020 int err = 0; 2021 uint16_t i; 2022 uint32_t klen; 2023 struct ieee80211_key *key; 2024 wl_wep_key_t *wepkey = (wl_wep_key_t *)wldp_buf; 2025 2026 /* set all valid keys */ 2027 for (i = 0; i < MAX_NWEPKEYS; i++) { 2028 if (wepkey[i].wl_wep_operation != WL_ADD) 2029 continue; 2030 klen = wepkey[i].wl_wep_length; 2031 if (klen > IEEE80211_KEYBUF_SIZE) { 2032 ieee80211_err("wl_set_wepkey: " 2033 "invalid wepkey length, %u\n", klen); 2034 err = EINVAL; 2035 continue; /* continue to set other keys */ 2036 } 2037 if (klen == 0) 2038 continue; 2039 2040 /* 2041 * Set key contents. Only WEP is supported 2042 */ 2043 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_wepkey: " 2044 "set key %u, len=%u\n", i, klen); 2045 key = &ic->ic_nw_keys[i]; 2046 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP, 2047 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key) == 0) { 2048 ieee80211_err("wl_set_wepkey: " 2049 "abort, create key failed. id=%u\n", i); 2050 err = EIO; 2051 continue; 2052 } 2053 2054 key->wk_keyix = i; 2055 key->wk_keylen = (uint8_t)klen; 2056 key->wk_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 2057 bzero(key->wk_key, IEEE80211_KEYBUF_SIZE); 2058 bcopy(wepkey[i].wl_wep_key, key->wk_key, klen); 2059 if (ieee80211_crypto_setkey(ic, key, ic->ic_macaddr) 2060 == 0) { 2061 ieee80211_err("wl_set_wepkey: " 2062 "set key failed len=%u\n", klen); 2063 err = EIO; 2064 } 2065 } 2066 if (err == 0) 2067 err = ENETRESET; 2068 2069 return (err); 2070 } 2071 2072 /* 2073 * MAC_PROP_WL_SETOPTIE 2074 */ 2075 static int 2076 wl_set_optie(struct ieee80211com *ic, const void *wldp_buf) 2077 { 2078 int err = 0; 2079 char *ie; 2080 wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)wldp_buf; 2081 2082 if (ic->ic_opmode != IEEE80211_M_STA) { 2083 ieee80211_err("wl_set_optie: opmode err\n"); 2084 err = EINVAL; 2085 return (err); 2086 } 2087 if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) { 2088 2089 ieee80211_err("wl_set_optie: optie is too long\n"); 2090 2091 err = EINVAL; 2092 return (err); 2093 } 2094 2095 ie = ieee80211_malloc(ie_in->wpa_ie_len); 2096 (void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len); 2097 if (ic->ic_opt_ie != NULL) { 2098 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, 2099 "wl_set_optie:ic_opt_ie!=NULL\n"); 2100 ieee80211_free(ic->ic_opt_ie); 2101 } 2102 ic->ic_opt_ie = ie; 2103 ic->ic_opt_ie_len = ie_in->wpa_ie_len; 2104 2105 return (err); 2106 } 2107 2108 /* 2109 * MAC_PROP_WL_DELKEY 2110 */ 2111 static int 2112 wl_set_delkey(struct ieee80211com *ic, const void *wldp_buf) 2113 { 2114 int err = 0; 2115 int kid; 2116 wl_del_key_t *dk = (wl_del_key_t *)wldp_buf; 2117 2118 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_delkey(): " 2119 "keyix=%d\n", dk->idk_keyix); 2120 2121 kid = dk->idk_keyix; 2122 2123 if (kid == IEEE80211_KEYIX_NONE || 2124 kid >= IEEE80211_WEP_NKID) { 2125 ieee80211_err("wl_set_delkey: incorrect keyix\n"); 2126 err = EINVAL; 2127 return (err); 2128 } else { 2129 (void) ieee80211_crypto_delkey(ic, 2130 &ic->ic_nw_keys[kid]); 2131 ieee80211_mac_update(ic); 2132 } 2133 2134 return (err); 2135 } 2136 2137 /* 2138 * MAC_PROP_WL_MLME 2139 */ 2140 2141 static int 2142 wl_set_mlme(struct ieee80211com *ic, const void *wldp_buf) 2143 { 2144 int err = 0; 2145 uint32_t flags; 2146 ieee80211_node_t *in; 2147 wl_mlme_t *mlme = (wl_mlme_t *)wldp_buf; 2148 2149 ieee80211_dbg(IEEE80211_MSG_WPA, "wl_set_mlme: " 2150 "op=%d\n", mlme->im_op); 2151 2152 switch (mlme->im_op) { 2153 case IEEE80211_MLME_DISASSOC: 2154 case IEEE80211_MLME_DEAUTH: 2155 if (ic->ic_opmode == IEEE80211_M_STA) { 2156 /* 2157 * Mask ic_flags of IEEE80211_F_WPA to disable 2158 * ieee80211_notify temporarily. 2159 */ 2160 flags = ic->ic_flags; 2161 ic->ic_flags &= ~IEEE80211_F_WPA; 2162 2163 IEEE80211_UNLOCK(ic); 2164 ieee80211_new_state(ic, IEEE80211_S_INIT, 2165 mlme->im_reason); 2166 IEEE80211_LOCK(ic); 2167 2168 ic->ic_flags = flags; 2169 } 2170 break; 2171 case IEEE80211_MLME_ASSOC: 2172 if (ic->ic_opmode != IEEE80211_M_STA) { 2173 ieee80211_err("wifi_cfg_setmlme: opmode err\n"); 2174 err = EINVAL; 2175 break; 2176 } 2177 if (ic->ic_des_esslen != 0) { 2178 /* 2179 * Desired ssid specified; must match both bssid and 2180 * ssid to distinguish ap advertising multiple ssid's. 2181 */ 2182 in = ieee80211_find_node_with_ssid(&ic->ic_scan, 2183 mlme->im_macaddr, 2184 ic->ic_des_esslen, 2185 ic->ic_des_essid); 2186 } else { 2187 /* 2188 * Normal case; just match bssid. 2189 */ 2190 in = ieee80211_find_node(&ic->ic_scan, 2191 mlme->im_macaddr); 2192 } 2193 if (in == NULL) { 2194 ieee80211_err("wifi_cfg_setmlme: " 2195 "no matched node\n"); 2196 err = EINVAL; 2197 break; 2198 } 2199 IEEE80211_UNLOCK(ic); 2200 ieee80211_sta_join(ic, in); 2201 IEEE80211_LOCK(ic); 2202 break; 2203 default: 2204 err = EINVAL; 2205 break; 2206 } 2207 2208 return (err); 2209 } 2210 2211 /* 2212 * MAC_PROP_WL_WPA_KEY 2213 */ 2214 static int 2215 wl_set_wpakey(struct ieee80211com *ic, const void *wldp_buf) 2216 { 2217 int err = 0; 2218 uint16_t kid; 2219 struct ieee80211_node *in; 2220 struct ieee80211_key *wk; 2221 wl_key_t ik; 2222 2223 bcopy(wldp_buf, &ik, sizeof (wl_key_t)); 2224 2225 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpakey: " 2226 "idx=%d\n", ik.ik_keyix); 2227 2228 /* 2229 * cipher support is verified by ieee80211_crypt_newkey 2230 * this also checks ik.ik_keylen > sizeof(wk->wk_key) 2231 */ 2232 if (ik.ik_keylen > sizeof (ik.ik_keydata)) { 2233 ieee80211_err("wl_set_wpakey: key is too long\n"); 2234 err = EINVAL; 2235 return (err); 2236 } 2237 kid = ik.ik_keyix; 2238 if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) { 2239 ieee80211_err("wl_set_wpakey: incorrect keyix\n"); 2240 err = EINVAL; 2241 return (err); 2242 } else { 2243 wk = &ic->ic_nw_keys[kid]; 2244 /* 2245 * Globle slots start off w/o any assigned key index. 2246 * Force one here for consistency with WEPKEY. 2247 */ 2248 if (wk->wk_keyix == IEEE80211_KEYIX_NONE) 2249 wk->wk_keyix = kid; 2250 in = NULL; 2251 } 2252 2253 KEY_UPDATE_BEGIN(ic); 2254 if (ieee80211_crypto_newkey(ic, ik.ik_type, 2255 ik.ik_flags, wk)) { 2256 wk->wk_keylen = ik.ik_keylen; 2257 /* MIC presence is implied by cipher type */ 2258 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE) 2259 wk->wk_keylen = IEEE80211_KEYBUF_SIZE; 2260 wk->wk_keyrsc = ik.ik_keyrsc; 2261 wk->wk_keytsc = 0; 2262 wk->wk_flags |= ik.ik_flags & 2263 (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV); 2264 (void) memset(wk->wk_key, 0, sizeof (wk->wk_key)); 2265 (void) memcpy(wk->wk_key, ik.ik_keydata, 2266 ik.ik_keylen); 2267 if (!ieee80211_crypto_setkey(ic, wk, 2268 in != NULL ? in->in_macaddr : ik.ik_macaddr)) { 2269 err = EIO; 2270 } else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT)) { 2271 ic->ic_def_txkey = kid; 2272 ieee80211_mac_update(ic); 2273 } 2274 } else { 2275 err = EIO; 2276 } 2277 KEY_UPDATE_END(ic); 2278 2279 return (err); 2280 } 2281 2282 /* 2283 * MAC_PROP_WL_SUP_RATE 2284 */ 2285 static void 2286 wl_get_suprates(struct ieee80211com *ic, void *wldp_buf) 2287 { 2288 int i, j, k, l; 2289 uint8_t srates; 2290 uint8_t *drates; 2291 wl_rates_t *wl_rates; 2292 const struct ieee80211_rateset *srs; 2293 2294 wl_rates = (wl_rates_t *)wldp_buf; 2295 2296 wl_rates->wl_rates_num = 0; 2297 drates = (uint8_t *)wl_rates->wl_rates_rates; 2298 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 2299 srs = &ic->ic_sup_rates[i]; 2300 if (srs->ir_nrates == 0) 2301 continue; 2302 for (j = 0; j < srs->ir_nrates; j++) { 2303 srates = IEEE80211_RV(srs->ir_rates[j]); 2304 /* sort & skip duplicated rates */ 2305 for (k = 0; k < wl_rates->wl_rates_num; k++) { 2306 if (srates <= drates[k]) 2307 break; 2308 } 2309 if (srates == drates[k]) 2310 /* skip duplicated rates */ 2311 continue; 2312 /* sort */ 2313 for (l = wl_rates->wl_rates_num; l > k; l--) 2314 drates[l] = drates[l-1]; 2315 drates[k] = srates; 2316 wl_rates->wl_rates_num++; 2317 } 2318 } 2319 2320 } 2321 2322 /* 2323 * MAC_PROP_WL_CREATE_IBSS 2324 */ 2325 static int 2326 wl_set_createibss(struct ieee80211com *ic, const void *wldp_buf) 2327 { 2328 wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)wldp_buf; 2329 int err = 0; 2330 2331 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_ibss: " 2332 "set createibss=%u\n", *iw_ibss); 2333 2334 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) { 2335 err = ENOTSUP; 2336 return (err); 2337 } 2338 if (*iw_ibss) { 2339 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 2340 ic->ic_flags |= IEEE80211_F_IBSSON; 2341 ic->ic_opmode = IEEE80211_M_IBSS; 2342 /* 2343 * Yech, slot time may change depending on the 2344 * operating mode so reset it to be sure 2345 * everything is setup appropriately. 2346 */ 2347 ieee80211_reset_erp(ic); 2348 err = ENETRESET; 2349 } 2350 } else { 2351 if (ic->ic_flags & IEEE80211_F_IBSSON) { 2352 ic->ic_flags &= ~IEEE80211_F_IBSSON; 2353 err = ENETRESET; 2354 } 2355 } 2356 2357 return (err); 2358 } 2359 2360 static void 2361 wl_get_createibss(struct ieee80211com *ic, void *wldp_buf) 2362 { 2363 wl_create_ibss_t *ow_ibss = (wl_create_ibss_t *)wldp_buf; 2364 2365 *ow_ibss = (ic->ic_flags & IEEE80211_F_IBSSON)? 1 : 0; 2366 } 2367 2368 /* 2369 * Typically invoked by drivers in response to request for 2370 * information or to change settings from the userland. 2371 * 2372 * Return value should be checked by WiFI drivers. Return 0 2373 * on success. Otherwise, return non-zero value to indicate 2374 * the error. Driver should operate as below when the return 2375 * error is: 2376 * ENETRESET Reset wireless network and re-start to join a 2377 * WLAN, ENETRESET is returned when a configuration 2378 * parameter has been changed. 2379 * When acknowledge a M_IOCTL message, this error 2380 * is ignored 2381 */ 2382 /* ARGSUSED */ 2383 int 2384 ieee80211_setprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2385 uint_t wldp_length, const void *wldp_buf) 2386 { 2387 int err = 0; 2388 struct ieee80211com *ic = ic_arg; 2389 2390 ASSERT(ic != NULL); 2391 IEEE80211_LOCK(ic); 2392 2393 switch (wldp_pr_num) { 2394 /* mac_prop_id */ 2395 case MAC_PROP_WL_ESSID: 2396 err = wl_set_essid(ic, wldp_buf); 2397 break; 2398 case MAC_PROP_WL_BSSID: 2399 err = wl_set_bssid(ic, wldp_buf); 2400 break; 2401 case MAC_PROP_WL_PHY_CONFIG: 2402 err = wl_set_phy(ic, wldp_buf); 2403 break; 2404 case MAC_PROP_WL_KEY_TAB: 2405 err = wl_set_wepkey(ic, wldp_buf); 2406 break; 2407 case MAC_PROP_WL_AUTH_MODE: 2408 err = wl_set_authmode(ic, wldp_buf); 2409 break; 2410 case MAC_PROP_WL_ENCRYPTION: 2411 err = wl_set_encrypt(ic, wldp_buf); 2412 break; 2413 case MAC_PROP_WL_BSSTYPE: 2414 err = wl_set_bsstype(ic, wldp_buf); 2415 break; 2416 case MAC_PROP_WL_DESIRED_RATES: 2417 err = wl_set_desrates(ic, wldp_buf); 2418 break; 2419 case MAC_PROP_WL_WPA: 2420 err = wl_set_wpa(ic, wldp_buf); 2421 break; 2422 case MAC_PROP_WL_KEY: 2423 err = wl_set_wpakey(ic, wldp_buf); 2424 break; 2425 case MAC_PROP_WL_DELKEY: 2426 err = wl_set_delkey(ic, wldp_buf); 2427 break; 2428 case MAC_PROP_WL_SETOPTIE: 2429 err = wl_set_optie(ic, wldp_buf); 2430 break; 2431 case MAC_PROP_WL_MLME: 2432 err = wl_set_mlme(ic, wldp_buf); 2433 break; 2434 case MAC_PROP_WL_CREATE_IBSS: 2435 err = wl_set_createibss(ic, wldp_buf); 2436 break; 2437 case MAC_PROP_WL_LINKSTATUS: 2438 case MAC_PROP_WL_ESS_LIST: 2439 case MAC_PROP_WL_SUPPORTED_RATES: 2440 case MAC_PROP_WL_RSSI: 2441 case MAC_PROP_WL_CAPABILITY: 2442 case MAC_PROP_WL_SCANRESULTS: 2443 ieee80211_err("ieee80211_setprop: opmode err\n"); 2444 err = EINVAL; 2445 break; 2446 default: 2447 ieee80211_err("ieee80211_setprop: opmode not support\n"); 2448 err = ENOTSUP; 2449 break; 2450 } 2451 2452 IEEE80211_UNLOCK(ic); 2453 2454 return (err); 2455 } 2456 2457 /* ARGSUSED */ 2458 int 2459 ieee80211_getprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2460 uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 2461 { 2462 int err = 0; 2463 struct ieee80211com *ic = ic_arg; 2464 2465 if (wldp_length == 0) { 2466 err = EINVAL; 2467 return (err); 2468 } 2469 bzero(wldp_buf, wldp_length); 2470 2471 ASSERT(ic != NULL); 2472 IEEE80211_LOCK(ic); 2473 2474 *perm = MAC_PROP_PERM_RW; 2475 2476 switch (wldp_pr_num) { 2477 /* mac_prop_id */ 2478 case MAC_PROP_WL_ESSID: 2479 wl_get_essid(ic, wldp_buf); 2480 break; 2481 case MAC_PROP_WL_BSSID: 2482 wl_get_bssid(ic, wldp_buf); 2483 break; 2484 case MAC_PROP_WL_PHY_CONFIG: 2485 err = wl_get_phy(ic, wldp_buf); 2486 break; 2487 case MAC_PROP_WL_AUTH_MODE: 2488 wl_get_authmode(ic, wldp_buf); 2489 break; 2490 case MAC_PROP_WL_ENCRYPTION: 2491 wl_get_encrypt(ic, wldp_buf); 2492 break; 2493 case MAC_PROP_WL_BSSTYPE: 2494 wl_get_bsstype(ic, wldp_buf); 2495 break; 2496 case MAC_PROP_WL_DESIRED_RATES: 2497 wl_get_desrates(ic, wldp_buf); 2498 break; 2499 case MAC_PROP_WL_LINKSTATUS: 2500 *perm = MAC_PROP_PERM_READ; 2501 wl_get_linkstatus(ic, wldp_buf); 2502 break; 2503 case MAC_PROP_WL_ESS_LIST: 2504 *perm = MAC_PROP_PERM_READ; 2505 wl_get_esslist(ic, wldp_buf); 2506 break; 2507 case MAC_PROP_WL_SUPPORTED_RATES: 2508 *perm = MAC_PROP_PERM_READ; 2509 wl_get_suprates(ic, wldp_buf); 2510 break; 2511 case MAC_PROP_WL_RSSI: 2512 *perm = MAC_PROP_PERM_READ; 2513 wl_get_rssi(ic, wldp_buf); 2514 break; 2515 case MAC_PROP_WL_CAPABILITY: 2516 *perm = MAC_PROP_PERM_READ; 2517 wl_get_capability(ic, wldp_buf); 2518 break; 2519 case MAC_PROP_WL_WPA: 2520 wl_get_wpa(ic, wldp_buf); 2521 break; 2522 case MAC_PROP_WL_SCANRESULTS: 2523 *perm = MAC_PROP_PERM_READ; 2524 wl_get_scanresults(ic, wldp_buf); 2525 break; 2526 case MAC_PROP_WL_CREATE_IBSS: 2527 *perm = MAC_PROP_PERM_READ; 2528 wl_get_createibss(ic, wldp_buf); 2529 break; 2530 case MAC_PROP_WL_KEY_TAB: 2531 case MAC_PROP_WL_KEY: 2532 case MAC_PROP_WL_DELKEY: 2533 case MAC_PROP_WL_SETOPTIE: 2534 case MAC_PROP_WL_MLME: 2535 ieee80211_err("ieee80211_setprop: opmode err\n"); 2536 err = EINVAL; 2537 break; 2538 default: 2539 ieee80211_err("ieee80211_setprop: opmode not support\n"); 2540 err = ENOTSUP; 2541 break; 2542 } 2543 2544 IEEE80211_UNLOCK(ic); 2545 2546 return (err); 2547 } 2548