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