1 /* 2 * Copyright 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 #include <sys/param.h> 37 #include <sys/types.h> 38 #include <sys/errno.h> 39 #include <sys/strsun.h> 40 #include <sys/policy.h> 41 #include <inet/common.h> 42 #include <inet/nd.h> 43 #include <inet/mi.h> 44 #include <sys/note.h> 45 #include <sys/mac.h> 46 #include <inet/wifi_ioctl.h> 47 #include "net80211_impl.h" 48 49 static size_t 50 wifi_strnlen(const char *s, size_t n) 51 { 52 size_t i; 53 54 for (i = 0; i < n && s[i] != '\0'; i++) 55 /* noop */; 56 return (i); 57 } 58 59 /* 60 * Initialize an output message block by copying from an 61 * input message block. The message is of type wldp_t. 62 * mp input message block 63 * buflen length of wldp_buf 64 */ 65 static void 66 wifi_setupoutmsg(mblk_t *mp, int buflen) 67 { 68 wldp_t *wp; 69 70 wp = (wldp_t *)mp->b_rptr; 71 wp->wldp_length = WIFI_BUF_OFFSET + buflen; 72 wp->wldp_result = WL_SUCCESS; 73 mp->b_wptr = mp->b_rptr + wp->wldp_length; 74 } 75 76 /* 77 * Allocate and initialize an output message. 78 */ 79 static mblk_t * 80 wifi_getoutmsg(mblk_t *mp, uint32_t cmd, int buflen) 81 { 82 mblk_t *mp1; 83 int size; 84 85 size = WIFI_BUF_OFFSET; 86 if (cmd == WLAN_GET_PARAM) 87 size += buflen; /* to hold output parameters */ 88 mp1 = allocb(size, BPRI_HI); 89 if (mp1 == NULL) { 90 ieee80211_err("wifi_getoutbuf: allocb %d bytes failed!\n", 91 size); 92 return (NULL); 93 } 94 95 bzero(mp1->b_rptr, size); 96 bcopy(mp->b_rptr, mp1->b_rptr, WIFI_BUF_OFFSET); 97 wifi_setupoutmsg(mp1, size - WIFI_BUF_OFFSET); 98 99 return (mp1); 100 } 101 102 static int 103 wifi_cfg_essid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 104 { 105 mblk_t *omp; 106 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 107 wldp_t *outp; 108 wl_essid_t *iw_essid = (wl_essid_t *)inp->wldp_buf; 109 wl_essid_t *ow_essid; 110 char *essid; 111 int err = 0; 112 113 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_essid_t))) == NULL) 114 return (ENOMEM); 115 outp = (wldp_t *)omp->b_rptr; 116 ow_essid = (wl_essid_t *)outp->wldp_buf; 117 118 switch (cmd) { 119 case WLAN_GET_PARAM: 120 essid = (char *)ic->ic_des_essid; 121 if (essid[0] == '\0') 122 essid = (char *)ic->ic_bss->in_essid; 123 ow_essid->wl_essid_length = wifi_strnlen((const char *)essid, 124 IEEE80211_NWID_LEN); 125 bcopy(essid, ow_essid->wl_essid_essid, 126 ow_essid->wl_essid_length); 127 break; 128 case WLAN_SET_PARAM: 129 if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN) { 130 ieee80211_err("wifi_cfg_essid: " 131 "essid too long, %u, max %u\n", 132 iw_essid->wl_essid_length, IEEE80211_NWID_LEN); 133 outp->wldp_result = WL_NOTSUPPORTED; 134 err = EINVAL; 135 break; 136 } 137 essid = iw_essid->wl_essid_essid; 138 essid[IEEE80211_NWID_LEN] = 0; 139 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_essid: " 140 "set essid=%s length=%d\n", 141 essid, iw_essid->wl_essid_length); 142 143 ic->ic_des_esslen = iw_essid->wl_essid_length; 144 if (ic->ic_des_esslen != 0) 145 bcopy(essid, ic->ic_des_essid, ic->ic_des_esslen); 146 if (ic->ic_des_esslen < IEEE80211_NWID_LEN) 147 ic->ic_des_essid[ic->ic_des_esslen] = 0; 148 err = ENETRESET; 149 break; 150 default: 151 ieee80211_err("wifi_cfg_essid: unknown command %x\n", cmd); 152 outp->wldp_result = WL_NOTSUPPORTED; 153 err = EINVAL; 154 break; 155 } 156 157 freemsg(*mp); 158 *mp = omp; 159 return (err); 160 } 161 162 static int 163 wifi_cfg_bssid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 164 { 165 mblk_t *omp; 166 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 167 wldp_t *outp; 168 uint8_t *bssid; 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 if (ic->ic_flags & IEEE80211_F_DESBSSID) 178 bssid = ic->ic_des_bssid; 179 else 180 bssid = ic->ic_bss->in_bssid; 181 bcopy(bssid, outp->wldp_buf, sizeof (wl_bssid_t)); 182 break; 183 case WLAN_SET_PARAM: 184 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_bssid: " 185 "set bssid=%s\n", 186 ieee80211_macaddr_sprintf(inp->wldp_buf)); 187 bcopy(inp->wldp_buf, ic->ic_des_bssid, sizeof (wl_bssid_t)); 188 ic->ic_flags |= IEEE80211_F_DESBSSID; 189 err = ENETRESET; 190 break; 191 default: 192 ieee80211_err("wifi_cfg_bssid: unknown command %x\n", cmd); 193 outp->wldp_result = WL_NOTSUPPORTED; 194 err = EINVAL; 195 break; 196 } 197 198 freemsg(*mp); 199 *mp = omp; 200 return (err); 201 } 202 203 static int 204 wifi_cfg_nodename(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 205 { 206 mblk_t *omp; 207 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 208 wldp_t *outp; 209 wl_nodename_t *iw_name = (wl_nodename_t *)inp->wldp_buf; 210 wl_nodename_t *ow_name; 211 char *nodename; 212 int len, err; 213 214 err = 0; 215 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_nodename_t))) == NULL) 216 return (ENOMEM); 217 outp = (wldp_t *)omp->b_rptr; 218 ow_name = (wl_nodename_t *)outp->wldp_buf; 219 220 switch (cmd) { 221 case WLAN_GET_PARAM: 222 len = wifi_strnlen((const char *)ic->ic_nickname, 223 IEEE80211_NWID_LEN); 224 ow_name->wl_nodename_length = len; 225 bcopy(ic->ic_nickname, ow_name->wl_nodename_name, len); 226 break; 227 case WLAN_SET_PARAM: 228 if (iw_name->wl_nodename_length > IEEE80211_NWID_LEN) { 229 ieee80211_err("wifi_cfg_nodename: " 230 "node name too long, %u\n", 231 iw_name->wl_nodename_length); 232 outp->wldp_result = WL_NOTSUPPORTED; 233 err = EINVAL; 234 break; 235 } 236 nodename = iw_name->wl_nodename_name; 237 nodename[IEEE80211_NWID_LEN] = 0; 238 ieee80211_dbg(IEEE80211_MSG_CONFIG, 239 "wifi_cfg_nodename: set nodename %s, len=%d\n", 240 nodename, iw_name->wl_nodename_length); 241 242 len = iw_name->wl_nodename_length; 243 if (len > 0) 244 bcopy(nodename, ic->ic_nickname, len); 245 if (len < IEEE80211_NWID_LEN) 246 ic->ic_nickname[len] = 0; 247 break; 248 default: 249 ieee80211_err("wifi_cfg_nodename: unknown command %x\n", cmd); 250 outp->wldp_result = WL_NOTSUPPORTED; 251 err = EINVAL; 252 break; 253 } 254 255 freemsg(*mp); 256 *mp = omp; 257 return (err); 258 } 259 260 static int 261 wifi_cfg_phy(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 262 { 263 mblk_t *omp; 264 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 265 wldp_t *outp; 266 wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)inp->wldp_buf; 267 wl_phy_conf_t *ow_phy; 268 struct ieee80211_channel *ch = ic->ic_curchan; 269 int err = 0; 270 271 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_phy_conf_t))) == NULL) 272 return (ENOMEM); 273 outp = (wldp_t *)omp->b_rptr; 274 ow_phy = (wl_phy_conf_t *)outp->wldp_buf; 275 276 switch (cmd) { 277 case WLAN_GET_PARAM: { 278 /* get current physical (FH, DS, ERP) parameters */ 279 if (IEEE80211_IS_CHAN_A(ch) || IEEE80211_IS_CHAN_T(ch)) { 280 wl_ofdm_t *ofdm = (wl_ofdm_t *)ow_phy; 281 282 ofdm->wl_ofdm_subtype = WL_OFDM; 283 ofdm->wl_ofdm_frequency = ch->ich_freq; 284 } else { 285 switch (ic->ic_phytype) { 286 case IEEE80211_T_FH: { 287 wl_fhss_t *fhss = (wl_fhss_t *)ow_phy; 288 289 fhss->wl_fhss_subtype = WL_FHSS; 290 fhss->wl_fhss_channel = 291 ieee80211_chan2ieee(ic, ch); 292 break; 293 } 294 case IEEE80211_T_DS: { 295 wl_dsss_t *dsss = (wl_dsss_t *)ow_phy; 296 297 dsss->wl_dsss_subtype = WL_DSSS; 298 dsss->wl_dsss_channel = 299 ieee80211_chan2ieee(ic, ch); 300 break; 301 } 302 case IEEE80211_T_OFDM: { 303 wl_erp_t *erp = (wl_erp_t *)ow_phy; 304 305 erp->wl_erp_subtype = WL_ERP; 306 erp->wl_erp_channel = 307 ieee80211_chan2ieee(ic, ch); 308 break; 309 } 310 default: 311 ieee80211_err("wifi_cfg_phy: " 312 "unknown phy type, %x\n", ic->ic_phytype); 313 outp->wldp_result = WL_HW_ERROR; 314 err = EIO; 315 break; 316 } /* switch (ic->ic_phytype) */ 317 } 318 break; 319 } 320 321 case WLAN_SET_PARAM: { 322 wl_dsss_t *dsss = (wl_dsss_t *)iw_phy; 323 int16_t ch = dsss->wl_dsss_channel; 324 325 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_phy: " 326 "set channel=%d\n", ch); 327 if (ch == 0 || ch == (int16_t)IEEE80211_CHAN_ANY) { 328 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 329 } else if ((uint_t)ch > IEEE80211_CHAN_MAX || 330 ieee80211_isclr(ic->ic_chan_active, ch)) { 331 outp->wldp_result = WL_NOTSUPPORTED; 332 err = EINVAL; 333 break; 334 } else { 335 ic->ic_des_chan = ic->ic_ibss_chan = 336 &ic->ic_sup_channels[ch]; 337 } 338 switch (ic->ic_state) { 339 case IEEE80211_S_INIT: 340 case IEEE80211_S_SCAN: 341 err = ENETRESET; 342 break; 343 default: 344 /* 345 * If the desired channel has changed (to something 346 * other than any) and we're not already scanning, 347 * then kick the state machine. 348 */ 349 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 350 ic->ic_bss->in_chan != ic->ic_des_chan && 351 (ic->ic_flags & IEEE80211_F_SCAN) == 0) 352 err = ENETRESET; 353 break; 354 } 355 break; 356 } 357 358 default: 359 ieee80211_err("wifi_cfg_phy: unknown command %x\n", cmd); 360 outp->wldp_result = WL_NOTSUPPORTED; 361 err = EINVAL; 362 break; 363 } /* switch (cmd) */ 364 365 freemsg(*mp); 366 *mp = omp; 367 return (err); 368 } 369 370 static int 371 wifi_cfg_wepkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 372 { 373 mblk_t *omp; 374 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 375 wldp_t *outp; 376 wl_wep_key_t *iw_wepkey = (wl_wep_key_t *)inp->wldp_buf; 377 struct ieee80211_key *k; 378 uint16_t i; 379 uint32_t klen; 380 int err = 0; 381 382 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 383 return (ENOMEM); 384 outp = (wldp_t *)omp->b_rptr; 385 386 switch (cmd) { 387 case WLAN_GET_PARAM: 388 outp->wldp_result = WL_WRITEONLY; 389 err = EINVAL; 390 break; 391 case WLAN_SET_PARAM: 392 if (inp->wldp_length < sizeof (wl_wep_key_tab_t)) { 393 ieee80211_err("wifi_cfg_wepkey: " 394 "parameter too short, %d, expected %d\n", 395 inp->wldp_length, sizeof (wl_wep_key_tab_t)); 396 outp->wldp_result = WL_NOTSUPPORTED; 397 err = EINVAL; 398 break; 399 } 400 401 /* set all valid keys */ 402 for (i = 0; i < MAX_NWEPKEYS; i++) { 403 if (iw_wepkey[i].wl_wep_operation != WL_ADD) 404 continue; 405 klen = iw_wepkey[i].wl_wep_length; 406 if (klen > IEEE80211_KEYBUF_SIZE) { 407 ieee80211_err("wifi_cfg_wepkey: " 408 "invalid wepkey length, %u\n", klen); 409 outp->wldp_result = WL_NOTSUPPORTED; 410 err = EINVAL; 411 continue; /* continue to set other keys */ 412 } 413 if (klen == 0) 414 continue; 415 416 /* 417 * Set key contents. Only WEP is supported 418 */ 419 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_wepkey: " 420 "set key %u, len=%u\n", i, klen); 421 k = &ic->ic_nw_keys[i]; 422 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP, 423 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k) == 0) { 424 ieee80211_err("wifi_cfg_wepkey: " 425 "abort, create key failed. id=%u\n", i); 426 outp->wldp_result = WL_HW_ERROR; 427 err = EIO; 428 continue; 429 } 430 k->wk_keyix = i; 431 k->wk_keylen = (uint8_t)klen; 432 k->wk_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 433 bzero(k->wk_key, IEEE80211_KEYBUF_SIZE); 434 bcopy(iw_wepkey[i].wl_wep_key, k->wk_key, klen); 435 if (ieee80211_crypto_setkey(ic, k, ic->ic_macaddr) 436 == 0) { 437 ieee80211_err("wifi_cfg_wepkey: " 438 "set key failed len=%u\n", klen); 439 outp->wldp_result = WL_HW_ERROR; 440 err = EIO; 441 } 442 } 443 if (err == 0) 444 err = ENETRESET; 445 break; 446 default: 447 ieee80211_err("wifi_cfg_wepkey: unknown command %x\n", cmd); 448 outp->wldp_result = WL_NOTSUPPORTED; 449 err = EINVAL; 450 break; 451 } 452 453 freemsg(*mp); 454 *mp = omp; 455 return (err); 456 } 457 458 static int 459 wifi_cfg_keyid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 460 { 461 mblk_t *omp; 462 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 463 wldp_t *outp; 464 wl_wep_key_id_t *iw_kid = (wl_wep_key_id_t *)inp->wldp_buf; 465 wl_wep_key_id_t *ow_kid; 466 int err = 0; 467 468 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wep_key_id_t))) == NULL) 469 return (ENOMEM); 470 outp = (wldp_t *)omp->b_rptr; 471 ow_kid = (wl_wep_key_id_t *)outp->wldp_buf; 472 473 switch (cmd) { 474 case WLAN_GET_PARAM: 475 *ow_kid = (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) ? 476 0 : ic->ic_def_txkey; 477 break; 478 case WLAN_SET_PARAM: 479 if (*iw_kid >= MAX_NWEPKEYS) { 480 ieee80211_err("wifi_cfg_keyid: " 481 "keyid too large, %u\n", *iw_kid); 482 outp->wldp_result = WL_NOTSUPPORTED; 483 err = EINVAL; 484 } else { 485 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_keyid: " 486 "set keyid=%u\n", *iw_kid); 487 ic->ic_def_txkey = *iw_kid; 488 err = ENETRESET; 489 } 490 break; 491 default: 492 ieee80211_err("wifi_cfg_keyid: unknown command %x\n", cmd); 493 outp->wldp_result = WL_NOTSUPPORTED; 494 err = EINVAL; 495 break; 496 } 497 498 freemsg(*mp); 499 *mp = omp; 500 return (err); 501 } 502 503 static int 504 wifi_cfg_authmode(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 505 { 506 mblk_t *omp; 507 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 508 wldp_t *outp; 509 wl_authmode_t *iw_auth = (wl_authmode_t *)inp->wldp_buf; 510 wl_authmode_t *ow_auth; 511 int err = 0; 512 513 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_authmode_t))) == NULL) 514 return (ENOMEM); 515 outp = (wldp_t *)omp->b_rptr; 516 ow_auth = (wl_authmode_t *)outp->wldp_buf; 517 518 switch (cmd) { 519 case WLAN_GET_PARAM: 520 *ow_auth = ic->ic_bss->in_authmode; 521 break; 522 case WLAN_SET_PARAM: 523 if (*iw_auth == ic->ic_bss->in_authmode) 524 break; 525 526 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_authmode: " 527 "set authmode=%u\n", *iw_auth); 528 switch (*iw_auth) { 529 case WL_OPENSYSTEM: 530 case WL_SHAREDKEY: 531 ic->ic_bss->in_authmode = *iw_auth; 532 err = ENETRESET; 533 break; 534 default: 535 ieee80211_err("wifi_cfg_authmode: " 536 "unknown authmode %u\n", *iw_auth); 537 outp->wldp_result = WL_NOTSUPPORTED; 538 err = EINVAL; 539 break; 540 } 541 break; 542 default: 543 ieee80211_err("wifi_cfg_authmode: unknown command %x\n", cmd); 544 outp->wldp_result = WL_NOTSUPPORTED; 545 err = EINVAL; 546 break; 547 } 548 549 freemsg(*mp); 550 *mp = omp; 551 return (err); 552 } 553 554 static int 555 wifi_cfg_encrypt(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 556 { 557 mblk_t *omp; 558 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 559 wldp_t *outp; 560 wl_encryption_t *iw_encryp = (wl_encryption_t *)inp->wldp_buf; 561 wl_encryption_t *ow_encryp; 562 uint32_t flags; 563 int err = 0; 564 565 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_encryption_t))) == NULL) 566 return (ENOMEM); 567 outp = (wldp_t *)omp->b_rptr; 568 ow_encryp = (wl_encryption_t *)outp->wldp_buf; 569 570 switch (cmd) { 571 case WLAN_GET_PARAM: 572 *ow_encryp = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0; 573 if (ic->ic_flags & IEEE80211_F_WPA) 574 *ow_encryp = WL_ENC_WPA; 575 break; 576 case WLAN_SET_PARAM: 577 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_encrypt: " 578 "set encryption=%u\n", *iw_encryp); 579 flags = ic->ic_flags; 580 if (*iw_encryp == WL_NOENCRYPTION) 581 flags &= ~IEEE80211_F_PRIVACY; 582 else 583 flags |= IEEE80211_F_PRIVACY; 584 585 if (ic->ic_flags != flags) { 586 ic->ic_flags = flags; 587 err = ENETRESET; 588 } 589 break; 590 default: 591 ieee80211_err("wifi_cfg_encrypt: unknown command %x\n", cmd); 592 outp->wldp_result = WL_NOTSUPPORTED; 593 err = EINVAL; 594 break; 595 } 596 597 freemsg(*mp); 598 *mp = omp; 599 return (err); 600 } 601 602 static int 603 wifi_cfg_bsstype(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 604 { 605 mblk_t *omp; 606 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 607 wldp_t *outp; 608 wl_bss_type_t *iw_opmode = (wl_bss_type_t *)inp->wldp_buf; 609 wl_bss_type_t *ow_opmode; 610 int err = 0; 611 612 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bss_type_t))) == NULL) 613 return (ENOMEM); 614 outp = (wldp_t *)omp->b_rptr; 615 ow_opmode = (wl_bss_type_t *)outp->wldp_buf; 616 617 switch (cmd) { 618 case WLAN_GET_PARAM: 619 switch (ic->ic_opmode) { 620 case IEEE80211_M_STA: 621 *ow_opmode = WL_BSS_BSS; 622 break; 623 case IEEE80211_M_IBSS: 624 *ow_opmode = WL_BSS_IBSS; 625 break; 626 default: 627 *ow_opmode = WL_BSS_ANY; 628 break; 629 } 630 break; 631 case WLAN_SET_PARAM: 632 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_bsstype: " 633 "set bsstype=%u\n", *iw_opmode); 634 switch (*iw_opmode) { 635 case WL_BSS_BSS: 636 ic->ic_flags &= ~IEEE80211_F_IBSSON; 637 ic->ic_opmode = IEEE80211_M_STA; 638 err = ENETRESET; 639 break; 640 case WL_BSS_IBSS: 641 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) { 642 outp->wldp_result = WL_LACK_FEATURE; 643 err = ENOTSUP; 644 break; 645 } 646 647 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 648 ic->ic_flags |= IEEE80211_F_IBSSON; 649 ic->ic_opmode = IEEE80211_M_IBSS; 650 err = ENETRESET; 651 } 652 break; 653 default: 654 ieee80211_err("wifi_cfg_bsstype: " 655 "unknown opmode %u\n", *iw_opmode); 656 outp->wldp_result = WL_NOTSUPPORTED; 657 err = EINVAL; 658 break; 659 } 660 break; 661 default: 662 ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd); 663 outp->wldp_result = WL_NOTSUPPORTED; 664 err = EINVAL; 665 break; 666 } 667 668 freemsg(*mp); 669 *mp = omp; 670 return (err); 671 } 672 673 static int 674 wifi_cfg_linkstatus(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 675 { 676 mblk_t *omp; 677 wldp_t *outp; 678 wl_linkstatus_t *ow_linkstat; 679 int err = 0; 680 681 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_linkstatus_t))) == NULL) 682 return (ENOMEM); 683 outp = (wldp_t *)omp->b_rptr; 684 ow_linkstat = (wl_linkstatus_t *)outp->wldp_buf; 685 686 switch (cmd) { 687 case WLAN_GET_PARAM: 688 *ow_linkstat = (ic->ic_state == IEEE80211_S_RUN) ? 689 WL_CONNECTED : WL_NOTCONNECTED; 690 if ((ic->ic_flags & IEEE80211_F_WPA) && 691 (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA)) { 692 *ow_linkstat = WL_NOTCONNECTED; 693 } 694 break; 695 case WLAN_SET_PARAM: 696 outp->wldp_result = WL_READONLY; 697 err = EINVAL; 698 break; 699 default: 700 ieee80211_err("wifi_cfg_linkstatus: unknown command %x\n", cmd); 701 outp->wldp_result = WL_NOTSUPPORTED; 702 err = EINVAL; 703 break; 704 } 705 706 freemsg(*mp); 707 *mp = omp; 708 return (err); 709 } 710 711 static int 712 wifi_cfg_suprates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 713 { 714 mblk_t *omp; 715 wldp_t *outp; 716 wl_rates_t *ow_rates; 717 const struct ieee80211_rateset *srs; 718 uint8_t srates, *drates; 719 int err, buflen, i, j, k, l; 720 721 err = 0; 722 /* rate value (wl_rates_rates) is of type char */ 723 buflen = offsetof(wl_rates_t, wl_rates_rates) + 724 sizeof (char) * IEEE80211_MODE_MAX * IEEE80211_RATE_MAXSIZE; 725 if ((omp = wifi_getoutmsg(*mp, cmd, buflen)) == NULL) 726 return (ENOMEM); 727 outp = (wldp_t *)omp->b_rptr; 728 ow_rates = (wl_rates_t *)outp->wldp_buf; 729 730 switch (cmd) { 731 case WLAN_GET_PARAM: 732 /* all rates supported by the device */ 733 ow_rates->wl_rates_num = 0; 734 drates = (uint8_t *)ow_rates->wl_rates_rates; 735 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 736 srs = &ic->ic_sup_rates[i]; 737 if (srs->ir_nrates == 0) 738 continue; 739 740 for (j = 0; j < srs->ir_nrates; j++) { 741 srates = IEEE80211_RV(srs->ir_rates[j]); 742 /* sort and skip duplicated rates */ 743 for (k = 0; k < ow_rates->wl_rates_num; k++) { 744 if (srates <= drates[k]) 745 break; 746 } 747 if (srates == drates[k]) 748 continue; /* duplicate, skip */ 749 /* sort */ 750 for (l = ow_rates->wl_rates_num; l > k; l--) 751 drates[l] = drates[l-1]; 752 drates[k] = srates; 753 ow_rates->wl_rates_num++; 754 } 755 } 756 break; 757 case WLAN_SET_PARAM: 758 outp->wldp_result = WL_READONLY; 759 err = EINVAL; 760 break; 761 default: 762 ieee80211_err("wifi_cfg_suprates: unknown command %x\n", cmd); 763 outp->wldp_result = WL_NOTSUPPORTED; 764 err = EINVAL; 765 break; 766 } 767 768 freemsg(*mp); 769 *mp = omp; 770 return (err); 771 } 772 773 static int 774 wifi_cfg_desrates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 775 { 776 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 777 wl_rates_t *iw_rates = (wl_rates_t *)inp->wldp_buf; 778 mblk_t *omp; 779 wldp_t *outp; 780 wl_rates_t *ow_rates; 781 struct ieee80211_node *in = ic->ic_bss; 782 struct ieee80211_rateset *rs = &in->in_rates; 783 uint8_t drate, srate; 784 int err, i, j; 785 boolean_t found; 786 787 err = 0; 788 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rates_t))) == NULL) 789 return (ENOMEM); 790 outp = (wldp_t *)omp->b_rptr; 791 ow_rates = (wl_rates_t *)outp->wldp_buf; 792 793 srate = rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL; 794 switch (cmd) { 795 case WLAN_GET_PARAM: 796 ow_rates->wl_rates_num = 1; 797 ow_rates->wl_rates_rates[0] = 798 (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 799 srate : ic->ic_fixed_rate; 800 break; 801 case WLAN_SET_PARAM: 802 drate = iw_rates->wl_rates_rates[0]; 803 if (ic->ic_fixed_rate == drate) 804 break; 805 806 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_desrates: " 807 "set desired rate=%u\n", drate); 808 809 if (drate == 0) { /* reset */ 810 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 811 if (ic->ic_state == IEEE80211_S_RUN) { 812 IEEE80211_UNLOCK(ic); 813 ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0); 814 IEEE80211_LOCK(ic); 815 } 816 break; 817 } 818 819 /* 820 * Set desired rate. the desired rate is for data transfer 821 * and usually is checked and used when driver changes to 822 * RUN state. 823 * If the driver is in AUTH | ASSOC | RUN state, desired 824 * rate is checked against rates supported by current ESS. 825 * If it's supported and current state is AUTH|ASSOC, nothing 826 * needs to be doen by driver since the desired rate will 827 * be enabled when the device changes to RUN state. And 828 * when current state is RUN, Re-associate with the ESS to 829 * enable the desired rate. 830 */ 831 if (ic->ic_state != IEEE80211_S_INIT && 832 ic->ic_state != IEEE80211_S_SCAN) { 833 /* check if the rate is supported by current ESS */ 834 for (i = 0; i < rs->ir_nrates; i++) { 835 if (drate == IEEE80211_RV(rs->ir_rates[i])) 836 break; 837 } 838 if (i < rs->ir_nrates) { /* supported */ 839 ic->ic_fixed_rate = drate; 840 if (ic->ic_state == IEEE80211_S_RUN) { 841 IEEE80211_UNLOCK(ic); 842 ieee80211_new_state(ic, 843 IEEE80211_S_ASSOC, 0); 844 IEEE80211_LOCK(ic); 845 } 846 break; 847 } 848 } 849 850 /* check the rate is supported by device */ 851 found = B_FALSE; 852 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 853 rs = &ic->ic_sup_rates[i]; 854 for (j = 0; j < rs->ir_nrates; j++) { 855 if (drate == IEEE80211_RV(rs->ir_rates[j])) { 856 found = B_TRUE; 857 break; 858 } 859 } 860 if (found) 861 break; 862 } 863 if (!found) { 864 ieee80211_err("wifi_cfg_desrates: " 865 "invalid rate %d\n", drate); 866 outp->wldp_result = WL_NOTSUPPORTED; 867 err = EINVAL; 868 break; 869 } 870 ic->ic_fixed_rate = drate; 871 if (ic->ic_state != IEEE80211_S_SCAN) 872 err = ENETRESET; /* restart */ 873 break; 874 default: 875 ieee80211_err("wifi_cfg_desrates: unknown command %x\n", cmd); 876 outp->wldp_result = WL_NOTSUPPORTED; 877 err = EINVAL; 878 break; 879 } 880 881 freemsg(*mp); 882 *mp = omp; 883 return (err); 884 } 885 886 /* 887 * Rescale device's RSSI value to (0, 15) as required by WiFi 888 * driver IOCTLs (PSARC/2003/722) 889 */ 890 static wl_rssi_t 891 wifi_getrssi(struct ieee80211_node *in) 892 { 893 struct ieee80211com *ic = in->in_ic; 894 wl_rssi_t rssi, max_rssi; 895 896 rssi = ic->ic_node_getrssi(in); 897 max_rssi = (ic->ic_maxrssi == 0) ? IEEE80211_MAXRSSI : ic->ic_maxrssi; 898 if (rssi == 0) 899 rssi = 0; 900 else if (rssi >= max_rssi) 901 rssi = MAX_RSSI; 902 else 903 rssi = rssi * MAX_RSSI / max_rssi + 1; 904 905 return (rssi); 906 } 907 908 static int 909 wifi_cfg_rssi(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 910 { 911 mblk_t *omp; 912 wldp_t *outp; 913 wl_rssi_t *ow_rssi; 914 int err = 0; 915 916 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rssi_t))) == NULL) 917 return (ENOMEM); 918 outp = (wldp_t *)omp->b_rptr; 919 ow_rssi = (wl_rssi_t *)outp->wldp_buf; 920 921 switch (cmd) { 922 case WLAN_GET_PARAM: 923 *ow_rssi = wifi_getrssi(ic->ic_bss); 924 break; 925 case WLAN_SET_PARAM: 926 outp->wldp_result = WL_READONLY; 927 err = EINVAL; 928 break; 929 default: 930 ieee80211_err("wifi_cfg_rssi: unknown command %x\n", cmd); 931 outp->wldp_result = WL_NOTSUPPORTED; 932 return (EINVAL); 933 } 934 935 freemsg(*mp); 936 *mp = omp; 937 return (err); 938 } 939 940 /* 941 * maximum scan wait time in second. 942 * Time spent on scaning one channel is usually 100~200ms. The maximum 943 * number of channels defined in wifi_ioctl.h is 99 (MAX_CHANNEL_NUM). 944 * As a result the maximum total scan time is defined as below in ms. 945 */ 946 #define WAIT_SCAN_MAX (200 * MAX_CHANNEL_NUM) 947 948 static void 949 wifi_wait_scan(struct ieee80211com *ic) 950 { 951 ieee80211_impl_t *im = ic->ic_private; 952 953 while ((ic->ic_flags & (IEEE80211_F_SCAN | IEEE80211_F_ASCAN)) != 0) { 954 if (cv_timedwait_sig(&im->im_scan_cv, &ic->ic_genlock, 955 ddi_get_lbolt() + drv_usectohz(WAIT_SCAN_MAX * 1000)) != 956 0) { 957 break; 958 } 959 } 960 } 961 962 #define WIFI_HAVE_CAP(in, flag) (((in)->in_capinfo & (flag)) ? 1 : 0) 963 964 /* 965 * Callback function used by ieee80211_iterate_nodes() in 966 * wifi_cfg_esslist() to get info of each node in a node table 967 * arg output buffer, pointer to wl_ess_list_t 968 * in each node in the node table 969 */ 970 static void 971 wifi_read_ap(void *arg, struct ieee80211_node *in) 972 { 973 wl_ess_list_t *aps = arg; 974 ieee80211com_t *ic = in->in_ic; 975 struct ieee80211_channel *chan = in->in_chan; 976 struct ieee80211_rateset *rates = &(in->in_rates); 977 wl_ess_conf_t *conf; 978 uint8_t *end; 979 uint_t i, nrates; 980 981 end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN - 982 sizeof (wl_ess_list_t); 983 conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num]; 984 if ((uint8_t *)conf > end) 985 return; 986 987 /* skip newly allocated NULL bss node */ 988 if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr)) 989 return; 990 991 conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen; 992 bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid, 993 in->in_esslen); 994 bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN); 995 conf->wl_ess_conf_wepenabled = 996 (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ? 997 WL_ENC_WEP : WL_NOENCRYPTION); 998 conf->wl_ess_conf_bsstype = 999 (in->in_capinfo & IEEE80211_CAPINFO_ESS ? 1000 WL_BSS_BSS : WL_BSS_IBSS); 1001 conf->wl_ess_conf_sl = wifi_getrssi(in); 1002 conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1); 1003 1004 /* physical (FH, DS, ERP) parameters */ 1005 if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) { 1006 wl_ofdm_t *ofdm = 1007 (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf); 1008 ofdm->wl_ofdm_subtype = WL_OFDM; 1009 ofdm->wl_ofdm_frequency = chan->ich_freq; 1010 } else { 1011 switch (in->in_phytype) { 1012 case IEEE80211_T_FH: { 1013 wl_fhss_t *fhss = (wl_fhss_t *) 1014 &((conf->wl_phy_conf).wl_phy_fhss_conf); 1015 1016 fhss->wl_fhss_subtype = WL_FHSS; 1017 fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan); 1018 fhss->wl_fhss_dwelltime = in->in_fhdwell; 1019 break; 1020 } 1021 case IEEE80211_T_DS: { 1022 wl_dsss_t *dsss = (wl_dsss_t *) 1023 &((conf->wl_phy_conf).wl_phy_dsss_conf); 1024 1025 dsss->wl_dsss_subtype = WL_DSSS; 1026 dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan); 1027 dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in, 1028 IEEE80211_CAPINFO_SHORT_PREAMBLE); 1029 dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in, 1030 IEEE80211_CAPINFO_CHNL_AGILITY); 1031 dsss->wl_dsss_have_pbcc = dsss->wl_dsss_pbcc_enable = 1032 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 1033 break; 1034 } 1035 case IEEE80211_T_OFDM: { 1036 wl_erp_t *erp = (wl_erp_t *) 1037 &((conf->wl_phy_conf).wl_phy_erp_conf); 1038 1039 erp->wl_erp_subtype = WL_ERP; 1040 erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan); 1041 erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in, 1042 IEEE80211_CAPINFO_SHORT_PREAMBLE); 1043 erp->wl_erp_have_agility = erp->wl_erp_agility_enabled = 1044 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_CHNL_AGILITY); 1045 erp->wl_erp_have_pbcc = erp->wl_erp_pbcc_enabled = 1046 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 1047 erp->wl_erp_dsss_ofdm_enabled = 1048 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_DSSSOFDM); 1049 erp->wl_erp_sst_enabled = WIFI_HAVE_CAP(in, 1050 IEEE80211_CAPINFO_SHORT_SLOTTIME); 1051 break; 1052 } /* case IEEE80211_T_OFDM */ 1053 } /* switch in->in_phytype */ 1054 } 1055 1056 /* supported rates */ 1057 nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES); 1058 /* 1059 * The number of supported rates might exceed 1060 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates 1061 * first so userland command could properly show 1062 * maximum speed of AP 1063 */ 1064 for (i = 0; i < nrates; i++) { 1065 conf->wl_supported_rates[i] = 1066 rates->ir_rates[rates->ir_nrates - i - 1]; 1067 } 1068 1069 aps->wl_ess_list_num++; 1070 } 1071 1072 static int 1073 wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1074 { 1075 mblk_t *omp; 1076 wldp_t *outp; 1077 wl_ess_list_t *ow_aps; 1078 int err = 0; 1079 1080 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 1081 NULL) { 1082 return (ENOMEM); 1083 } 1084 outp = (wldp_t *)omp->b_rptr; 1085 ow_aps = (wl_ess_list_t *)outp->wldp_buf; 1086 1087 switch (cmd) { 1088 case WLAN_GET_PARAM: 1089 ow_aps->wl_ess_list_num = 0; 1090 ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps); 1091 outp->wldp_length = WIFI_BUF_OFFSET + 1092 offsetof(wl_ess_list_t, wl_ess_list_ess) + 1093 ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t); 1094 omp->b_wptr = omp->b_rptr + outp->wldp_length; 1095 break; 1096 case WLAN_SET_PARAM: 1097 outp->wldp_result = WL_READONLY; 1098 err = EINVAL; 1099 break; 1100 default: 1101 ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd); 1102 outp->wldp_result = WL_NOTSUPPORTED; 1103 err = EINVAL; 1104 break; 1105 } 1106 1107 freemsg(*mp); 1108 *mp = omp; 1109 return (err); 1110 } 1111 1112 /* 1113 * Scan the network for all available ESSs. 1114 * IEEE80211_F_SCANONLY is set when current state is INIT. And 1115 * with this flag, after scan the state will be changed back to 1116 * INIT. The reason is at the end of SCAN stage, the STA will 1117 * consequently connect to an AP. Then it looks unreasonable that 1118 * for a disconnected device, A SCAN command causes it connected. 1119 * So the state is changed back to INIT. 1120 */ 1121 static int 1122 wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp) 1123 { 1124 int ostate = ic->ic_state; 1125 1126 /* 1127 * Do not scan when current state is RUN. The reason is 1128 * when connected, STA is on the same channel as AP. But 1129 * to do scan, STA have to switch to each available channel, 1130 * send probe request and wait certian time for probe 1131 * response/beacon. Then when the STA switches to a channel 1132 * different than AP's, as a result it cannot send/receive 1133 * data packets to/from the connected WLAN. This eventually 1134 * will cause data loss. 1135 */ 1136 if (ostate == IEEE80211_S_RUN) 1137 return (0); 1138 1139 IEEE80211_UNLOCK(ic); 1140 1141 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1142 IEEE80211_LOCK(ic); 1143 if (ostate == IEEE80211_S_INIT) 1144 ic->ic_flags |= IEEE80211_F_SCANONLY; 1145 1146 /* Don't wait on WPA mode */ 1147 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) { 1148 /* wait scan complete */ 1149 wifi_wait_scan(ic); 1150 } 1151 1152 wifi_setupoutmsg(mp, 0); 1153 return (0); 1154 } 1155 1156 static void 1157 wifi_loaddefdata(struct ieee80211com *ic) 1158 { 1159 struct ieee80211_node *in = ic->ic_bss; 1160 int i; 1161 1162 ic->ic_des_esslen = 0; 1163 bzero(ic->ic_des_essid, IEEE80211_NWID_LEN); 1164 ic->ic_flags &= ~IEEE80211_F_DESBSSID; 1165 bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN); 1166 bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN); 1167 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 1168 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 1169 bzero(ic->ic_nickname, IEEE80211_NWID_LEN); 1170 in->in_authmode = IEEE80211_AUTH_OPEN; 1171 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 1172 ic->ic_flags &= ~IEEE80211_F_WPA; /* mask WPA mode */ 1173 ic->ic_evq_head = ic->ic_evq_tail = 0; /* reset Queue */ 1174 ic->ic_def_txkey = 0; 1175 for (i = 0; i < MAX_NWEPKEYS; i++) { 1176 ic->ic_nw_keys[i].wk_keylen = 0; 1177 bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE); 1178 } 1179 ic->ic_curmode = IEEE80211_MODE_AUTO; 1180 } 1181 1182 static int 1183 wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp) 1184 { 1185 wifi_loaddefdata(ic); 1186 wifi_setupoutmsg(mp, 0); 1187 return (ENETRESET); 1188 } 1189 1190 static int 1191 wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp) 1192 { 1193 if (ic->ic_state != IEEE80211_S_INIT) { 1194 IEEE80211_UNLOCK(ic); 1195 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1196 IEEE80211_LOCK(ic); 1197 } 1198 wifi_loaddefdata(ic); 1199 wifi_setupoutmsg(mp, 0); 1200 return (0); 1201 } 1202 1203 /* 1204 * Get the capabilities of drivers. 1205 */ 1206 static int 1207 wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1208 { 1209 mblk_t *omp; 1210 wldp_t *outp; 1211 wl_capability_t *o_caps; 1212 int err = 0; 1213 1214 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL) 1215 return (ENOMEM); 1216 outp = (wldp_t *)omp->b_rptr; 1217 o_caps = (wl_capability_t *)outp->wldp_buf; 1218 1219 switch (cmd) { 1220 case WLAN_GET_PARAM: 1221 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_caps: " 1222 "ic_caps = %u\n", ic->ic_caps); 1223 o_caps->caps = ic->ic_caps; 1224 break; 1225 case WLAN_SET_PARAM: 1226 outp->wldp_result = WL_READONLY; 1227 err = EINVAL; 1228 break; 1229 default: 1230 ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd); 1231 outp->wldp_result = WL_NOTSUPPORTED; 1232 err = EINVAL; 1233 break; 1234 } 1235 1236 freemsg(*mp); 1237 *mp = omp; 1238 return (err); 1239 } 1240 1241 /* 1242 * Operating on WPA mode. 1243 */ 1244 static int 1245 wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1246 { 1247 mblk_t *omp; 1248 wldp_t *outp; 1249 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1250 wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf; 1251 wl_wpa_t *o_wpa; 1252 int err = 0; 1253 1254 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL) 1255 return (ENOMEM); 1256 outp = (wldp_t *)omp->b_rptr; 1257 o_wpa = (wl_wpa_t *)outp->wldp_buf; 1258 1259 switch (cmd) { 1260 case WLAN_GET_PARAM: 1261 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_wpa: " 1262 "get wpa=%u\n", wpa->wpa_flag); 1263 o_wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA)? 1 : 0); 1264 break; 1265 case WLAN_SET_PARAM: 1266 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_wpa: " 1267 "set wpa=%u\n", wpa->wpa_flag); 1268 if (wpa->wpa_flag > 0) { /* enable WPA mode */ 1269 ic->ic_flags |= IEEE80211_F_PRIVACY; 1270 ic->ic_flags |= IEEE80211_F_WPA; 1271 } else { 1272 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 1273 ic->ic_flags &= ~IEEE80211_F_WPA; 1274 } 1275 break; 1276 default: 1277 ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd); 1278 outp->wldp_result = WL_NOTSUPPORTED; 1279 err = EINVAL; 1280 break; 1281 } 1282 1283 freemsg(*mp); 1284 *mp = omp; 1285 return (err); 1286 } 1287 1288 /* 1289 * WPA daemon set the WPA keys. 1290 * The WPA keys are negotiated with APs through wpa service. 1291 */ 1292 static int 1293 wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1294 { 1295 mblk_t *omp; 1296 wldp_t *outp; 1297 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1298 wl_key_t *ik = (wl_key_t *)(inp->wldp_buf); 1299 struct ieee80211_node *in; 1300 struct ieee80211_key *wk; 1301 uint16_t kid; 1302 int err = 0; 1303 1304 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1305 return (ENOMEM); 1306 outp = (wldp_t *)omp->b_rptr; 1307 1308 switch (cmd) { 1309 case WLAN_GET_PARAM: 1310 outp->wldp_result = WL_WRITEONLY; 1311 err = EINVAL; 1312 break; 1313 case WLAN_SET_PARAM: 1314 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_wpakey: " 1315 "idx=%d\n", ik->ik_keyix); 1316 /* NB: cipher support is verified by ieee80211_crypt_newkey */ 1317 /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */ 1318 if (ik->ik_keylen > sizeof (ik->ik_keydata)) { 1319 ieee80211_err("wifi_cfg_wpakey: key too long\n"); 1320 outp->wldp_result = WL_NOTSUPPORTED; 1321 err = EINVAL; 1322 break; 1323 } 1324 kid = ik->ik_keyix; 1325 if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) { 1326 ieee80211_err("wifi_cfg_wpakey: incorrect keyix\n"); 1327 outp->wldp_result = WL_NOTSUPPORTED; 1328 err = EINVAL; 1329 break; 1330 1331 } else { 1332 wk = &ic->ic_nw_keys[kid]; 1333 /* 1334 * Global slots start off w/o any assigned key index. 1335 * Force one here for consistency with WEPKEY. 1336 */ 1337 if (wk->wk_keyix == IEEE80211_KEYIX_NONE) 1338 wk->wk_keyix = kid; 1339 /* in = ic->ic_bss; */ 1340 in = NULL; 1341 } 1342 1343 KEY_UPDATE_BEGIN(ic); 1344 if (ieee80211_crypto_newkey(ic, ik->ik_type, 1345 ik->ik_flags, wk)) { 1346 wk->wk_keylen = ik->ik_keylen; 1347 /* NB: MIC presence is implied by cipher type */ 1348 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE) 1349 wk->wk_keylen = IEEE80211_KEYBUF_SIZE; 1350 wk->wk_keyrsc = ik->ik_keyrsc; 1351 wk->wk_keytsc = 0; /* new key, reset */ 1352 wk->wk_flags |= ik->ik_flags & 1353 (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV); 1354 (void) memset(wk->wk_key, 0, sizeof (wk->wk_key)); 1355 (void) memcpy(wk->wk_key, ik->ik_keydata, 1356 ik->ik_keylen); 1357 if (!ieee80211_crypto_setkey(ic, wk, 1358 in != NULL ? in->in_macaddr : ik->ik_macaddr)) { 1359 err = EIO; 1360 outp->wldp_result = WL_HW_ERROR; 1361 } else if ((ik->ik_flags & IEEE80211_KEY_DEFAULT)) { 1362 ic->ic_def_txkey = kid; 1363 ieee80211_mac_update(ic); 1364 } 1365 } else { 1366 err = EIO; 1367 outp->wldp_result = WL_HW_ERROR; 1368 } 1369 KEY_UPDATE_END(ic); 1370 break; 1371 default: 1372 ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd); 1373 outp->wldp_result = WL_NOTSUPPORTED; 1374 err = EINVAL; 1375 break; 1376 } 1377 1378 freemsg(*mp); 1379 *mp = omp; 1380 return (err); 1381 } 1382 1383 /* 1384 * Delete obsolete keys - keys are dynamically exchanged between APs 1385 * and wpa daemon. 1386 */ 1387 static int 1388 wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1389 { 1390 mblk_t *omp; 1391 wldp_t *outp; 1392 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1393 wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf; 1394 int kid; 1395 int err = 0; 1396 1397 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1398 return (ENOMEM); 1399 outp = (wldp_t *)omp->b_rptr; 1400 1401 switch (cmd) { 1402 case WLAN_GET_PARAM: 1403 outp->wldp_result = WL_WRITEONLY; 1404 err = EINVAL; 1405 break; 1406 case WLAN_SET_PARAM: 1407 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_delkey: " 1408 "keyix=%d\n", dk->idk_keyix); 1409 kid = dk->idk_keyix; 1410 if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) { 1411 ieee80211_err("wifi_cfg_delkey: incorrect keyix\n"); 1412 outp->wldp_result = WL_NOTSUPPORTED; 1413 err = EINVAL; 1414 break; 1415 1416 } else { 1417 (void) ieee80211_crypto_delkey(ic, 1418 &ic->ic_nw_keys[kid]); 1419 ieee80211_mac_update(ic); 1420 } 1421 break; 1422 default: 1423 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1424 outp->wldp_result = WL_NOTSUPPORTED; 1425 err = EINVAL; 1426 break; 1427 } 1428 1429 freemsg(*mp); 1430 *mp = omp; 1431 return (err); 1432 } 1433 1434 /* 1435 * The OPTIE will be used in the association request. 1436 */ 1437 static int 1438 wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1439 { 1440 mblk_t *omp; 1441 wldp_t *outp; 1442 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1443 wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf; 1444 char *ie; 1445 int err = 0; 1446 1447 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1448 return (ENOMEM); 1449 outp = (wldp_t *)omp->b_rptr; 1450 1451 switch (cmd) { 1452 case WLAN_GET_PARAM: 1453 outp->wldp_result = WL_WRITEONLY; 1454 err = EINVAL; 1455 break; 1456 case WLAN_SET_PARAM: 1457 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_setoptie\n"); 1458 /* 1459 * NB: Doing this for ap operation could be useful (e.g. for 1460 * WPA and/or WME) except that it typically is worthless 1461 * without being able to intervene when processing 1462 * association response frames--so disallow it for now. 1463 */ 1464 if (ic->ic_opmode != IEEE80211_M_STA) { 1465 ieee80211_err("wifi_cfg_setoptie: opmode err\n"); 1466 err = EINVAL; 1467 outp->wldp_result = WL_NOTSUPPORTED; 1468 break; 1469 } 1470 if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) { 1471 ieee80211_err("wifi_cfg_setoptie: optie too long\n"); 1472 err = EINVAL; 1473 outp->wldp_result = WL_NOTSUPPORTED; 1474 break; 1475 } 1476 1477 ie = ieee80211_malloc(ie_in->wpa_ie_len); 1478 (void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len); 1479 if (ic->ic_opt_ie != NULL) 1480 ieee80211_free(ic->ic_opt_ie); 1481 ic->ic_opt_ie = ie; 1482 ic->ic_opt_ie_len = ie_in->wpa_ie_len; 1483 break; 1484 default: 1485 ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd); 1486 outp->wldp_result = WL_NOTSUPPORTED; 1487 err = EINVAL; 1488 break; 1489 } 1490 1491 freemsg(*mp); 1492 *mp = omp; 1493 return (err); 1494 } 1495 1496 /* 1497 * To be compatible with drivers/tools of OpenSolaris.org, 1498 * we use a different ID to filter out those APs of WPA mode. 1499 */ 1500 static int 1501 wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1502 { 1503 mblk_t *omp; 1504 wldp_t *outp; 1505 wl_wpa_ess_t *sr; 1506 ieee80211_node_t *in; 1507 ieee80211_node_table_t *nt; 1508 int len, ap_num = 0; 1509 int err = 0; 1510 1511 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 1512 NULL) { 1513 return (ENOMEM); 1514 } 1515 outp = (wldp_t *)omp->b_rptr; 1516 sr = (wl_wpa_ess_t *)outp->wldp_buf; 1517 sr->count = 0; 1518 1519 switch (cmd) { 1520 case WLAN_GET_PARAM: 1521 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n"); 1522 nt = &ic->ic_scan; 1523 IEEE80211_NODE_LOCK(nt); 1524 in = list_head(&nt->nt_node); 1525 while (in != NULL) { 1526 /* filter out non-WPA APs */ 1527 if (in->in_wpa_ie == NULL) { 1528 in = list_next(&nt->nt_node, in); 1529 continue; 1530 } 1531 bcopy(in->in_bssid, sr->ess[ap_num].bssid, 1532 IEEE80211_ADDR_LEN); 1533 sr->ess[ap_num].ssid_len = in->in_esslen; 1534 bcopy(in->in_essid, sr->ess[ap_num].ssid, 1535 in->in_esslen); 1536 sr->ess[ap_num].freq = in->in_chan->ich_freq; 1537 1538 len = in->in_wpa_ie[1] + 2; 1539 bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len); 1540 sr->ess[ap_num].wpa_ie_len = len; 1541 1542 ap_num ++; 1543 in = list_next(&nt->nt_node, in); 1544 } 1545 IEEE80211_NODE_UNLOCK(nt); 1546 sr->count = ap_num; 1547 outp->wldp_length = WIFI_BUF_OFFSET + 1548 offsetof(wl_wpa_ess_t, ess) + 1549 sr->count * sizeof (struct wpa_ess); 1550 omp->b_wptr = omp->b_rptr + outp->wldp_length; 1551 break; 1552 case WLAN_SET_PARAM: 1553 outp->wldp_result = WL_READONLY; 1554 err = EINVAL; 1555 break; 1556 default: 1557 ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd); 1558 outp->wldp_result = WL_NOTSUPPORTED; 1559 err = EINVAL; 1560 break; 1561 } 1562 1563 freemsg(*mp); 1564 *mp = omp; 1565 return (err); 1566 } 1567 1568 /* 1569 * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC 1570 */ 1571 static int 1572 wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1573 { 1574 mblk_t *omp; 1575 wldp_t *outp; 1576 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1577 wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf; 1578 ieee80211_node_t *in; 1579 int err = 0; 1580 uint32_t flags; 1581 1582 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1583 return (ENOMEM); 1584 outp = (wldp_t *)omp->b_rptr; 1585 1586 switch (cmd) { 1587 case WLAN_GET_PARAM: 1588 outp->wldp_result = WL_WRITEONLY; 1589 err = EINVAL; 1590 break; 1591 case WLAN_SET_PARAM: 1592 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_setmlme: " 1593 "op=%d\n", mlme->im_op); 1594 switch (mlme->im_op) { 1595 case IEEE80211_MLME_DISASSOC: 1596 case IEEE80211_MLME_DEAUTH: 1597 if (ic->ic_opmode == IEEE80211_M_STA) { 1598 /* 1599 * Mask ic_flags of IEEE80211_F_WPA to disable 1600 * ieee80211_notify temporarily. 1601 */ 1602 flags = ic->ic_flags; 1603 ic->ic_flags &= ~IEEE80211_F_WPA; 1604 1605 IEEE80211_UNLOCK(ic); 1606 ieee80211_new_state(ic, IEEE80211_S_INIT, 1607 mlme->im_reason); 1608 IEEE80211_LOCK(ic); 1609 1610 ic->ic_flags = flags; 1611 } 1612 break; 1613 case IEEE80211_MLME_ASSOC: 1614 if (ic->ic_opmode != IEEE80211_M_STA) { 1615 ieee80211_err("wifi_cfg_setmlme: opmode err\n"); 1616 err = EINVAL; 1617 outp->wldp_result = WL_NOTSUPPORTED; 1618 break; 1619 } 1620 if (ic->ic_des_esslen != 0) { 1621 /* 1622 * Desired ssid specified; must match both bssid and 1623 * ssid to distinguish ap advertising multiple ssid's. 1624 */ 1625 in = ieee80211_find_node_with_ssid(&ic->ic_scan, 1626 mlme->im_macaddr, 1627 ic->ic_des_esslen, ic->ic_des_essid); 1628 } else { 1629 /* 1630 * Normal case; just match bssid. 1631 */ 1632 in = ieee80211_find_node(&ic->ic_scan, 1633 mlme->im_macaddr); 1634 } 1635 if (in == NULL) { 1636 ieee80211_err("wifi_cfg_setmlme: " 1637 "no matched node\n"); 1638 err = EINVAL; 1639 outp->wldp_result = WL_NOTSUPPORTED; 1640 break; 1641 } 1642 IEEE80211_UNLOCK(ic); 1643 ieee80211_sta_join(ic, in); 1644 IEEE80211_LOCK(ic); 1645 } 1646 break; 1647 default: 1648 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1649 outp->wldp_result = WL_NOTSUPPORTED; 1650 err = EINVAL; 1651 break; 1652 } 1653 1654 freemsg(*mp); 1655 *mp = omp; 1656 return (err); 1657 } 1658 1659 static int 1660 wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd) 1661 { 1662 mblk_t *mp1 = *mp; 1663 wldp_t *wp = (wldp_t *)mp1->b_rptr; 1664 int err = 0; 1665 1666 ASSERT(ic != NULL && mp1 != NULL); 1667 IEEE80211_LOCK_ASSERT(ic); 1668 if (MBLKL(mp1) < WIFI_BUF_OFFSET) { 1669 ieee80211_err("wifi_cfg_getset: " 1670 "invalid input buffer, size=%d\n", MBLKL(mp1)); 1671 return (EINVAL); 1672 } 1673 1674 switch (wp->wldp_id) { 1675 /* Commands */ 1676 case WL_SCAN: 1677 err = wifi_cmd_scan(ic, mp1); 1678 break; 1679 case WL_LOAD_DEFAULTS: 1680 err = wifi_cmd_loaddefaults(ic, mp1); 1681 break; 1682 case WL_DISASSOCIATE: 1683 err = wifi_cmd_disassoc(ic, mp1); 1684 break; 1685 /* Parameters */ 1686 case WL_ESSID: 1687 err = wifi_cfg_essid(ic, cmd, mp); 1688 break; 1689 case WL_BSSID: 1690 err = wifi_cfg_bssid(ic, cmd, mp); 1691 break; 1692 case WL_NODE_NAME: 1693 err = wifi_cfg_nodename(ic, cmd, mp); 1694 break; 1695 case WL_PHY_CONFIG: 1696 err = wifi_cfg_phy(ic, cmd, mp); 1697 break; 1698 case WL_WEP_KEY_TAB: 1699 err = wifi_cfg_wepkey(ic, cmd, mp); 1700 break; 1701 case WL_WEP_KEY_ID: 1702 err = wifi_cfg_keyid(ic, cmd, mp); 1703 break; 1704 case WL_AUTH_MODE: 1705 err = wifi_cfg_authmode(ic, cmd, mp); 1706 break; 1707 case WL_ENCRYPTION: 1708 err = wifi_cfg_encrypt(ic, cmd, mp); 1709 break; 1710 case WL_BSS_TYPE: 1711 err = wifi_cfg_bsstype(ic, cmd, mp); 1712 break; 1713 case WL_DESIRED_RATES: 1714 err = wifi_cfg_desrates(ic, cmd, mp); 1715 break; 1716 case WL_LINKSTATUS: 1717 err = wifi_cfg_linkstatus(ic, cmd, mp); 1718 break; 1719 case WL_ESS_LIST: 1720 err = wifi_cfg_esslist(ic, cmd, mp); 1721 break; 1722 case WL_SUPPORTED_RATES: 1723 err = wifi_cfg_suprates(ic, cmd, mp); 1724 break; 1725 case WL_RSSI: 1726 err = wifi_cfg_rssi(ic, cmd, mp); 1727 break; 1728 /* 1729 * WPA IOCTLs 1730 */ 1731 case WL_CAPABILITY: 1732 err = wifi_cfg_caps(ic, cmd, mp); 1733 break; 1734 case WL_WPA: 1735 err = wifi_cfg_wpa(ic, cmd, mp); 1736 break; 1737 case WL_KEY: 1738 err = wifi_cfg_wpakey(ic, cmd, mp); 1739 break; 1740 case WL_DELKEY: 1741 err = wifi_cfg_delkey(ic, cmd, mp); 1742 break; 1743 case WL_SETOPTIE: 1744 err = wifi_cfg_setoptie(ic, cmd, mp); 1745 break; 1746 case WL_SCANRESULTS: 1747 err = wifi_cfg_scanresults(ic, cmd, mp); 1748 break; 1749 case WL_MLME: 1750 err = wifi_cfg_setmlme(ic, cmd, mp); 1751 break; 1752 default: 1753 wifi_setupoutmsg(mp1, 0); 1754 wp->wldp_result = WL_LACK_FEATURE; 1755 err = ENOTSUP; 1756 break; 1757 } 1758 1759 return (err); 1760 } 1761 1762 /* 1763 * Typically invoked by drivers in response to requests for 1764 * information or to change settings from the userland. 1765 * 1766 * Return value should be checked by WiFi drivers. Return 0 1767 * on success. Otherwise, return non-zero value to indicate 1768 * the error. Driver should operate as below when the return 1769 * error is: 1770 * ENETRESET Reset wireless network and re-start to join a 1771 * WLAN. ENETRESET is returned when a configuration 1772 * parameter has been changed. 1773 * When acknowledge a M_IOCTL message, thie error 1774 * is ignored. 1775 */ 1776 int 1777 ieee80211_ioctl(struct ieee80211com *ic, queue_t *wq, mblk_t *mp) 1778 { 1779 struct iocblk *iocp; 1780 int32_t cmd, err, len; 1781 boolean_t need_privilege; 1782 mblk_t *mp1; 1783 1784 if (MBLKL(mp) < sizeof (struct iocblk)) { 1785 ieee80211_err("ieee80211_ioctl: ioctl buffer too short, %u\n", 1786 MBLKL(mp)); 1787 miocnak(wq, mp, 0, EINVAL); 1788 return (EINVAL); 1789 } 1790 1791 /* 1792 * Validate the command 1793 */ 1794 iocp = (struct iocblk *)mp->b_rptr; 1795 iocp->ioc_error = 0; 1796 cmd = iocp->ioc_cmd; 1797 need_privilege = B_TRUE; 1798 switch (cmd) { 1799 case WLAN_SET_PARAM: 1800 case WLAN_COMMAND: 1801 break; 1802 case WLAN_GET_PARAM: 1803 need_privilege = B_FALSE; 1804 break; 1805 default: 1806 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): " 1807 "unknown cmd 0x%x\n", cmd); 1808 miocnak(wq, mp, 0, EINVAL); 1809 return (EINVAL); 1810 } 1811 1812 if (need_privilege) { 1813 /* 1814 * Check for specific net_config privilege on Solaris 10+. 1815 */ 1816 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 1817 if (err != 0) { 1818 miocnak(wq, mp, 0, err); 1819 return (err); 1820 } 1821 } 1822 1823 IEEE80211_LOCK(ic); 1824 1825 /* sanity check */ 1826 mp1 = mp->b_cont; 1827 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 1828 mp1 == NULL) { 1829 miocnak(wq, mp, 0, EINVAL); 1830 IEEE80211_UNLOCK(ic); 1831 return (EINVAL); 1832 } 1833 1834 /* assuming single data block */ 1835 if (mp1->b_cont != NULL) { 1836 freemsg(mp1->b_cont); 1837 mp1->b_cont = NULL; 1838 } 1839 1840 err = wifi_cfg_getset(ic, &mp1, cmd); 1841 mp->b_cont = mp1; 1842 IEEE80211_UNLOCK(ic); 1843 1844 len = msgdsize(mp1); 1845 /* ignore ENETRESET when acknowledge the M_IOCTL message */ 1846 if (err == 0 || err == ENETRESET) 1847 miocack(wq, mp, len, 0); 1848 else 1849 miocack(wq, mp, len, err); 1850 1851 return (err); 1852 } 1853