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 #define WIFI_HAVE_HTCAP(in) (((in)->in_htcap != 0) ? 1 : 0) 723 724 /* 725 * Callback function used by ieee80211_iterate_nodes() in 726 * wifi_cfg_esslist() to get info of each node in a node table 727 * arg output buffer, pointer to wl_ess_list_t 728 * in each node in the node table 729 */ 730 static void 731 wifi_read_ap(void *arg, struct ieee80211_node *in) 732 { 733 wl_ess_list_t *aps = arg; 734 ieee80211com_t *ic = in->in_ic; 735 struct ieee80211_channel *chan = in->in_chan; 736 struct ieee80211_rateset *rates = &(in->in_rates); 737 wl_ess_conf_t *conf; 738 uint8_t *end; 739 uint_t i, nrates; 740 741 end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN - 742 sizeof (wl_ess_list_t); 743 conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num]; 744 if ((uint8_t *)conf > end) 745 return; 746 747 conf->wl_ess_conf_length = sizeof (struct wl_ess_conf); 748 749 /* skip newly allocated NULL bss node */ 750 if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr)) 751 return; 752 753 conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen; 754 bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid, 755 in->in_esslen); 756 bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN); 757 conf->wl_ess_conf_wepenabled = 758 (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ? 759 WL_ENC_WEP : WL_NOENCRYPTION); 760 conf->wl_ess_conf_bsstype = 761 (in->in_capinfo & IEEE80211_CAPINFO_ESS ? 762 WL_BSS_BSS : WL_BSS_IBSS); 763 conf->wl_ess_conf_sl = wifi_getrssi(in); 764 conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1); 765 766 /* physical (FH, DS, ERP) parameters */ 767 if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) { 768 wl_ofdm_t *ofdm = 769 (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf); 770 ofdm->wl_ofdm_subtype = WL_OFDM; 771 ofdm->wl_ofdm_frequency = chan->ich_freq; 772 ofdm->wl_ofdm_ht_enabled = WIFI_HAVE_HTCAP(in); 773 } else { 774 switch (in->in_phytype) { 775 case IEEE80211_T_FH: { 776 wl_fhss_t *fhss = (wl_fhss_t *) 777 &((conf->wl_phy_conf).wl_phy_fhss_conf); 778 779 fhss->wl_fhss_subtype = WL_FHSS; 780 fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan); 781 fhss->wl_fhss_dwelltime = in->in_fhdwell; 782 break; 783 } 784 case IEEE80211_T_DS: { 785 wl_dsss_t *dsss = (wl_dsss_t *) 786 &((conf->wl_phy_conf).wl_phy_dsss_conf); 787 788 dsss->wl_dsss_subtype = WL_DSSS; 789 dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan); 790 dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in, 791 IEEE80211_CAPINFO_SHORT_PREAMBLE); 792 dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in, 793 IEEE80211_CAPINFO_CHNL_AGILITY); 794 dsss->wl_dsss_have_pbcc = dsss->wl_dsss_pbcc_enable = 795 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 796 break; 797 } 798 case IEEE80211_T_OFDM: { 799 wl_erp_t *erp = (wl_erp_t *) 800 &((conf->wl_phy_conf).wl_phy_erp_conf); 801 802 erp->wl_erp_subtype = WL_ERP; 803 erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan); 804 erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in, 805 IEEE80211_CAPINFO_SHORT_PREAMBLE); 806 erp->wl_erp_have_agility = erp->wl_erp_agility_enabled = 807 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_CHNL_AGILITY); 808 erp->wl_erp_have_pbcc = erp->wl_erp_pbcc_enabled = 809 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 810 erp->wl_erp_dsss_ofdm_enabled = 811 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_DSSSOFDM); 812 erp->wl_erp_sst_enabled = WIFI_HAVE_CAP(in, 813 IEEE80211_CAPINFO_SHORT_SLOTTIME); 814 erp->wl_erp_ht_enabled = WIFI_HAVE_HTCAP(in); 815 break; 816 } /* case IEEE80211_T_OFDM */ 817 } /* switch in->in_phytype */ 818 } 819 820 /* supported rates */ 821 nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES); 822 /* 823 * The number of supported rates might exceed 824 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates 825 * first so userland command could properly show 826 * maximum speed of AP 827 */ 828 for (i = 0; i < nrates; i++) { 829 conf->wl_supported_rates[i] = 830 rates->ir_rates[rates->ir_nrates - i - 1]; 831 } 832 833 aps->wl_ess_list_num++; 834 } 835 836 static int 837 wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 838 { 839 mblk_t *omp; 840 wldp_t *outp; 841 wl_ess_list_t *ow_aps; 842 int err = 0; 843 844 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 845 NULL) { 846 return (ENOMEM); 847 } 848 outp = (wldp_t *)omp->b_rptr; 849 ow_aps = (wl_ess_list_t *)outp->wldp_buf; 850 851 switch (cmd) { 852 case WLAN_GET_PARAM: 853 ow_aps->wl_ess_list_num = 0; 854 ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps); 855 outp->wldp_length = WIFI_BUF_OFFSET + 856 offsetof(wl_ess_list_t, wl_ess_list_ess) + 857 ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t); 858 omp->b_wptr = omp->b_rptr + outp->wldp_length; 859 break; 860 case WLAN_SET_PARAM: 861 outp->wldp_result = WL_READONLY; 862 err = EINVAL; 863 break; 864 default: 865 ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd); 866 outp->wldp_result = WL_NOTSUPPORTED; 867 err = EINVAL; 868 break; 869 } 870 871 freemsg(*mp); 872 *mp = omp; 873 return (err); 874 } 875 876 /* 877 * Scan the network for all available ESSs. 878 * IEEE80211_F_SCANONLY is set when current state is INIT. And 879 * with this flag, after scan the state will be changed back to 880 * INIT. The reason is at the end of SCAN stage, the STA will 881 * consequently connect to an AP. Then it looks unreasonable that 882 * for a disconnected device, A SCAN command causes it connected. 883 * So the state is changed back to INIT. 884 */ 885 static int 886 wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp) 887 { 888 int ostate = ic->ic_state; 889 890 /* 891 * Do not scan when current state is RUN. The reason is 892 * when connected, STA is on the same channel as AP. But 893 * to do scan, STA have to switch to each available channel, 894 * send probe request and wait certian time for probe 895 * response/beacon. Then when the STA switches to a channel 896 * different than AP's, as a result it cannot send/receive 897 * data packets to/from the connected WLAN. This eventually 898 * will cause data loss. 899 */ 900 if (ostate == IEEE80211_S_RUN) 901 return (0); 902 903 IEEE80211_UNLOCK(ic); 904 905 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 906 IEEE80211_LOCK(ic); 907 if (ostate == IEEE80211_S_INIT) 908 ic->ic_flags |= IEEE80211_F_SCANONLY; 909 910 /* Don't wait on WPA mode */ 911 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) { 912 /* wait scan complete */ 913 wifi_wait_scan(ic); 914 } 915 916 wifi_setupoutmsg(mp, 0); 917 return (0); 918 } 919 920 static void 921 wifi_loaddefdata(struct ieee80211com *ic) 922 { 923 struct ieee80211_node *in = ic->ic_bss; 924 int i; 925 926 ic->ic_des_esslen = 0; 927 bzero(ic->ic_des_essid, IEEE80211_NWID_LEN); 928 ic->ic_flags &= ~IEEE80211_F_DESBSSID; 929 bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN); 930 bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN); 931 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 932 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 933 bzero(ic->ic_nickname, IEEE80211_NWID_LEN); 934 in->in_authmode = IEEE80211_AUTH_OPEN; 935 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 936 ic->ic_flags &= ~IEEE80211_F_WPA; /* mask WPA mode */ 937 ic->ic_evq_head = ic->ic_evq_tail = 0; /* reset Queue */ 938 ic->ic_def_txkey = 0; 939 for (i = 0; i < MAX_NWEPKEYS; i++) { 940 ic->ic_nw_keys[i].wk_keylen = 0; 941 bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE); 942 } 943 ic->ic_curmode = IEEE80211_MODE_AUTO; 944 ic->ic_flags &= ~IEEE80211_F_IBSSON; 945 ic->ic_opmode = IEEE80211_M_STA; 946 } 947 948 static int 949 wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp) 950 { 951 wifi_loaddefdata(ic); 952 wifi_setupoutmsg(mp, 0); 953 return (ENETRESET); 954 } 955 956 static int 957 wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp) 958 { 959 if (ic->ic_state != IEEE80211_S_INIT) { 960 IEEE80211_UNLOCK(ic); 961 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 962 IEEE80211_LOCK(ic); 963 } 964 wifi_loaddefdata(ic); 965 wifi_setupoutmsg(mp, 0); 966 return (0); 967 } 968 969 /* 970 * Get the capabilities of drivers. 971 */ 972 static int 973 wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 974 { 975 mblk_t *omp; 976 wldp_t *outp; 977 wl_capability_t *o_caps; 978 int err = 0; 979 980 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL) 981 return (ENOMEM); 982 outp = (wldp_t *)omp->b_rptr; 983 o_caps = (wl_capability_t *)outp->wldp_buf; 984 985 switch (cmd) { 986 case WLAN_GET_PARAM: 987 wl_get_capability(ic, o_caps); 988 break; 989 case WLAN_SET_PARAM: 990 outp->wldp_result = WL_READONLY; 991 err = EINVAL; 992 break; 993 default: 994 ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd); 995 outp->wldp_result = WL_NOTSUPPORTED; 996 err = EINVAL; 997 break; 998 } 999 1000 freemsg(*mp); 1001 *mp = omp; 1002 return (err); 1003 } 1004 1005 /* 1006 * Operating on WPA mode. 1007 */ 1008 static int 1009 wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1010 { 1011 mblk_t *omp; 1012 wldp_t *outp; 1013 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1014 wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf; 1015 wl_wpa_t *o_wpa; 1016 int err = 0; 1017 1018 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL) 1019 return (ENOMEM); 1020 outp = (wldp_t *)omp->b_rptr; 1021 o_wpa = (wl_wpa_t *)outp->wldp_buf; 1022 1023 switch (cmd) { 1024 case WLAN_GET_PARAM: 1025 wl_get_wpa(ic, o_wpa); 1026 break; 1027 case WLAN_SET_PARAM: 1028 err = wl_set_wpa(ic, wpa); 1029 break; 1030 default: 1031 ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd); 1032 outp->wldp_result = WL_NOTSUPPORTED; 1033 err = EINVAL; 1034 break; 1035 } 1036 1037 freemsg(*mp); 1038 *mp = omp; 1039 return (err); 1040 } 1041 1042 /* 1043 * WPA daemon set the WPA keys. 1044 * The WPA keys are negotiated with APs through wpa service. 1045 */ 1046 static int 1047 wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1048 { 1049 mblk_t *omp; 1050 wldp_t *outp; 1051 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1052 wl_key_t *ik = (wl_key_t *)(inp->wldp_buf); 1053 int err = 0; 1054 1055 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1056 return (ENOMEM); 1057 outp = (wldp_t *)omp->b_rptr; 1058 1059 switch (cmd) { 1060 case WLAN_GET_PARAM: 1061 outp->wldp_result = WL_WRITEONLY; 1062 err = EINVAL; 1063 break; 1064 case WLAN_SET_PARAM: 1065 err = wl_set_wpakey(ic, ik); 1066 break; 1067 default: 1068 ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd); 1069 outp->wldp_result = WL_NOTSUPPORTED; 1070 err = EINVAL; 1071 break; 1072 } 1073 1074 freemsg(*mp); 1075 *mp = omp; 1076 return (err); 1077 } 1078 1079 /* 1080 * Delete obsolete keys - keys are dynamically exchanged between APs 1081 * and wpa daemon. 1082 */ 1083 static int 1084 wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1085 { 1086 mblk_t *omp; 1087 wldp_t *outp; 1088 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1089 wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf; 1090 int err = 0; 1091 1092 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1093 return (ENOMEM); 1094 outp = (wldp_t *)omp->b_rptr; 1095 1096 switch (cmd) { 1097 case WLAN_GET_PARAM: 1098 outp->wldp_result = WL_WRITEONLY; 1099 err = EINVAL; 1100 break; 1101 case WLAN_SET_PARAM: 1102 err = wl_set_delkey(ic, dk); 1103 break; 1104 default: 1105 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1106 outp->wldp_result = WL_NOTSUPPORTED; 1107 err = EINVAL; 1108 break; 1109 } 1110 1111 freemsg(*mp); 1112 *mp = omp; 1113 return (err); 1114 } 1115 1116 /* 1117 * The OPTIE will be used in the association request. 1118 */ 1119 static int 1120 wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1121 { 1122 mblk_t *omp; 1123 wldp_t *outp; 1124 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1125 wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf; 1126 int err = 0; 1127 1128 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1129 return (ENOMEM); 1130 outp = (wldp_t *)omp->b_rptr; 1131 1132 switch (cmd) { 1133 case WLAN_GET_PARAM: 1134 outp->wldp_result = WL_WRITEONLY; 1135 err = EINVAL; 1136 break; 1137 case WLAN_SET_PARAM: 1138 if ((err = wl_set_optie(ic, ie_in)) == EINVAL) 1139 outp->wldp_result = WL_NOTSUPPORTED; 1140 break; 1141 default: 1142 ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd); 1143 outp->wldp_result = WL_NOTSUPPORTED; 1144 err = EINVAL; 1145 break; 1146 } 1147 1148 freemsg(*mp); 1149 *mp = omp; 1150 return (err); 1151 } 1152 1153 /* 1154 * To be compatible with drivers/tools of OpenSolaris.org, 1155 * we use a different ID to filter out those APs of WPA mode. 1156 */ 1157 static int 1158 wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1159 { 1160 mblk_t *omp; 1161 wldp_t *outp; 1162 wl_wpa_ess_t *sr; 1163 ieee80211_node_t *in; 1164 ieee80211_node_table_t *nt; 1165 int len, ap_num = 0; 1166 int err = 0; 1167 1168 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 1169 NULL) { 1170 return (ENOMEM); 1171 } 1172 outp = (wldp_t *)omp->b_rptr; 1173 sr = (wl_wpa_ess_t *)outp->wldp_buf; 1174 sr->count = 0; 1175 1176 switch (cmd) { 1177 case WLAN_GET_PARAM: 1178 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n"); 1179 nt = &ic->ic_scan; 1180 IEEE80211_NODE_LOCK(nt); 1181 in = list_head(&nt->nt_node); 1182 while (in != NULL) { 1183 /* filter out non-WPA APs */ 1184 if (in->in_wpa_ie == NULL) { 1185 in = list_next(&nt->nt_node, in); 1186 continue; 1187 } 1188 bcopy(in->in_bssid, sr->ess[ap_num].bssid, 1189 IEEE80211_ADDR_LEN); 1190 sr->ess[ap_num].ssid_len = in->in_esslen; 1191 bcopy(in->in_essid, sr->ess[ap_num].ssid, 1192 in->in_esslen); 1193 sr->ess[ap_num].freq = in->in_chan->ich_freq; 1194 1195 len = in->in_wpa_ie[1] + 2; 1196 bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len); 1197 sr->ess[ap_num].wpa_ie_len = len; 1198 1199 ap_num ++; 1200 in = list_next(&nt->nt_node, in); 1201 } 1202 IEEE80211_NODE_UNLOCK(nt); 1203 sr->count = ap_num; 1204 outp->wldp_length = WIFI_BUF_OFFSET + 1205 offsetof(wl_wpa_ess_t, ess) + 1206 sr->count * sizeof (struct wpa_ess); 1207 omp->b_wptr = omp->b_rptr + outp->wldp_length; 1208 break; 1209 case WLAN_SET_PARAM: 1210 outp->wldp_result = WL_READONLY; 1211 err = EINVAL; 1212 break; 1213 default: 1214 ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd); 1215 outp->wldp_result = WL_NOTSUPPORTED; 1216 err = EINVAL; 1217 break; 1218 } 1219 1220 freemsg(*mp); 1221 *mp = omp; 1222 return (err); 1223 } 1224 1225 /* 1226 * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC 1227 */ 1228 static int 1229 wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1230 { 1231 mblk_t *omp; 1232 wldp_t *outp; 1233 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1234 wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf; 1235 int err = 0; 1236 1237 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1238 return (ENOMEM); 1239 outp = (wldp_t *)omp->b_rptr; 1240 1241 switch (cmd) { 1242 case WLAN_GET_PARAM: 1243 outp->wldp_result = WL_WRITEONLY; 1244 err = EINVAL; 1245 break; 1246 case WLAN_SET_PARAM: 1247 err = wl_set_mlme(ic, mlme); 1248 break; 1249 default: 1250 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1251 outp->wldp_result = WL_NOTSUPPORTED; 1252 err = EINVAL; 1253 break; 1254 } 1255 1256 freemsg(*mp); 1257 *mp = omp; 1258 return (err); 1259 } 1260 1261 static int 1262 wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd) 1263 { 1264 mblk_t *mp1 = *mp; 1265 wldp_t *wp = (wldp_t *)mp1->b_rptr; 1266 int err = 0; 1267 1268 ASSERT(ic != NULL && mp1 != NULL); 1269 IEEE80211_LOCK_ASSERT(ic); 1270 if (MBLKL(mp1) < WIFI_BUF_OFFSET) { 1271 ieee80211_err("wifi_cfg_getset: " 1272 "invalid input buffer, size=%d\n", MBLKL(mp1)); 1273 return (EINVAL); 1274 } 1275 1276 switch (wp->wldp_id) { 1277 /* Commands */ 1278 case WL_SCAN: 1279 err = wifi_cmd_scan(ic, mp1); 1280 break; 1281 case WL_LOAD_DEFAULTS: 1282 err = wifi_cmd_loaddefaults(ic, mp1); 1283 break; 1284 case WL_DISASSOCIATE: 1285 err = wifi_cmd_disassoc(ic, mp1); 1286 break; 1287 /* Parameters */ 1288 case WL_ESSID: 1289 err = wifi_cfg_essid(ic, cmd, mp); 1290 break; 1291 case WL_BSSID: 1292 err = wifi_cfg_bssid(ic, cmd, mp); 1293 break; 1294 case WL_NODE_NAME: 1295 err = wifi_cfg_nodename(ic, cmd, mp); 1296 break; 1297 case WL_PHY_CONFIG: 1298 err = wifi_cfg_phy(ic, cmd, mp); 1299 break; 1300 case WL_WEP_KEY_TAB: 1301 err = wifi_cfg_wepkey(ic, cmd, mp); 1302 break; 1303 case WL_WEP_KEY_ID: 1304 err = wifi_cfg_keyid(ic, cmd, mp); 1305 break; 1306 case WL_AUTH_MODE: 1307 err = wifi_cfg_authmode(ic, cmd, mp); 1308 break; 1309 case WL_ENCRYPTION: 1310 err = wifi_cfg_encrypt(ic, cmd, mp); 1311 break; 1312 case WL_BSS_TYPE: 1313 err = wifi_cfg_bsstype(ic, cmd, mp); 1314 break; 1315 case WL_CREATE_IBSS: 1316 err = wifi_cfg_createibss(ic, cmd, mp); 1317 break; 1318 case WL_DESIRED_RATES: 1319 err = wifi_cfg_desrates(ic, cmd, mp); 1320 break; 1321 case WL_LINKSTATUS: 1322 err = wifi_cfg_linkstatus(ic, cmd, mp); 1323 break; 1324 case WL_ESS_LIST: 1325 err = wifi_cfg_esslist(ic, cmd, mp); 1326 break; 1327 case WL_SUPPORTED_RATES: 1328 err = wifi_cfg_suprates(ic, cmd, mp); 1329 break; 1330 case WL_RSSI: 1331 err = wifi_cfg_rssi(ic, cmd, mp); 1332 break; 1333 /* 1334 * WPA IOCTLs 1335 */ 1336 case WL_CAPABILITY: 1337 err = wifi_cfg_caps(ic, cmd, mp); 1338 break; 1339 case WL_WPA: 1340 err = wifi_cfg_wpa(ic, cmd, mp); 1341 break; 1342 case WL_KEY: 1343 err = wifi_cfg_wpakey(ic, cmd, mp); 1344 break; 1345 case WL_DELKEY: 1346 err = wifi_cfg_delkey(ic, cmd, mp); 1347 break; 1348 case WL_SETOPTIE: 1349 err = wifi_cfg_setoptie(ic, cmd, mp); 1350 break; 1351 case WL_SCANRESULTS: 1352 err = wifi_cfg_scanresults(ic, cmd, mp); 1353 break; 1354 case WL_MLME: 1355 err = wifi_cfg_setmlme(ic, cmd, mp); 1356 break; 1357 default: 1358 wifi_setupoutmsg(mp1, 0); 1359 wp->wldp_result = WL_LACK_FEATURE; 1360 err = ENOTSUP; 1361 break; 1362 } 1363 1364 return (err); 1365 } 1366 1367 /* 1368 * Typically invoked by drivers in response to requests for 1369 * information or to change settings from the userland. 1370 * 1371 * Return value should be checked by WiFi drivers. Return 0 1372 * on success. Otherwise, return non-zero value to indicate 1373 * the error. Driver should operate as below when the return 1374 * error is: 1375 * ENETRESET Reset wireless network and re-start to join a 1376 * WLAN. ENETRESET is returned when a configuration 1377 * parameter has been changed. 1378 * When acknowledge a M_IOCTL message, thie error 1379 * is ignored. 1380 */ 1381 int 1382 ieee80211_ioctl(struct ieee80211com *ic, queue_t *wq, mblk_t *mp) 1383 { 1384 struct iocblk *iocp; 1385 int32_t cmd, err, len; 1386 boolean_t need_privilege; 1387 mblk_t *mp1; 1388 1389 if (MBLKL(mp) < sizeof (struct iocblk)) { 1390 ieee80211_err("ieee80211_ioctl: ioctl buffer too short, %u\n", 1391 MBLKL(mp)); 1392 miocnak(wq, mp, 0, EINVAL); 1393 return (EINVAL); 1394 } 1395 1396 /* 1397 * Validate the command 1398 */ 1399 iocp = (struct iocblk *)mp->b_rptr; 1400 iocp->ioc_error = 0; 1401 cmd = iocp->ioc_cmd; 1402 need_privilege = B_TRUE; 1403 switch (cmd) { 1404 case WLAN_SET_PARAM: 1405 case WLAN_COMMAND: 1406 break; 1407 case WLAN_GET_PARAM: 1408 need_privilege = B_FALSE; 1409 break; 1410 default: 1411 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): " 1412 "unknown cmd 0x%x\n", cmd); 1413 miocnak(wq, mp, 0, EINVAL); 1414 return (EINVAL); 1415 } 1416 1417 if (need_privilege && (err = secpolicy_dl_config(iocp->ioc_cr)) != 0) { 1418 miocnak(wq, mp, 0, err); 1419 return (err); 1420 } 1421 1422 IEEE80211_LOCK(ic); 1423 1424 /* sanity check */ 1425 mp1 = mp->b_cont; 1426 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 1427 mp1 == NULL) { 1428 miocnak(wq, mp, 0, EINVAL); 1429 IEEE80211_UNLOCK(ic); 1430 return (EINVAL); 1431 } 1432 1433 /* assuming single data block */ 1434 if (mp1->b_cont != NULL) { 1435 freemsg(mp1->b_cont); 1436 mp1->b_cont = NULL; 1437 } 1438 1439 err = wifi_cfg_getset(ic, &mp1, cmd); 1440 mp->b_cont = mp1; 1441 IEEE80211_UNLOCK(ic); 1442 1443 len = msgdsize(mp1); 1444 /* ignore ENETRESET when acknowledge the M_IOCTL message */ 1445 if (err == 0 || err == ENETRESET) 1446 miocack(wq, mp, len, 0); 1447 else 1448 miocack(wq, mp, len, err); 1449 1450 return (err); 1451 } 1452 1453 /* 1454 * The following routines are for brussels support 1455 */ 1456 1457 /* 1458 * MAC_PROP_WL_ESSID 1459 */ 1460 static int 1461 wl_set_essid(struct ieee80211com *ic, const void *wldp_buf) 1462 { 1463 int err = 0; 1464 char *essid; 1465 wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf; 1466 1467 if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN) { 1468 ieee80211_err("wl_set_essid: " 1469 "essid too long, %u, max %u\n", 1470 iw_essid->wl_essid_length, IEEE80211_NWID_LEN); 1471 1472 err = EINVAL; 1473 return (err); 1474 } 1475 1476 essid = iw_essid->wl_essid_essid; 1477 essid[IEEE80211_NWID_LEN] = 0; 1478 1479 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_essid: " 1480 "set essid=%s length=%d\n", 1481 essid, iw_essid->wl_essid_length); 1482 1483 ic->ic_des_esslen = iw_essid->wl_essid_length; 1484 if (ic->ic_des_esslen != 0) 1485 bcopy(essid, ic->ic_des_essid, ic->ic_des_esslen); 1486 if (ic->ic_des_esslen < IEEE80211_NWID_LEN) 1487 ic->ic_des_essid[ic->ic_des_esslen] = 0; 1488 1489 err = ENETRESET; 1490 1491 return (err); 1492 } 1493 1494 static void 1495 wl_get_essid(struct ieee80211com *ic, void *wldp_buf) 1496 { 1497 char *essid; 1498 wl_essid_t ow_essid; 1499 1500 essid = (char *)ic->ic_des_essid; 1501 if (essid[0] == '\0') 1502 essid = (char *)ic->ic_bss->in_essid; 1503 1504 bzero(&ow_essid, sizeof (wl_essid_t)); 1505 ow_essid.wl_essid_length = wifi_strnlen((const char *)essid, 1506 IEEE80211_NWID_LEN); 1507 bcopy(essid, ow_essid.wl_essid_essid, 1508 ow_essid.wl_essid_length); 1509 bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t)); 1510 1511 } 1512 1513 /* 1514 * MAC_PROP_WL_BSSID 1515 */ 1516 static int 1517 wl_set_bssid(struct ieee80211com *ic, const void* wldp_buf) 1518 { 1519 1520 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bssid: " 1521 "set bssid=%s\n", 1522 ieee80211_macaddr_sprintf(wldp_buf)); 1523 1524 bcopy(wldp_buf, ic->ic_des_bssid, sizeof (wl_bssid_t)); 1525 ic->ic_flags |= IEEE80211_F_DESBSSID; 1526 1527 return (ENETRESET); 1528 } 1529 1530 static void 1531 wl_get_bssid(struct ieee80211com *ic, void *wldp_buf) 1532 { 1533 uint8_t *bssid; 1534 1535 if (ic->ic_flags & IEEE80211_F_DESBSSID) 1536 bssid = ic->ic_des_bssid; 1537 else 1538 bssid = ic->ic_bss->in_bssid; 1539 bcopy(bssid, wldp_buf, sizeof (wl_bssid_t)); 1540 1541 } 1542 1543 /* 1544 * MAC_PROP_WL_BSSTYP 1545 */ 1546 static int 1547 wl_set_bsstype(struct ieee80211com *ic, const void *wldp_buf) 1548 { 1549 int err = 0; 1550 wl_bss_type_t *iw_opmode = (wl_bss_type_t *)wldp_buf; 1551 1552 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bsstype: " 1553 "set bsstype=%u\n", *iw_opmode); 1554 1555 switch (*iw_opmode) { 1556 case WL_BSS_BSS: 1557 ic->ic_flags &= ~IEEE80211_F_IBSSON; 1558 ic->ic_opmode = IEEE80211_M_STA; 1559 err = ENETRESET; 1560 break; 1561 case WL_BSS_IBSS: 1562 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) { 1563 err = ENOTSUP; 1564 break; 1565 } 1566 1567 ic->ic_opmode = IEEE80211_M_IBSS; 1568 err = ENETRESET; 1569 break; 1570 default: 1571 ieee80211_err("wl_set_bsstype: " 1572 "unknown opmode\n"); 1573 err = EINVAL; 1574 break; 1575 } 1576 return (err); 1577 } 1578 1579 static void 1580 wl_get_bsstype(struct ieee80211com *ic, void *wldp_buf) 1581 { 1582 wl_bss_type_t ow_opmode; 1583 1584 switch (ic->ic_opmode) { 1585 case IEEE80211_M_STA: 1586 ow_opmode = WL_BSS_BSS; 1587 break; 1588 case IEEE80211_M_IBSS: 1589 ow_opmode = WL_BSS_IBSS; 1590 break; 1591 default: 1592 ow_opmode = WL_BSS_ANY; 1593 break; 1594 } 1595 1596 bcopy(&ow_opmode, wldp_buf, sizeof (wl_bss_type_t)); 1597 } 1598 1599 /* 1600 * MAC_PROP_WL_LINKSTATUS 1601 */ 1602 static void 1603 wl_get_linkstatus(struct ieee80211com *ic, void *wldp_buf) 1604 { 1605 wl_linkstatus_t ow_linkstat; 1606 1607 ow_linkstat = (ic->ic_state == IEEE80211_S_RUN) ? 1608 WL_CONNECTED : WL_NOTCONNECTED; 1609 if ((ic->ic_flags & IEEE80211_F_WPA) && 1610 (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA)) { 1611 ow_linkstat = WL_NOTCONNECTED; 1612 } 1613 1614 bcopy(&ow_linkstat, wldp_buf, sizeof (wl_linkstatus_t)); 1615 } 1616 1617 /* 1618 * MAC_PROP_WL_DESIRED_RATESa 1619 */ 1620 static int 1621 wl_set_desrates(struct ieee80211com *ic, const void *wldp_buf) 1622 { 1623 int err = 0; 1624 int i, j; 1625 uint8_t drate; 1626 boolean_t isfound; 1627 wl_rates_t *iw_rates = (wl_rates_t *)wldp_buf; 1628 struct ieee80211_node *in = ic->ic_bss; 1629 struct ieee80211_rateset *rs = &in->in_rates; 1630 1631 drate = iw_rates->wl_rates_rates[0]; 1632 if (ic->ic_fixed_rate == drate) 1633 return (err); 1634 1635 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_desrates: " 1636 "set desired rate=%u\n", drate); 1637 1638 if (drate == 0) { 1639 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 1640 if (ic->ic_state == IEEE80211_S_RUN) { 1641 IEEE80211_UNLOCK(ic); 1642 ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0); 1643 IEEE80211_LOCK(ic); 1644 } 1645 return (err); 1646 } 1647 1648 /* 1649 * Set desired rate. The desired rate is for data transfer 1650 * and usally is checked and used when driver changes to 1651 * RUN state. 1652 * If the driver is in AUTH | ASSOC | RUN state, desired 1653 * rate is checked anainst rates supported by current ESS. 1654 * If it's supported and current state is AUTH|ASSOC, nothing 1655 * needs to be done by driver since the desired rate will 1656 * be enabled when the device changes to RUN state. And 1657 * when current state is RUN, Re-associate with the ESS to 1658 * enable the desired rate. 1659 */ 1660 1661 if (ic->ic_state != IEEE80211_S_INIT && 1662 ic->ic_state != IEEE80211_S_SCAN) { 1663 for (i = 0; i < rs->ir_nrates; i++) { 1664 if (drate == IEEE80211_RV(rs->ir_rates[i])) 1665 break; 1666 } 1667 /* supported */ 1668 if (i < rs->ir_nrates) { 1669 ic->ic_fixed_rate = drate; 1670 if (ic->ic_state == IEEE80211_S_RUN) { 1671 IEEE80211_UNLOCK(ic); 1672 ieee80211_new_state(ic, 1673 IEEE80211_S_ASSOC, 0); 1674 IEEE80211_LOCK(ic); 1675 } 1676 return (err); 1677 } 1678 } 1679 1680 /* 1681 * In INIT or SCAN state 1682 * check if the desired rate is supported by device 1683 */ 1684 isfound = B_FALSE; 1685 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 1686 rs = &ic->ic_sup_rates[i]; 1687 for (j = 0; j < rs->ir_nrates; j++) { 1688 if (drate == IEEE80211_RV(rs->ir_rates[j])) { 1689 isfound = B_TRUE; 1690 break; 1691 } 1692 } 1693 if (isfound) 1694 break; 1695 } 1696 if (!isfound) { 1697 ieee80211_err("wl_set_desrates: " 1698 "invald rate %d\n", drate); 1699 err = EINVAL; 1700 return (err); 1701 } 1702 ic->ic_fixed_rate = drate; 1703 if (ic->ic_state != IEEE80211_S_SCAN) 1704 err = ENETRESET; 1705 1706 return (err); 1707 } 1708 1709 static void 1710 wl_get_desrates(struct ieee80211com *ic, void *wldp_buf) 1711 { 1712 uint8_t srate; 1713 wl_rates_t ow_rates; 1714 struct ieee80211_node *in = ic->ic_bss; 1715 struct ieee80211_rateset *rs = &in->in_rates; 1716 1717 srate = rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL; 1718 ow_rates.wl_rates_num = 1; 1719 ow_rates.wl_rates_rates[0] = 1720 (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 1721 srate : ic->ic_fixed_rate; 1722 bcopy(&ow_rates, wldp_buf, sizeof (wl_rates_t)); 1723 1724 } 1725 1726 /* 1727 * MAC_PROP_AUTH_MODE 1728 */ 1729 static int 1730 wl_set_authmode(struct ieee80211com *ic, const void *wldp_buf) 1731 { 1732 int err = 0; 1733 wl_authmode_t *iw_auth = (wl_authmode_t *)wldp_buf; 1734 1735 if (*iw_auth == ic->ic_bss->in_authmode) 1736 return (err); 1737 1738 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_authmode: " 1739 "set authmode=%u\n", *iw_auth); 1740 1741 switch (*iw_auth) { 1742 case WL_OPENSYSTEM: 1743 case WL_SHAREDKEY: 1744 ic->ic_bss->in_authmode = *iw_auth; 1745 err = ENETRESET; 1746 break; 1747 default: 1748 ieee80211_err("wl_set_authmode: " 1749 "unknown authmode %u\n", *iw_auth); 1750 err = EINVAL; 1751 break; 1752 } 1753 1754 return (err); 1755 } 1756 1757 static void 1758 wl_get_authmode(struct ieee80211com *ic, void *wldp_buf) 1759 { 1760 wl_authmode_t ow_auth; 1761 1762 ow_auth = ic->ic_bss->in_authmode; 1763 bcopy(&ow_auth, wldp_buf, sizeof (wl_authmode_t)); 1764 1765 } 1766 1767 /* 1768 * MAC_PROP_WL_ENCRYPTION 1769 */ 1770 static int 1771 wl_set_encrypt(struct ieee80211com *ic, const void *wldp_buf) 1772 { 1773 int err = 0; 1774 uint32_t flags; 1775 wl_encryption_t *iw_encryp = (wl_encryption_t *)wldp_buf; 1776 1777 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_encrypt: " 1778 "set encryption=%u\n", *iw_encryp); 1779 1780 flags = ic->ic_flags; 1781 if (*iw_encryp == WL_NOENCRYPTION) 1782 flags &= ~IEEE80211_F_PRIVACY; 1783 else 1784 flags |= IEEE80211_F_PRIVACY; 1785 1786 if (ic->ic_flags != flags) { 1787 ic->ic_flags = flags; 1788 err = ENETRESET; 1789 } 1790 1791 return (err); 1792 } 1793 1794 static void 1795 wl_get_encrypt(struct ieee80211com *ic, void *wldp_buf) 1796 { 1797 wl_encryption_t *ow_encryp; 1798 1799 ow_encryp = (wl_encryption_t *)wldp_buf; 1800 *ow_encryp = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0; 1801 if (ic->ic_flags & IEEE80211_F_WPA) 1802 *ow_encryp = WL_ENC_WPA; 1803 1804 } 1805 1806 /* 1807 * MAC_PROP_WL_RSSI 1808 */ 1809 static void 1810 wl_get_rssi(struct ieee80211com *ic, void *wldp_buf) 1811 { 1812 wl_rssi_t *ow_rssi; 1813 1814 ow_rssi = (wl_rssi_t *)wldp_buf; 1815 *ow_rssi = wifi_getrssi(ic->ic_bss); 1816 1817 } 1818 1819 /* 1820 * MAC_PROP_WL_PHY_CONFIG 1821 */ 1822 1823 static int 1824 wl_set_phy(struct ieee80211com *ic, const void* wldp_buf) 1825 { 1826 int err = 0; 1827 int16_t ch; 1828 wl_dsss_t *dsss; 1829 wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)wldp_buf; 1830 1831 dsss = (wl_dsss_t *)iw_phy; 1832 ch = dsss->wl_dsss_channel; 1833 1834 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_phy: " 1835 "set channel=%d\n", ch); 1836 1837 if (ch == 0 || ch == (int16_t)IEEE80211_CHAN_ANY) { 1838 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 1839 } else if ((uint_t)ch > IEEE80211_CHAN_MAX || 1840 ieee80211_isclr(ic->ic_chan_active, ch)) { 1841 err = EINVAL; 1842 return (err); 1843 } else { 1844 ic->ic_des_chan = ic->ic_ibss_chan = 1845 &ic->ic_sup_channels[ch]; 1846 } 1847 1848 switch (ic->ic_state) { 1849 case IEEE80211_S_INIT: 1850 case IEEE80211_S_SCAN: 1851 err = ENETRESET; 1852 break; 1853 default: 1854 /* 1855 * If hte desired channel has changed (to something 1856 * other than any) and we're not already scanning, 1857 * then kick the state machine. 1858 */ 1859 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 1860 ic->ic_bss->in_chan != ic->ic_des_chan && 1861 (ic->ic_flags & IEEE80211_F_SCAN) == 0) 1862 err = ENETRESET; 1863 break; 1864 } 1865 1866 return (err); 1867 } 1868 1869 #define WIFI_HT_MODE(in) (((in)->in_flags & IEEE80211_NODE_HT) ? 1 : 0) 1870 1871 static int 1872 wl_get_phy(struct ieee80211com *ic, void *wldp_buf) 1873 { 1874 int err = 0; 1875 wl_phy_conf_t *ow_phy; 1876 struct ieee80211_channel *ch = ic->ic_curchan; 1877 struct ieee80211_node *in = ic->ic_bss; 1878 1879 ow_phy = (wl_phy_conf_t *)wldp_buf; 1880 bzero(wldp_buf, sizeof (wl_phy_conf_t)); 1881 1882 /* get current phy parameters: FH|DS|ERP */ 1883 if (IEEE80211_IS_CHAN_A(ch) || IEEE80211_IS_CHAN_T(ch)) { 1884 wl_ofdm_t *ofdm = (wl_ofdm_t *)ow_phy; 1885 ofdm->wl_ofdm_subtype = WL_OFDM; 1886 ofdm->wl_ofdm_frequency = ch->ich_freq; 1887 ofdm->wl_ofdm_ht_enabled = WIFI_HT_MODE(in); 1888 } else { 1889 switch (ic->ic_phytype) { 1890 case IEEE80211_T_FH: { 1891 wl_fhss_t *fhss = (wl_fhss_t *)ow_phy; 1892 fhss->wl_fhss_subtype = WL_FHSS; 1893 fhss->wl_fhss_channel = 1894 ieee80211_chan2ieee(ic, ch); 1895 break; 1896 } 1897 case IEEE80211_T_DS: { 1898 wl_dsss_t *dsss = (wl_dsss_t *)ow_phy; 1899 dsss->wl_dsss_subtype = WL_DSSS; 1900 dsss->wl_dsss_channel = 1901 ieee80211_chan2ieee(ic, ch); 1902 break; 1903 } 1904 case IEEE80211_T_OFDM: { 1905 wl_erp_t *erp = (wl_erp_t *)ow_phy; 1906 erp->wl_erp_subtype = WL_ERP; 1907 erp->wl_erp_channel = 1908 ieee80211_chan2ieee(ic, ch); 1909 erp->wl_erp_ht_enabled = WIFI_HT_MODE(in); 1910 break; 1911 } 1912 default: 1913 ieee80211_err("wl_get_phy: " 1914 "unknown phy type, %x\n", ic->ic_phytype); 1915 err = EIO; 1916 break; 1917 } 1918 } 1919 1920 return (err); 1921 } 1922 1923 /* 1924 * MAC_PROP_WL_CAPABILITY 1925 */ 1926 static void 1927 wl_get_capability(struct ieee80211com *ic, void *wldp_buf) 1928 { 1929 wl_capability_t ow_caps; 1930 1931 ow_caps.caps = ic->ic_caps; 1932 bcopy(&ow_caps, wldp_buf, sizeof (wl_capability_t)); 1933 1934 } 1935 1936 /* 1937 * MAC_PROP_WL_WPA 1938 */ 1939 static int 1940 wl_set_wpa(struct ieee80211com *ic, const void *wldp_buf) 1941 { 1942 int err = 0; 1943 wl_wpa_t *wpa = (wl_wpa_t *)wldp_buf; 1944 1945 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpa: " 1946 "set wpa=%u\n", wpa->wpa_flag); 1947 1948 if (wpa->wpa_flag > 0) { 1949 /* enable wpa mode */ 1950 ic->ic_flags |= IEEE80211_F_PRIVACY; 1951 ic->ic_flags |= IEEE80211_F_WPA; 1952 } else { 1953 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 1954 ic->ic_flags &= ~IEEE80211_F_WPA; 1955 } 1956 1957 return (err); 1958 } 1959 1960 static void 1961 wl_get_wpa(struct ieee80211com *ic, void *wldp_buf) 1962 { 1963 wl_wpa_t *wpa; 1964 1965 wpa = (wl_wpa_t *)wldp_buf; 1966 wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA) ? 1 : 0); 1967 1968 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_get_wpa: " 1969 "get wpa=%u\n", wpa->wpa_flag); 1970 1971 } 1972 1973 /* 1974 * MAC_PROP_WL_SCANRESULTS 1975 */ 1976 1977 static void 1978 wl_get_scanresults(struct ieee80211com *ic, void *wldp_buf) 1979 { 1980 wl_wpa_ess_t *sr; 1981 ieee80211_node_t *in; 1982 ieee80211_node_table_t *nt; 1983 int ap_num; 1984 int len; 1985 1986 sr = (wl_wpa_ess_t *)wldp_buf; 1987 sr->count = 0; 1988 ap_num = 0; 1989 1990 ieee80211_dbg(IEEE80211_MSG_WPA, "wl_get_scanrelults\n"); 1991 1992 nt = &ic->ic_scan; 1993 IEEE80211_NODE_LOCK(nt); 1994 in = list_head(&nt->nt_node); 1995 1996 while (in != NULL) { 1997 /* filter out non-wpa APs */ 1998 if (in->in_wpa_ie == NULL) { 1999 in = list_next(&nt->nt_node, in); 2000 continue; 2001 } 2002 bcopy(in->in_bssid, sr->ess[ap_num].bssid, 2003 IEEE80211_ADDR_LEN); 2004 sr->ess[ap_num].ssid_len = in->in_esslen; 2005 bcopy(in->in_essid, sr->ess[ap_num].ssid, 2006 in->in_esslen); 2007 sr->ess[ap_num].freq = in->in_chan->ich_freq; 2008 2009 len = in->in_wpa_ie[1] + 2; 2010 bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len); 2011 sr->ess[ap_num].wpa_ie_len = len; 2012 2013 ap_num++; 2014 in = list_next(&nt->nt_node, in); 2015 } 2016 IEEE80211_NODE_UNLOCK(nt); 2017 sr->count = ap_num; 2018 2019 } 2020 2021 /* 2022 * MAC_PROP_WL_ESS_LIST 2023 */ 2024 static void 2025 wl_get_esslist(struct ieee80211com *ic, void *wldp_buf) 2026 { 2027 wl_ess_list_t *ess_list; 2028 2029 ess_list = (wl_ess_list_t *)wldp_buf; 2030 2031 ess_list->wl_ess_list_num = 0; 2032 ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ess_list); 2033 2034 } 2035 2036 /* 2037 * MAC_PROP_WL_WEP_KEY 2038 */ 2039 static int 2040 wl_set_wepkey(struct ieee80211com *ic, const void *wldp_buf) 2041 { 2042 int err = 0; 2043 uint16_t i; 2044 uint32_t klen; 2045 struct ieee80211_key *key; 2046 wl_wep_key_t *wepkey = (wl_wep_key_t *)wldp_buf; 2047 2048 /* set all valid keys */ 2049 for (i = 0; i < MAX_NWEPKEYS; i++) { 2050 if (wepkey[i].wl_wep_operation != WL_ADD) 2051 continue; 2052 klen = wepkey[i].wl_wep_length; 2053 if (klen > IEEE80211_KEYBUF_SIZE) { 2054 ieee80211_err("wl_set_wepkey: " 2055 "invalid wepkey length, %u\n", klen); 2056 err = EINVAL; 2057 continue; /* continue to set other keys */ 2058 } 2059 if (klen == 0) 2060 continue; 2061 2062 /* 2063 * Set key contents. Only WEP is supported 2064 */ 2065 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_wepkey: " 2066 "set key %u, len=%u\n", i, klen); 2067 key = &ic->ic_nw_keys[i]; 2068 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP, 2069 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key) == 0) { 2070 ieee80211_err("wl_set_wepkey: " 2071 "abort, create key failed. id=%u\n", i); 2072 err = EIO; 2073 continue; 2074 } 2075 2076 key->wk_keyix = i; 2077 key->wk_keylen = (uint8_t)klen; 2078 key->wk_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 2079 bzero(key->wk_key, IEEE80211_KEYBUF_SIZE); 2080 bcopy(wepkey[i].wl_wep_key, key->wk_key, klen); 2081 if (ieee80211_crypto_setkey(ic, key, ic->ic_macaddr) 2082 == 0) { 2083 ieee80211_err("wl_set_wepkey: " 2084 "set key failed len=%u\n", klen); 2085 err = EIO; 2086 } 2087 } 2088 if (err == 0) 2089 err = ENETRESET; 2090 2091 return (err); 2092 } 2093 2094 /* 2095 * MAC_PROP_WL_SETOPTIE 2096 */ 2097 static int 2098 wl_set_optie(struct ieee80211com *ic, const void *wldp_buf) 2099 { 2100 int err = 0; 2101 char *ie; 2102 wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)wldp_buf; 2103 2104 if (ic->ic_opmode != IEEE80211_M_STA) { 2105 ieee80211_err("wl_set_optie: opmode err\n"); 2106 err = EINVAL; 2107 return (err); 2108 } 2109 if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) { 2110 2111 ieee80211_err("wl_set_optie: optie is too long\n"); 2112 2113 err = EINVAL; 2114 return (err); 2115 } 2116 2117 ie = ieee80211_malloc(ie_in->wpa_ie_len); 2118 (void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len); 2119 if (ic->ic_opt_ie != NULL) { 2120 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, 2121 "wl_set_optie:ic_opt_ie!=NULL\n"); 2122 ieee80211_free(ic->ic_opt_ie); 2123 } 2124 ic->ic_opt_ie = ie; 2125 ic->ic_opt_ie_len = ie_in->wpa_ie_len; 2126 2127 return (err); 2128 } 2129 2130 /* 2131 * MAC_PROP_WL_DELKEY 2132 */ 2133 static int 2134 wl_set_delkey(struct ieee80211com *ic, const void *wldp_buf) 2135 { 2136 int err = 0; 2137 int kid; 2138 wl_del_key_t *dk = (wl_del_key_t *)wldp_buf; 2139 2140 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_delkey(): " 2141 "keyix=%d\n", dk->idk_keyix); 2142 2143 kid = dk->idk_keyix; 2144 2145 if (kid == IEEE80211_KEYIX_NONE || 2146 kid >= IEEE80211_WEP_NKID) { 2147 ieee80211_err("wl_set_delkey: incorrect keyix\n"); 2148 err = EINVAL; 2149 return (err); 2150 } else { 2151 (void) ieee80211_crypto_delkey(ic, 2152 &ic->ic_nw_keys[kid]); 2153 ieee80211_mac_update(ic); 2154 } 2155 2156 return (err); 2157 } 2158 2159 /* 2160 * MAC_PROP_WL_MLME 2161 */ 2162 2163 static int 2164 wl_set_mlme(struct ieee80211com *ic, const void *wldp_buf) 2165 { 2166 int err = 0; 2167 uint32_t flags; 2168 ieee80211_node_t *in; 2169 wl_mlme_t *mlme = (wl_mlme_t *)wldp_buf; 2170 2171 ieee80211_dbg(IEEE80211_MSG_WPA, "wl_set_mlme: " 2172 "op=%d\n", mlme->im_op); 2173 2174 switch (mlme->im_op) { 2175 case IEEE80211_MLME_DISASSOC: 2176 case IEEE80211_MLME_DEAUTH: 2177 if (ic->ic_opmode == IEEE80211_M_STA) { 2178 /* 2179 * Mask ic_flags of IEEE80211_F_WPA to disable 2180 * ieee80211_notify temporarily. 2181 */ 2182 flags = ic->ic_flags; 2183 ic->ic_flags &= ~IEEE80211_F_WPA; 2184 2185 IEEE80211_UNLOCK(ic); 2186 ieee80211_new_state(ic, IEEE80211_S_INIT, 2187 mlme->im_reason); 2188 IEEE80211_LOCK(ic); 2189 2190 ic->ic_flags = flags; 2191 } 2192 break; 2193 case IEEE80211_MLME_ASSOC: 2194 if (ic->ic_opmode != IEEE80211_M_STA) { 2195 ieee80211_err("wifi_cfg_setmlme: opmode err\n"); 2196 err = EINVAL; 2197 break; 2198 } 2199 if (ic->ic_des_esslen != 0) { 2200 /* 2201 * Desired ssid specified; must match both bssid and 2202 * ssid to distinguish ap advertising multiple ssid's. 2203 */ 2204 in = ieee80211_find_node_with_ssid(&ic->ic_scan, 2205 mlme->im_macaddr, 2206 ic->ic_des_esslen, 2207 ic->ic_des_essid); 2208 } else { 2209 /* 2210 * Normal case; just match bssid. 2211 */ 2212 in = ieee80211_find_node(&ic->ic_scan, 2213 mlme->im_macaddr); 2214 } 2215 if (in == NULL) { 2216 ieee80211_err("wifi_cfg_setmlme: " 2217 "no matched node\n"); 2218 err = EINVAL; 2219 break; 2220 } 2221 IEEE80211_UNLOCK(ic); 2222 ieee80211_sta_join(ic, in); 2223 IEEE80211_LOCK(ic); 2224 break; 2225 default: 2226 err = EINVAL; 2227 break; 2228 } 2229 2230 return (err); 2231 } 2232 2233 /* 2234 * MAC_PROP_WL_WPA_KEY 2235 */ 2236 static int 2237 wl_set_wpakey(struct ieee80211com *ic, const void *wldp_buf) 2238 { 2239 int err = 0; 2240 uint16_t kid; 2241 struct ieee80211_node *in; 2242 struct ieee80211_key *wk; 2243 wl_key_t ik; 2244 2245 bcopy(wldp_buf, &ik, sizeof (wl_key_t)); 2246 2247 ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpakey: " 2248 "idx=%d\n", ik.ik_keyix); 2249 2250 /* 2251 * cipher support is verified by ieee80211_crypt_newkey 2252 * this also checks ik.ik_keylen > sizeof(wk->wk_key) 2253 */ 2254 if (ik.ik_keylen > sizeof (ik.ik_keydata)) { 2255 ieee80211_err("wl_set_wpakey: key is too long\n"); 2256 err = EINVAL; 2257 return (err); 2258 } 2259 kid = ik.ik_keyix; 2260 if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) { 2261 ieee80211_err("wl_set_wpakey: incorrect keyix\n"); 2262 err = EINVAL; 2263 return (err); 2264 } else { 2265 wk = &ic->ic_nw_keys[kid]; 2266 /* 2267 * Globle slots start off w/o any assigned key index. 2268 * Force one here for consistency with WEPKEY. 2269 */ 2270 if (wk->wk_keyix == IEEE80211_KEYIX_NONE) 2271 wk->wk_keyix = kid; 2272 in = NULL; 2273 } 2274 2275 KEY_UPDATE_BEGIN(ic); 2276 if (ieee80211_crypto_newkey(ic, ik.ik_type, 2277 ik.ik_flags, wk)) { 2278 wk->wk_keylen = ik.ik_keylen; 2279 /* MIC presence is implied by cipher type */ 2280 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE) 2281 wk->wk_keylen = IEEE80211_KEYBUF_SIZE; 2282 wk->wk_keyrsc = ik.ik_keyrsc; 2283 wk->wk_keytsc = 0; 2284 wk->wk_flags |= ik.ik_flags & 2285 (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV); 2286 (void) memset(wk->wk_key, 0, sizeof (wk->wk_key)); 2287 (void) memcpy(wk->wk_key, ik.ik_keydata, 2288 ik.ik_keylen); 2289 if (!ieee80211_crypto_setkey(ic, wk, 2290 in != NULL ? in->in_macaddr : ik.ik_macaddr)) { 2291 err = EIO; 2292 } else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT)) { 2293 ic->ic_def_txkey = kid; 2294 ieee80211_mac_update(ic); 2295 } 2296 } else { 2297 err = EIO; 2298 } 2299 KEY_UPDATE_END(ic); 2300 2301 return (err); 2302 } 2303 2304 /* 2305 * MAC_PROP_WL_SUP_RATE 2306 */ 2307 static void 2308 wl_get_suprates(struct ieee80211com *ic, void *wldp_buf) 2309 { 2310 int i, j, k, l; 2311 uint8_t srates; 2312 uint8_t *drates; 2313 wl_rates_t *wl_rates; 2314 const struct ieee80211_rateset *srs; 2315 2316 wl_rates = (wl_rates_t *)wldp_buf; 2317 2318 wl_rates->wl_rates_num = 0; 2319 drates = (uint8_t *)wl_rates->wl_rates_rates; 2320 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 2321 srs = &ic->ic_sup_rates[i]; 2322 if (srs->ir_nrates == 0) 2323 continue; 2324 for (j = 0; j < srs->ir_nrates; j++) { 2325 srates = IEEE80211_RV(srs->ir_rates[j]); 2326 /* sort & skip duplicated rates */ 2327 for (k = 0; k < wl_rates->wl_rates_num; k++) { 2328 if (srates <= drates[k]) 2329 break; 2330 } 2331 if (srates == drates[k]) 2332 /* skip duplicated rates */ 2333 continue; 2334 /* sort */ 2335 for (l = wl_rates->wl_rates_num; l > k; l--) 2336 drates[l] = drates[l-1]; 2337 drates[k] = srates; 2338 wl_rates->wl_rates_num++; 2339 } 2340 } 2341 2342 } 2343 2344 /* 2345 * Typically invoked by drivers in response to request for 2346 * information or to change settings from the userland. 2347 * 2348 * Return value should be checked by WiFI drivers. Return 0 2349 * on success. Otherwise, return non-zero value to indicate 2350 * the error. Driver should operate as below when the return 2351 * error is: 2352 * ENETRESET Reset wireless network and re-start to join a 2353 * WLAN, ENETRESET is returned when a configuration 2354 * parameter has been changed. 2355 * When acknowledge a M_IOCTL message, this error 2356 * is ignored 2357 */ 2358 /* ARGSUSED */ 2359 int 2360 ieee80211_setprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2361 uint_t wldp_length, const void *wldp_buf) 2362 { 2363 int err = 0; 2364 struct ieee80211com *ic = ic_arg; 2365 2366 ASSERT(ic != NULL); 2367 IEEE80211_LOCK(ic); 2368 2369 switch (wldp_pr_num) { 2370 /* mac_prop_id */ 2371 case MAC_PROP_WL_ESSID: 2372 err = wl_set_essid(ic, wldp_buf); 2373 break; 2374 case MAC_PROP_WL_BSSID: 2375 err = wl_set_bssid(ic, wldp_buf); 2376 break; 2377 case MAC_PROP_WL_PHY_CONFIG: 2378 err = wl_set_phy(ic, wldp_buf); 2379 break; 2380 case MAC_PROP_WL_KEY_TAB: 2381 err = wl_set_wepkey(ic, wldp_buf); 2382 break; 2383 case MAC_PROP_WL_AUTH_MODE: 2384 err = wl_set_authmode(ic, wldp_buf); 2385 break; 2386 case MAC_PROP_WL_ENCRYPTION: 2387 err = wl_set_encrypt(ic, wldp_buf); 2388 break; 2389 case MAC_PROP_WL_BSSTYPE: 2390 err = wl_set_bsstype(ic, wldp_buf); 2391 break; 2392 case MAC_PROP_WL_DESIRED_RATES: 2393 err = wl_set_desrates(ic, wldp_buf); 2394 break; 2395 case MAC_PROP_WL_WPA: 2396 err = wl_set_wpa(ic, wldp_buf); 2397 break; 2398 case MAC_PROP_WL_KEY: 2399 err = wl_set_wpakey(ic, wldp_buf); 2400 break; 2401 case MAC_PROP_WL_DELKEY: 2402 err = wl_set_delkey(ic, wldp_buf); 2403 break; 2404 case MAC_PROP_WL_SETOPTIE: 2405 err = wl_set_optie(ic, wldp_buf); 2406 break; 2407 case MAC_PROP_WL_MLME: 2408 err = wl_set_mlme(ic, wldp_buf); 2409 break; 2410 case MAC_PROP_WL_LINKSTATUS: 2411 case MAC_PROP_WL_ESS_LIST: 2412 case MAC_PROP_WL_SUPPORTED_RATES: 2413 case MAC_PROP_WL_RSSI: 2414 case MAC_PROP_WL_CAPABILITY: 2415 case MAC_PROP_WL_SCANRESULTS: 2416 ieee80211_err("ieee80211_setprop: opmode err\n"); 2417 err = EINVAL; 2418 break; 2419 default: 2420 ieee80211_err("ieee80211_setprop: opmode not support\n"); 2421 err = ENOTSUP; 2422 break; 2423 } 2424 2425 IEEE80211_UNLOCK(ic); 2426 2427 return (err); 2428 } 2429 2430 /* ARGSUSED */ 2431 int 2432 ieee80211_getprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2433 uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 2434 { 2435 int err = 0; 2436 struct ieee80211com *ic = ic_arg; 2437 2438 if (wldp_length == 0) { 2439 err = EINVAL; 2440 return (err); 2441 } 2442 bzero(wldp_buf, wldp_length); 2443 2444 ASSERT(ic != NULL); 2445 IEEE80211_LOCK(ic); 2446 2447 *perm = MAC_PROP_PERM_RW; 2448 2449 switch (wldp_pr_num) { 2450 /* mac_prop_id */ 2451 case MAC_PROP_WL_ESSID: 2452 wl_get_essid(ic, wldp_buf); 2453 break; 2454 case MAC_PROP_WL_BSSID: 2455 wl_get_bssid(ic, wldp_buf); 2456 break; 2457 case MAC_PROP_WL_PHY_CONFIG: 2458 err = wl_get_phy(ic, wldp_buf); 2459 break; 2460 case MAC_PROP_WL_AUTH_MODE: 2461 wl_get_authmode(ic, wldp_buf); 2462 break; 2463 case MAC_PROP_WL_ENCRYPTION: 2464 wl_get_encrypt(ic, wldp_buf); 2465 break; 2466 case MAC_PROP_WL_BSSTYPE: 2467 wl_get_bsstype(ic, wldp_buf); 2468 break; 2469 case MAC_PROP_WL_DESIRED_RATES: 2470 wl_get_desrates(ic, wldp_buf); 2471 break; 2472 case MAC_PROP_WL_LINKSTATUS: 2473 *perm = MAC_PROP_PERM_READ; 2474 wl_get_linkstatus(ic, wldp_buf); 2475 break; 2476 case MAC_PROP_WL_ESS_LIST: 2477 *perm = MAC_PROP_PERM_READ; 2478 wl_get_esslist(ic, wldp_buf); 2479 break; 2480 case MAC_PROP_WL_SUPPORTED_RATES: 2481 *perm = MAC_PROP_PERM_READ; 2482 wl_get_suprates(ic, wldp_buf); 2483 break; 2484 case MAC_PROP_WL_RSSI: 2485 *perm = MAC_PROP_PERM_READ; 2486 wl_get_rssi(ic, wldp_buf); 2487 break; 2488 case MAC_PROP_WL_CAPABILITY: 2489 *perm = MAC_PROP_PERM_READ; 2490 wl_get_capability(ic, wldp_buf); 2491 break; 2492 case MAC_PROP_WL_WPA: 2493 wl_get_wpa(ic, wldp_buf); 2494 break; 2495 case MAC_PROP_WL_SCANRESULTS: 2496 *perm = MAC_PROP_PERM_READ; 2497 wl_get_scanresults(ic, wldp_buf); 2498 break; 2499 case MAC_PROP_WL_KEY_TAB: 2500 case MAC_PROP_WL_KEY: 2501 case MAC_PROP_WL_DELKEY: 2502 case MAC_PROP_WL_SETOPTIE: 2503 case MAC_PROP_WL_MLME: 2504 ieee80211_err("ieee80211_setprop: opmode err\n"); 2505 err = EINVAL; 2506 break; 2507 default: 2508 ieee80211_err("ieee80211_setprop: opmode not support\n"); 2509 err = ENOTSUP; 2510 break; 2511 } 2512 2513 IEEE80211_UNLOCK(ic); 2514 2515 return (err); 2516 } 2517