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