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