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 break; 691 case WLAN_SET_PARAM: 692 outp->wldp_result = WL_READONLY; 693 err = EINVAL; 694 break; 695 default: 696 ieee80211_err("wifi_cfg_linkstatus: unknown command %x\n", cmd); 697 outp->wldp_result = WL_NOTSUPPORTED; 698 err = EINVAL; 699 break; 700 } 701 702 freemsg(*mp); 703 *mp = omp; 704 return (err); 705 } 706 707 static int 708 wifi_cfg_suprates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 709 { 710 mblk_t *omp; 711 wldp_t *outp; 712 wl_rates_t *ow_rates; 713 const struct ieee80211_rateset *srs; 714 uint8_t srates, *drates; 715 int err, buflen, i, j, k, l; 716 717 err = 0; 718 /* rate value (wl_rates_rates) is of type char */ 719 buflen = offsetof(wl_rates_t, wl_rates_rates) + 720 sizeof (char) * IEEE80211_MODE_MAX * IEEE80211_RATE_MAXSIZE; 721 if ((omp = wifi_getoutmsg(*mp, cmd, buflen)) == NULL) 722 return (ENOMEM); 723 outp = (wldp_t *)omp->b_rptr; 724 ow_rates = (wl_rates_t *)outp->wldp_buf; 725 726 switch (cmd) { 727 case WLAN_GET_PARAM: 728 /* all rates supported by the device */ 729 ow_rates->wl_rates_num = 0; 730 drates = (uint8_t *)ow_rates->wl_rates_rates; 731 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 732 srs = &ic->ic_sup_rates[i]; 733 if (srs->ir_nrates == 0) 734 continue; 735 736 for (j = 0; j < srs->ir_nrates; j++) { 737 srates = IEEE80211_RV(srs->ir_rates[j]); 738 /* sort and skip duplicated rates */ 739 for (k = 0; k < ow_rates->wl_rates_num; k++) { 740 if (srates <= drates[k]) 741 break; 742 } 743 if (srates == drates[k]) 744 continue; /* duplicate, skip */ 745 /* sort */ 746 for (l = ow_rates->wl_rates_num; l > k; l--) 747 drates[l] = drates[l-1]; 748 drates[k] = srates; 749 ow_rates->wl_rates_num++; 750 } 751 } 752 break; 753 case WLAN_SET_PARAM: 754 outp->wldp_result = WL_READONLY; 755 err = EINVAL; 756 break; 757 default: 758 ieee80211_err("wifi_cfg_suprates: unknown command %x\n", cmd); 759 outp->wldp_result = WL_NOTSUPPORTED; 760 err = EINVAL; 761 break; 762 } 763 764 freemsg(*mp); 765 *mp = omp; 766 return (err); 767 } 768 769 static int 770 wifi_cfg_desrates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 771 { 772 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 773 wl_rates_t *iw_rates = (wl_rates_t *)inp->wldp_buf; 774 mblk_t *omp; 775 wldp_t *outp; 776 wl_rates_t *ow_rates; 777 struct ieee80211_node *in = ic->ic_bss; 778 struct ieee80211_rateset *rs = &in->in_rates; 779 uint8_t drate, srate; 780 int err, i, j; 781 boolean_t found; 782 783 err = 0; 784 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rates_t))) == NULL) 785 return (ENOMEM); 786 outp = (wldp_t *)omp->b_rptr; 787 ow_rates = (wl_rates_t *)outp->wldp_buf; 788 789 srate = rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL; 790 switch (cmd) { 791 case WLAN_GET_PARAM: 792 ow_rates->wl_rates_num = 1; 793 ow_rates->wl_rates_rates[0] = 794 (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 795 srate : ic->ic_fixed_rate; 796 break; 797 case WLAN_SET_PARAM: 798 drate = iw_rates->wl_rates_rates[0]; 799 if (ic->ic_fixed_rate == drate) 800 break; 801 802 ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_desrates: " 803 "set desired rate=%u\n", drate); 804 805 if (drate == 0) { /* reset */ 806 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 807 if (ic->ic_state == IEEE80211_S_RUN) { 808 IEEE80211_UNLOCK(ic); 809 ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0); 810 IEEE80211_LOCK(ic); 811 } 812 break; 813 } 814 815 /* 816 * Set desired rate. the desired rate is for data transfer 817 * and usually is checked and used when driver changes to 818 * RUN state. 819 * If the driver is in AUTH | ASSOC | RUN state, desired 820 * rate is checked against rates supported by current ESS. 821 * If it's supported and current state is AUTH|ASSOC, nothing 822 * needs to be doen by driver since the desired rate will 823 * be enabled when the device changes to RUN state. And 824 * when current state is RUN, Re-associate with the ESS to 825 * enable the desired rate. 826 */ 827 if (ic->ic_state != IEEE80211_S_INIT && 828 ic->ic_state != IEEE80211_S_SCAN) { 829 /* check if the rate is supported by current ESS */ 830 for (i = 0; i < rs->ir_nrates; i++) { 831 if (drate == IEEE80211_RV(rs->ir_rates[i])) 832 break; 833 } 834 if (i < rs->ir_nrates) { /* supported */ 835 ic->ic_fixed_rate = drate; 836 if (ic->ic_state == IEEE80211_S_RUN) { 837 IEEE80211_UNLOCK(ic); 838 ieee80211_new_state(ic, 839 IEEE80211_S_ASSOC, 0); 840 IEEE80211_LOCK(ic); 841 } 842 break; 843 } 844 } 845 846 /* check the rate is supported by device */ 847 found = B_FALSE; 848 for (i = 0; i < IEEE80211_MODE_MAX; i++) { 849 rs = &ic->ic_sup_rates[i]; 850 for (j = 0; j < rs->ir_nrates; j++) { 851 if (drate == IEEE80211_RV(rs->ir_rates[j])) { 852 found = B_TRUE; 853 break; 854 } 855 } 856 if (found) 857 break; 858 } 859 if (!found) { 860 ieee80211_err("wifi_cfg_desrates: " 861 "invalid rate %d\n", drate); 862 outp->wldp_result = WL_NOTSUPPORTED; 863 err = EINVAL; 864 break; 865 } 866 ic->ic_fixed_rate = drate; 867 if (ic->ic_state != IEEE80211_S_SCAN) 868 err = ENETRESET; /* restart */ 869 break; 870 default: 871 ieee80211_err("wifi_cfg_desrates: unknown command %x\n", cmd); 872 outp->wldp_result = WL_NOTSUPPORTED; 873 err = EINVAL; 874 break; 875 } 876 877 freemsg(*mp); 878 *mp = omp; 879 return (err); 880 } 881 882 /* 883 * Rescale device's RSSI value to (0, 15) as required by WiFi 884 * driver IOCTLs (PSARC/2003/722) 885 */ 886 static wl_rssi_t 887 wifi_getrssi(struct ieee80211_node *in) 888 { 889 struct ieee80211com *ic = in->in_ic; 890 wl_rssi_t rssi, max_rssi; 891 892 rssi = ic->ic_node_getrssi(in); 893 max_rssi = (ic->ic_maxrssi == 0) ? IEEE80211_MAXRSSI : ic->ic_maxrssi; 894 if (rssi == 0) 895 rssi = 0; 896 else if (rssi >= max_rssi) 897 rssi = MAX_RSSI; 898 else 899 rssi = rssi * MAX_RSSI / max_rssi + 1; 900 901 return (rssi); 902 } 903 904 static int 905 wifi_cfg_rssi(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 906 { 907 mblk_t *omp; 908 wldp_t *outp; 909 wl_rssi_t *ow_rssi; 910 int err = 0; 911 912 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rssi_t))) == NULL) 913 return (ENOMEM); 914 outp = (wldp_t *)omp->b_rptr; 915 ow_rssi = (wl_rssi_t *)outp->wldp_buf; 916 917 switch (cmd) { 918 case WLAN_GET_PARAM: 919 *ow_rssi = wifi_getrssi(ic->ic_bss); 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_rssi: unknown command %x\n", cmd); 927 outp->wldp_result = WL_NOTSUPPORTED; 928 return (EINVAL); 929 } 930 931 freemsg(*mp); 932 *mp = omp; 933 return (err); 934 } 935 936 /* 937 * maximum scan wait time in second. 938 * Time spent on scaning one channel is usually 100~200ms. The maximum 939 * number of channels defined in wifi_ioctl.h is 99 (MAX_CHANNEL_NUM). 940 * As a result the maximum total scan time is defined as below in ms. 941 */ 942 #define WAIT_SCAN_MAX (200 * MAX_CHANNEL_NUM) 943 944 static void 945 wifi_wait_scan(struct ieee80211com *ic) 946 { 947 ieee80211_impl_t *im = ic->ic_private; 948 949 while ((ic->ic_flags & (IEEE80211_F_SCAN | IEEE80211_F_ASCAN)) != 0) { 950 if (cv_timedwait_sig(&im->im_scan_cv, &ic->ic_genlock, 951 ddi_get_lbolt() + drv_usectohz(WAIT_SCAN_MAX * 1000)) != 952 0) { 953 break; 954 } 955 } 956 } 957 958 #define WIFI_HAVE_CAP(in, flag) (((in)->in_capinfo & (flag)) ? 1 : 0) 959 960 /* 961 * Callback function used by ieee80211_iterate_nodes() in 962 * wifi_cfg_esslist() to get info of each node in a node table 963 * arg output buffer, pointer to wl_ess_list_t 964 * in each node in the node table 965 */ 966 static void 967 wifi_read_ap(void *arg, struct ieee80211_node *in) 968 { 969 wl_ess_list_t *aps = arg; 970 ieee80211com_t *ic = in->in_ic; 971 struct ieee80211_channel *chan = in->in_chan; 972 struct ieee80211_rateset *rates = &(in->in_rates); 973 wl_ess_conf_t *conf; 974 uint8_t *end; 975 uint_t i, nrates; 976 977 end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN - 978 sizeof (wl_ess_list_t); 979 conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num]; 980 if ((uint8_t *)conf > end) 981 return; 982 983 /* skip newly allocated NULL bss node */ 984 if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr)) 985 return; 986 987 conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen; 988 bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid, 989 in->in_esslen); 990 bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN); 991 conf->wl_ess_conf_wepenabled = 992 (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ? 993 WL_ENC_WEP : WL_NOENCRYPTION); 994 conf->wl_ess_conf_bsstype = 995 (in->in_capinfo & IEEE80211_CAPINFO_ESS ? 996 WL_BSS_BSS : WL_BSS_IBSS); 997 conf->wl_ess_conf_sl = wifi_getrssi(in); 998 conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1); 999 1000 /* physical (FH, DS, ERP) parameters */ 1001 if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) { 1002 wl_ofdm_t *ofdm = 1003 (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf); 1004 ofdm->wl_ofdm_subtype = WL_OFDM; 1005 ofdm->wl_ofdm_frequency = chan->ich_freq; 1006 } else { 1007 switch (in->in_phytype) { 1008 case IEEE80211_T_FH: { 1009 wl_fhss_t *fhss = (wl_fhss_t *) 1010 &((conf->wl_phy_conf).wl_phy_fhss_conf); 1011 1012 fhss->wl_fhss_subtype = WL_FHSS; 1013 fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan); 1014 fhss->wl_fhss_dwelltime = in->in_fhdwell; 1015 break; 1016 } 1017 case IEEE80211_T_DS: { 1018 wl_dsss_t *dsss = (wl_dsss_t *) 1019 &((conf->wl_phy_conf).wl_phy_dsss_conf); 1020 1021 dsss->wl_dsss_subtype = WL_DSSS; 1022 dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan); 1023 dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in, 1024 IEEE80211_CAPINFO_SHORT_PREAMBLE); 1025 dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in, 1026 IEEE80211_CAPINFO_CHNL_AGILITY); 1027 dsss->wl_dsss_have_pbcc = dsss->wl_dsss_pbcc_enable = 1028 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 1029 break; 1030 } 1031 case IEEE80211_T_OFDM: { 1032 wl_erp_t *erp = (wl_erp_t *) 1033 &((conf->wl_phy_conf).wl_phy_erp_conf); 1034 1035 erp->wl_erp_subtype = WL_ERP; 1036 erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan); 1037 erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in, 1038 IEEE80211_CAPINFO_SHORT_PREAMBLE); 1039 erp->wl_erp_have_agility = erp->wl_erp_agility_enabled = 1040 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_CHNL_AGILITY); 1041 erp->wl_erp_have_pbcc = erp->wl_erp_pbcc_enabled = 1042 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC); 1043 erp->wl_erp_dsss_ofdm_enabled = 1044 WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_DSSSOFDM); 1045 erp->wl_erp_sst_enabled = WIFI_HAVE_CAP(in, 1046 IEEE80211_CAPINFO_SHORT_SLOTTIME); 1047 break; 1048 } /* case IEEE80211_T_OFDM */ 1049 } /* switch in->in_phytype */ 1050 } 1051 1052 /* supported rates */ 1053 nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES); 1054 /* 1055 * The number of supported rates might exceed 1056 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates 1057 * first so userland command could properly show 1058 * maximum speed of AP 1059 */ 1060 for (i = 0; i < nrates; i++) { 1061 conf->wl_supported_rates[i] = 1062 rates->ir_rates[rates->ir_nrates - i - 1]; 1063 } 1064 1065 aps->wl_ess_list_num++; 1066 } 1067 1068 static int 1069 wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1070 { 1071 mblk_t *omp; 1072 wldp_t *outp; 1073 wl_ess_list_t *ow_aps; 1074 int err = 0; 1075 1076 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 1077 NULL) { 1078 return (ENOMEM); 1079 } 1080 outp = (wldp_t *)omp->b_rptr; 1081 ow_aps = (wl_ess_list_t *)outp->wldp_buf; 1082 1083 switch (cmd) { 1084 case WLAN_GET_PARAM: 1085 ow_aps->wl_ess_list_num = 0; 1086 ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps); 1087 outp->wldp_length = WIFI_BUF_OFFSET + 1088 offsetof(wl_ess_list_t, wl_ess_list_ess) + 1089 ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t); 1090 omp->b_wptr = omp->b_rptr + outp->wldp_length; 1091 break; 1092 case WLAN_SET_PARAM: 1093 outp->wldp_result = WL_READONLY; 1094 err = EINVAL; 1095 break; 1096 default: 1097 ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd); 1098 outp->wldp_result = WL_NOTSUPPORTED; 1099 err = EINVAL; 1100 break; 1101 } 1102 1103 freemsg(*mp); 1104 *mp = omp; 1105 return (err); 1106 } 1107 1108 /* 1109 * Scan the network for all available ESSs. 1110 * IEEE80211_F_SCANONLY is set when current state is INIT. And 1111 * with this flag, after scan the state will be changed back to 1112 * INIT. The reason is at the end of SCAN stage, the STA will 1113 * consequently connect to an AP. Then it looks unreasonable that 1114 * for a disconnected device, A SCAN command causes it connected. 1115 * So the state is changed back to INIT. 1116 */ 1117 static int 1118 wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp) 1119 { 1120 int ostate = ic->ic_state; 1121 1122 /* 1123 * Do not scan when current state is RUN. The reason is 1124 * when connected, STA is on the same channel as AP. But 1125 * to do scan, STA have to switch to each available channel, 1126 * send probe request and wait certian time for probe 1127 * response/beacon. Then when the STA switches to a channel 1128 * different than AP's, as a result it cannot send/receive 1129 * data packets to/from the connected WLAN. This eventually 1130 * will cause data loss. 1131 */ 1132 if (ostate == IEEE80211_S_RUN) 1133 return (0); 1134 1135 IEEE80211_UNLOCK(ic); 1136 1137 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1138 IEEE80211_LOCK(ic); 1139 if (ostate == IEEE80211_S_INIT) 1140 ic->ic_flags |= IEEE80211_F_SCANONLY; 1141 1142 /* Don't wait on WPA mode */ 1143 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) { 1144 /* wait scan complete */ 1145 wifi_wait_scan(ic); 1146 } 1147 1148 wifi_setupoutmsg(mp, 0); 1149 return (0); 1150 } 1151 1152 static void 1153 wifi_loaddefdata(struct ieee80211com *ic) 1154 { 1155 struct ieee80211_node *in = ic->ic_bss; 1156 int i; 1157 1158 ic->ic_des_esslen = 0; 1159 bzero(ic->ic_des_essid, IEEE80211_NWID_LEN); 1160 ic->ic_flags &= ~IEEE80211_F_DESBSSID; 1161 bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN); 1162 bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN); 1163 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 1164 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 1165 bzero(ic->ic_nickname, IEEE80211_NWID_LEN); 1166 in->in_authmode = IEEE80211_AUTH_OPEN; 1167 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 1168 ic->ic_flags &= ~IEEE80211_F_WPA; /* mask WPA mode */ 1169 ic->ic_evq_head = ic->ic_evq_tail = 0; /* reset Queue */ 1170 ic->ic_def_txkey = 0; 1171 for (i = 0; i < MAX_NWEPKEYS; i++) { 1172 ic->ic_nw_keys[i].wk_keylen = 0; 1173 bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE); 1174 } 1175 ic->ic_curmode = IEEE80211_MODE_AUTO; 1176 } 1177 1178 static int 1179 wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp) 1180 { 1181 wifi_loaddefdata(ic); 1182 wifi_setupoutmsg(mp, 0); 1183 return (ENETRESET); 1184 } 1185 1186 static int 1187 wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp) 1188 { 1189 if (ic->ic_state != IEEE80211_S_INIT) { 1190 IEEE80211_UNLOCK(ic); 1191 (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1192 IEEE80211_LOCK(ic); 1193 } 1194 wifi_loaddefdata(ic); 1195 wifi_setupoutmsg(mp, 0); 1196 return (0); 1197 } 1198 1199 /* 1200 * Get the capabilities of drivers. 1201 */ 1202 static int 1203 wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1204 { 1205 mblk_t *omp; 1206 wldp_t *outp; 1207 wl_capability_t *o_caps; 1208 int err = 0; 1209 1210 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL) 1211 return (ENOMEM); 1212 outp = (wldp_t *)omp->b_rptr; 1213 o_caps = (wl_capability_t *)outp->wldp_buf; 1214 1215 switch (cmd) { 1216 case WLAN_GET_PARAM: 1217 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_caps: " 1218 "ic_caps = %u\n", ic->ic_caps); 1219 o_caps->caps = ic->ic_caps; 1220 break; 1221 case WLAN_SET_PARAM: 1222 outp->wldp_result = WL_READONLY; 1223 err = EINVAL; 1224 break; 1225 default: 1226 ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd); 1227 outp->wldp_result = WL_NOTSUPPORTED; 1228 err = EINVAL; 1229 break; 1230 } 1231 1232 freemsg(*mp); 1233 *mp = omp; 1234 return (err); 1235 } 1236 1237 /* 1238 * Operating on WPA mode. 1239 */ 1240 static int 1241 wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1242 { 1243 mblk_t *omp; 1244 wldp_t *outp; 1245 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1246 wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf; 1247 wl_wpa_t *o_wpa; 1248 int err = 0; 1249 1250 if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL) 1251 return (ENOMEM); 1252 outp = (wldp_t *)omp->b_rptr; 1253 o_wpa = (wl_wpa_t *)outp->wldp_buf; 1254 1255 switch (cmd) { 1256 case WLAN_GET_PARAM: 1257 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_wpa: " 1258 "get wpa=%u\n", wpa->wpa_flag); 1259 o_wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA)? 1 : 0); 1260 break; 1261 case WLAN_SET_PARAM: 1262 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_wpa: " 1263 "set wpa=%u\n", wpa->wpa_flag); 1264 if (wpa->wpa_flag > 0) { /* enable WPA mode */ 1265 ic->ic_flags |= IEEE80211_F_PRIVACY; 1266 ic->ic_flags |= IEEE80211_F_WPA; 1267 } else { 1268 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 1269 ic->ic_flags &= ~IEEE80211_F_WPA; 1270 } 1271 break; 1272 default: 1273 ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd); 1274 outp->wldp_result = WL_NOTSUPPORTED; 1275 err = EINVAL; 1276 break; 1277 } 1278 1279 freemsg(*mp); 1280 *mp = omp; 1281 return (err); 1282 } 1283 1284 /* 1285 * WPA daemon set the WPA keys. 1286 * The WPA keys are negotiated with APs through wpa service. 1287 */ 1288 static int 1289 wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1290 { 1291 mblk_t *omp; 1292 wldp_t *outp; 1293 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1294 wl_key_t *ik = (wl_key_t *)(inp->wldp_buf); 1295 struct ieee80211_node *in; 1296 struct ieee80211_key *wk; 1297 uint16_t kid; 1298 int err = 0; 1299 1300 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1301 return (ENOMEM); 1302 outp = (wldp_t *)omp->b_rptr; 1303 1304 switch (cmd) { 1305 case WLAN_GET_PARAM: 1306 outp->wldp_result = WL_WRITEONLY; 1307 err = EINVAL; 1308 break; 1309 case WLAN_SET_PARAM: 1310 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_wpakey: " 1311 "idx=%d\n", ik->ik_keyix); 1312 /* NB: cipher support is verified by ieee80211_crypt_newkey */ 1313 /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */ 1314 if (ik->ik_keylen > sizeof (ik->ik_keydata)) { 1315 ieee80211_err("wifi_cfg_wpakey: key too long\n"); 1316 outp->wldp_result = WL_NOTSUPPORTED; 1317 err = EINVAL; 1318 break; 1319 } 1320 kid = ik->ik_keyix; 1321 if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) { 1322 ieee80211_err("wifi_cfg_wpakey: incorrect keyix\n"); 1323 outp->wldp_result = WL_NOTSUPPORTED; 1324 err = EINVAL; 1325 break; 1326 1327 } else { 1328 wk = &ic->ic_nw_keys[kid]; 1329 /* 1330 * Global slots start off w/o any assigned key index. 1331 * Force one here for consistency with WEPKEY. 1332 */ 1333 if (wk->wk_keyix == IEEE80211_KEYIX_NONE) 1334 wk->wk_keyix = kid; 1335 /* in = ic->ic_bss; */ 1336 in = NULL; 1337 } 1338 1339 KEY_UPDATE_BEGIN(ic); 1340 if (ieee80211_crypto_newkey(ic, ik->ik_type, 1341 ik->ik_flags, wk)) { 1342 wk->wk_keylen = ik->ik_keylen; 1343 /* NB: MIC presence is implied by cipher type */ 1344 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE) 1345 wk->wk_keylen = IEEE80211_KEYBUF_SIZE; 1346 wk->wk_keyrsc = ik->ik_keyrsc; 1347 wk->wk_keytsc = 0; /* new key, reset */ 1348 wk->wk_flags |= ik->ik_flags & 1349 (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV); 1350 (void) memset(wk->wk_key, 0, sizeof (wk->wk_key)); 1351 (void) memcpy(wk->wk_key, ik->ik_keydata, 1352 ik->ik_keylen); 1353 if (!ieee80211_crypto_setkey(ic, wk, 1354 in != NULL ? in->in_macaddr : ik->ik_macaddr)) { 1355 err = EIO; 1356 outp->wldp_result = WL_HW_ERROR; 1357 } else if ((ik->ik_flags & IEEE80211_KEY_DEFAULT)) { 1358 ic->ic_def_txkey = kid; 1359 ieee80211_mac_update(ic); 1360 } 1361 } else { 1362 err = EIO; 1363 outp->wldp_result = WL_HW_ERROR; 1364 } 1365 KEY_UPDATE_END(ic); 1366 break; 1367 default: 1368 ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd); 1369 outp->wldp_result = WL_NOTSUPPORTED; 1370 err = EINVAL; 1371 break; 1372 } 1373 1374 freemsg(*mp); 1375 *mp = omp; 1376 return (err); 1377 } 1378 1379 /* 1380 * Delete obsolete keys - keys are dynamically exchanged between APs 1381 * and wpa daemon. 1382 */ 1383 static int 1384 wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1385 { 1386 mblk_t *omp; 1387 wldp_t *outp; 1388 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1389 wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf; 1390 int kid; 1391 int err = 0; 1392 1393 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1394 return (ENOMEM); 1395 outp = (wldp_t *)omp->b_rptr; 1396 1397 switch (cmd) { 1398 case WLAN_GET_PARAM: 1399 outp->wldp_result = WL_WRITEONLY; 1400 err = EINVAL; 1401 break; 1402 case WLAN_SET_PARAM: 1403 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_delkey: " 1404 "keyix=%d\n", dk->idk_keyix); 1405 kid = dk->idk_keyix; 1406 if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) { 1407 ieee80211_err("wifi_cfg_delkey: incorrect keyix\n"); 1408 outp->wldp_result = WL_NOTSUPPORTED; 1409 err = EINVAL; 1410 break; 1411 1412 } else { 1413 (void) ieee80211_crypto_delkey(ic, 1414 &ic->ic_nw_keys[kid]); 1415 ieee80211_mac_update(ic); 1416 } 1417 break; 1418 default: 1419 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1420 outp->wldp_result = WL_NOTSUPPORTED; 1421 err = EINVAL; 1422 break; 1423 } 1424 1425 freemsg(*mp); 1426 *mp = omp; 1427 return (err); 1428 } 1429 1430 /* 1431 * The OPTIE will be used in the association request. 1432 */ 1433 static int 1434 wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1435 { 1436 mblk_t *omp; 1437 wldp_t *outp; 1438 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1439 wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf; 1440 char *ie; 1441 int err = 0; 1442 1443 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1444 return (ENOMEM); 1445 outp = (wldp_t *)omp->b_rptr; 1446 1447 switch (cmd) { 1448 case WLAN_GET_PARAM: 1449 outp->wldp_result = WL_WRITEONLY; 1450 err = EINVAL; 1451 break; 1452 case WLAN_SET_PARAM: 1453 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_setoptie\n"); 1454 /* 1455 * NB: Doing this for ap operation could be useful (e.g. for 1456 * WPA and/or WME) except that it typically is worthless 1457 * without being able to intervene when processing 1458 * association response frames--so disallow it for now. 1459 */ 1460 if (ic->ic_opmode != IEEE80211_M_STA) { 1461 ieee80211_err("wifi_cfg_setoptie: opmode err\n"); 1462 err = EINVAL; 1463 outp->wldp_result = WL_NOTSUPPORTED; 1464 break; 1465 } 1466 if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) { 1467 ieee80211_err("wifi_cfg_setoptie: optie too long\n"); 1468 err = EINVAL; 1469 outp->wldp_result = WL_NOTSUPPORTED; 1470 break; 1471 } 1472 1473 ie = ieee80211_malloc(ie_in->wpa_ie_len); 1474 (void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len); 1475 if (ic->ic_opt_ie != NULL) 1476 ieee80211_free(ic->ic_opt_ie); 1477 ic->ic_opt_ie = ie; 1478 ic->ic_opt_ie_len = ie_in->wpa_ie_len; 1479 break; 1480 default: 1481 ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd); 1482 outp->wldp_result = WL_NOTSUPPORTED; 1483 err = EINVAL; 1484 break; 1485 } 1486 1487 freemsg(*mp); 1488 *mp = omp; 1489 return (err); 1490 } 1491 1492 /* 1493 * To be compatible with drivers/tools of OpenSolaris.org, 1494 * we use a different ID to filter out those APs of WPA mode. 1495 */ 1496 static int 1497 wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1498 { 1499 mblk_t *omp; 1500 wldp_t *outp; 1501 wl_wpa_ess_t *sr; 1502 ieee80211_node_t *in; 1503 ieee80211_node_table_t *nt; 1504 int len, ap_num = 0; 1505 int err = 0; 1506 1507 if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) == 1508 NULL) { 1509 return (ENOMEM); 1510 } 1511 outp = (wldp_t *)omp->b_rptr; 1512 sr = (wl_wpa_ess_t *)outp->wldp_buf; 1513 sr->count = 0; 1514 1515 switch (cmd) { 1516 case WLAN_GET_PARAM: 1517 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n"); 1518 nt = &ic->ic_scan; 1519 IEEE80211_NODE_LOCK(nt); 1520 in = list_head(&nt->nt_node); 1521 while (in != NULL) { 1522 /* filter out non-WPA APs */ 1523 if (in->in_wpa_ie == NULL) { 1524 in = list_next(&nt->nt_node, in); 1525 continue; 1526 } 1527 bcopy(in->in_bssid, sr->ess[ap_num].bssid, 1528 IEEE80211_ADDR_LEN); 1529 sr->ess[ap_num].ssid_len = in->in_esslen; 1530 bcopy(in->in_essid, sr->ess[ap_num].ssid, 1531 in->in_esslen); 1532 sr->ess[ap_num].freq = in->in_chan->ich_freq; 1533 1534 len = in->in_wpa_ie[1] + 2; 1535 bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len); 1536 sr->ess[ap_num].wpa_ie_len = len; 1537 1538 ap_num ++; 1539 in = list_next(&nt->nt_node, in); 1540 } 1541 IEEE80211_NODE_UNLOCK(nt); 1542 sr->count = ap_num; 1543 outp->wldp_length = WIFI_BUF_OFFSET + 1544 offsetof(wl_wpa_ess_t, ess) + 1545 sr->count * sizeof (struct wpa_ess); 1546 omp->b_wptr = omp->b_rptr + outp->wldp_length; 1547 break; 1548 case WLAN_SET_PARAM: 1549 outp->wldp_result = WL_READONLY; 1550 err = EINVAL; 1551 break; 1552 default: 1553 ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd); 1554 outp->wldp_result = WL_NOTSUPPORTED; 1555 err = EINVAL; 1556 break; 1557 } 1558 1559 freemsg(*mp); 1560 *mp = omp; 1561 return (err); 1562 } 1563 1564 /* 1565 * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC 1566 */ 1567 static int 1568 wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp) 1569 { 1570 mblk_t *omp; 1571 wldp_t *outp; 1572 wldp_t *inp = (wldp_t *)(*mp)->b_rptr; 1573 wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf; 1574 ieee80211_node_t *in; 1575 int err = 0; 1576 uint32_t flags; 1577 1578 if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL) 1579 return (ENOMEM); 1580 outp = (wldp_t *)omp->b_rptr; 1581 1582 switch (cmd) { 1583 case WLAN_GET_PARAM: 1584 outp->wldp_result = WL_WRITEONLY; 1585 err = EINVAL; 1586 break; 1587 case WLAN_SET_PARAM: 1588 ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_setmlme: " 1589 "op=%d\n", mlme->im_op); 1590 switch (mlme->im_op) { 1591 case IEEE80211_MLME_DISASSOC: 1592 case IEEE80211_MLME_DEAUTH: 1593 if (ic->ic_opmode == IEEE80211_M_STA) { 1594 /* 1595 * Mask ic_flags of IEEE80211_F_WPA to disable 1596 * ieee80211_notify temporarily. 1597 */ 1598 flags = ic->ic_flags; 1599 ic->ic_flags &= ~IEEE80211_F_WPA; 1600 1601 IEEE80211_UNLOCK(ic); 1602 ieee80211_new_state(ic, IEEE80211_S_INIT, 1603 mlme->im_reason); 1604 IEEE80211_LOCK(ic); 1605 1606 ic->ic_flags = flags; 1607 } 1608 break; 1609 case IEEE80211_MLME_ASSOC: 1610 if (ic->ic_opmode != IEEE80211_M_STA) { 1611 ieee80211_err("wifi_cfg_setmlme: opmode err\n"); 1612 err = EINVAL; 1613 outp->wldp_result = WL_NOTSUPPORTED; 1614 break; 1615 } 1616 if (ic->ic_des_esslen != 0) { 1617 /* 1618 * Desired ssid specified; must match both bssid and 1619 * ssid to distinguish ap advertising multiple ssid's. 1620 */ 1621 in = ieee80211_find_node_with_ssid(&ic->ic_scan, 1622 mlme->im_macaddr, 1623 ic->ic_des_esslen, ic->ic_des_essid); 1624 } else { 1625 /* 1626 * Normal case; just match bssid. 1627 */ 1628 in = ieee80211_find_node(&ic->ic_scan, 1629 mlme->im_macaddr); 1630 } 1631 if (in == NULL) { 1632 ieee80211_err("wifi_cfg_setmlme: " 1633 "no matched node\n"); 1634 err = EINVAL; 1635 outp->wldp_result = WL_NOTSUPPORTED; 1636 break; 1637 } 1638 IEEE80211_UNLOCK(ic); 1639 ieee80211_sta_join(ic, in); 1640 IEEE80211_LOCK(ic); 1641 } 1642 break; 1643 default: 1644 ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd); 1645 outp->wldp_result = WL_NOTSUPPORTED; 1646 err = EINVAL; 1647 break; 1648 } 1649 1650 freemsg(*mp); 1651 *mp = omp; 1652 return (err); 1653 } 1654 1655 static int 1656 wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd) 1657 { 1658 mblk_t *mp1 = *mp; 1659 wldp_t *wp = (wldp_t *)mp1->b_rptr; 1660 int err = 0; 1661 1662 ASSERT(ic != NULL && mp1 != NULL); 1663 IEEE80211_LOCK_ASSERT(ic); 1664 if (MBLKL(mp1) < WIFI_BUF_OFFSET) { 1665 ieee80211_err("wifi_cfg_getset: " 1666 "invalid input buffer, size=%d\n", MBLKL(mp1)); 1667 return (EINVAL); 1668 } 1669 1670 switch (wp->wldp_id) { 1671 /* Commands */ 1672 case WL_SCAN: 1673 err = wifi_cmd_scan(ic, mp1); 1674 break; 1675 case WL_LOAD_DEFAULTS: 1676 err = wifi_cmd_loaddefaults(ic, mp1); 1677 break; 1678 case WL_DISASSOCIATE: 1679 err = wifi_cmd_disassoc(ic, mp1); 1680 break; 1681 /* Parameters */ 1682 case WL_ESSID: 1683 err = wifi_cfg_essid(ic, cmd, mp); 1684 break; 1685 case WL_BSSID: 1686 err = wifi_cfg_bssid(ic, cmd, mp); 1687 break; 1688 case WL_NODE_NAME: 1689 err = wifi_cfg_nodename(ic, cmd, mp); 1690 break; 1691 case WL_PHY_CONFIG: 1692 err = wifi_cfg_phy(ic, cmd, mp); 1693 break; 1694 case WL_WEP_KEY_TAB: 1695 err = wifi_cfg_wepkey(ic, cmd, mp); 1696 break; 1697 case WL_WEP_KEY_ID: 1698 err = wifi_cfg_keyid(ic, cmd, mp); 1699 break; 1700 case WL_AUTH_MODE: 1701 err = wifi_cfg_authmode(ic, cmd, mp); 1702 break; 1703 case WL_ENCRYPTION: 1704 err = wifi_cfg_encrypt(ic, cmd, mp); 1705 break; 1706 case WL_BSS_TYPE: 1707 err = wifi_cfg_bsstype(ic, cmd, mp); 1708 break; 1709 case WL_DESIRED_RATES: 1710 err = wifi_cfg_desrates(ic, cmd, mp); 1711 break; 1712 case WL_LINKSTATUS: 1713 err = wifi_cfg_linkstatus(ic, cmd, mp); 1714 break; 1715 case WL_ESS_LIST: 1716 err = wifi_cfg_esslist(ic, cmd, mp); 1717 break; 1718 case WL_SUPPORTED_RATES: 1719 err = wifi_cfg_suprates(ic, cmd, mp); 1720 break; 1721 case WL_RSSI: 1722 err = wifi_cfg_rssi(ic, cmd, mp); 1723 break; 1724 /* 1725 * WPA IOCTLs 1726 */ 1727 case WL_CAPABILITY: 1728 err = wifi_cfg_caps(ic, cmd, mp); 1729 break; 1730 case WL_WPA: 1731 err = wifi_cfg_wpa(ic, cmd, mp); 1732 break; 1733 case WL_KEY: 1734 err = wifi_cfg_wpakey(ic, cmd, mp); 1735 break; 1736 case WL_DELKEY: 1737 err = wifi_cfg_delkey(ic, cmd, mp); 1738 break; 1739 case WL_SETOPTIE: 1740 err = wifi_cfg_setoptie(ic, cmd, mp); 1741 break; 1742 case WL_SCANRESULTS: 1743 err = wifi_cfg_scanresults(ic, cmd, mp); 1744 break; 1745 case WL_MLME: 1746 err = wifi_cfg_setmlme(ic, cmd, mp); 1747 break; 1748 default: 1749 wifi_setupoutmsg(mp1, 0); 1750 wp->wldp_result = WL_LACK_FEATURE; 1751 err = ENOTSUP; 1752 break; 1753 } 1754 1755 return (err); 1756 } 1757 1758 /* 1759 * Typically invoked by drivers in response to requests for 1760 * information or to change settings from the userland. 1761 * 1762 * Return value should be checked by WiFi drivers. Return 0 1763 * on success. Otherwise, return non-zero value to indicate 1764 * the error. Driver should operate as below when the return 1765 * error is: 1766 * ENETRESET Reset wireless network and re-start to join a 1767 * WLAN. ENETRESET is returned when a configuration 1768 * parameter has been changed. 1769 * When acknowledge a M_IOCTL message, thie error 1770 * is ignored. 1771 */ 1772 int 1773 ieee80211_ioctl(struct ieee80211com *ic, queue_t *wq, mblk_t *mp) 1774 { 1775 struct iocblk *iocp; 1776 int32_t cmd, err, len; 1777 boolean_t need_privilege; 1778 mblk_t *mp1; 1779 1780 if (MBLKL(mp) < sizeof (struct iocblk)) { 1781 ieee80211_err("ieee80211_ioctl: ioctl buffer too short, %u\n", 1782 MBLKL(mp)); 1783 miocnak(wq, mp, 0, EINVAL); 1784 return (EINVAL); 1785 } 1786 1787 /* 1788 * Validate the command 1789 */ 1790 iocp = (struct iocblk *)mp->b_rptr; 1791 iocp->ioc_error = 0; 1792 cmd = iocp->ioc_cmd; 1793 need_privilege = B_TRUE; 1794 switch (cmd) { 1795 case WLAN_SET_PARAM: 1796 case WLAN_COMMAND: 1797 break; 1798 case WLAN_GET_PARAM: 1799 need_privilege = B_FALSE; 1800 break; 1801 default: 1802 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): " 1803 "unknown cmd 0x%x\n", cmd); 1804 miocnak(wq, mp, 0, EINVAL); 1805 return (EINVAL); 1806 } 1807 1808 if (need_privilege) { 1809 /* 1810 * Check for specific net_config privilege on Solaris 10+. 1811 */ 1812 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 1813 if (err != 0) { 1814 miocnak(wq, mp, 0, err); 1815 return (err); 1816 } 1817 } 1818 1819 IEEE80211_LOCK(ic); 1820 1821 /* sanity check */ 1822 mp1 = mp->b_cont; 1823 if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) || 1824 mp1 == NULL) { 1825 miocnak(wq, mp, 0, EINVAL); 1826 IEEE80211_UNLOCK(ic); 1827 return (EINVAL); 1828 } 1829 1830 /* assuming single data block */ 1831 if (mp1->b_cont != NULL) { 1832 freemsg(mp1->b_cont); 1833 mp1->b_cont = NULL; 1834 } 1835 1836 err = wifi_cfg_getset(ic, &mp1, cmd); 1837 mp->b_cont = mp1; 1838 IEEE80211_UNLOCK(ic); 1839 1840 len = msgdsize(mp1); 1841 /* ignore ENETRESET when acknowledge the M_IOCTL message */ 1842 if (err == 0 || err == ENETRESET) 1843 miocack(wq, mp, len, 0); 1844 else 1845 miocack(wq, mp, len, err); 1846 1847 return (err); 1848 } 1849