1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <libintl.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stddef.h> 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <string.h> 35 #include <stropts.h> 36 #include <libdevinfo.h> 37 #include <net/if.h> 38 #include <net/if_dl.h> 39 #include <net/if_types.h> 40 #include <libscf.h> 41 #include <libdlwlan.h> 42 #include <libdlwlan_impl.h> 43 #include <net/wpa.h> 44 45 typedef struct val_desc { 46 char *vd_name; 47 uint_t vd_val; 48 } val_desc_t; 49 50 struct prop_desc; 51 52 typedef dladm_status_t wl_pd_getf_t(int, wldp_t *, char **, uint_t *); 53 typedef dladm_status_t wl_pd_setf_t(int, wldp_t *, val_desc_t *, uint_t); 54 typedef dladm_status_t wl_pd_checkf_t(int, wldp_t *, struct prop_desc *, 55 char **, uint_t, val_desc_t **); 56 typedef struct prop_desc { 57 char *pd_name; 58 val_desc_t pd_defval; 59 val_desc_t *pd_modval; 60 uint_t pd_nmodval; 61 wl_pd_setf_t *pd_set; 62 wl_pd_getf_t *pd_getmod; 63 wl_pd_getf_t *pd_get; 64 wl_pd_checkf_t *pd_check; 65 } prop_desc_t; 66 67 static int wpa_instance_create(const char *, void *); 68 static int wpa_instance_delete(const char *); 69 70 static int do_get_bsstype(int, wldp_t *); 71 static int do_get_essid(int, wldp_t *); 72 static int do_get_bssid(int, wldp_t *); 73 static int do_get_signal(int, wldp_t *); 74 static int do_get_encryption(int, wldp_t *); 75 static int do_get_authmode(int, wldp_t *); 76 static int do_get_linkstatus(int, wldp_t *); 77 static int do_get_esslist(int, wldp_t *); 78 static int do_get_rate(int, wldp_t *); 79 static int do_get_phyconf(int, wldp_t *); 80 static int do_get_powermode(int, wldp_t *); 81 static int do_get_radio(int, wldp_t *); 82 static int do_get_mode(int, wldp_t *); 83 static int do_get_capability(int, wldp_t *); 84 static int do_get_wpamode(int, wldp_t *); 85 86 static int do_set_bsstype(int, wldp_t *, dladm_wlan_bsstype_t *); 87 static int do_set_authmode(int, wldp_t *, dladm_wlan_auth_t *); 88 static int do_set_encryption(int, wldp_t *, dladm_wlan_secmode_t *); 89 static int do_set_essid(int, wldp_t *, dladm_wlan_essid_t *); 90 static int do_set_createibss(int, wldp_t *, boolean_t *); 91 static int do_set_key(int, wldp_t *, dladm_wlan_key_t *, uint_t); 92 static int do_set_rate(int, wldp_t *, dladm_wlan_rates_t *); 93 static int do_set_powermode(int, wldp_t *, dladm_wlan_powermode_t *); 94 static int do_set_radio(int, wldp_t *, dladm_wlan_radio_t *); 95 static int do_set_channel(int, wldp_t *, dladm_wlan_channel_t *); 96 97 static int open_link(const char *); 98 static int do_scan(int, wldp_t *); 99 static int do_disconnect(const char *, int, wldp_t *); 100 static boolean_t find_val_by_name(const char *, val_desc_t *, uint_t, uint_t *); 101 static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); 102 static void generate_essid(dladm_wlan_essid_t *); 103 104 static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); 105 106 static wl_pd_getf_t do_get_rate_mod, do_get_rate_prop, do_get_channel_prop, 107 do_get_powermode_prop, do_get_radio_prop; 108 static wl_pd_setf_t do_set_rate_prop, do_set_powermode_prop, 109 do_set_radio_prop; 110 static wl_pd_checkf_t do_check_prop, do_check_rate; 111 112 static val_desc_t linkstatus_vals[] = { 113 { "disconnected", DLADM_WLAN_LINKSTATUS_DISCONNECTED }, 114 { "connected", DLADM_WLAN_LINKSTATUS_CONNECTED } 115 }; 116 117 static val_desc_t secmode_vals[] = { 118 { "none", DLADM_WLAN_SECMODE_NONE }, 119 { "wep", DLADM_WLAN_SECMODE_WEP }, 120 { "wpa", DLADM_WLAN_SECMODE_WPA } 121 }; 122 123 static val_desc_t strength_vals[] = { 124 { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, 125 { "weak", DLADM_WLAN_STRENGTH_WEAK }, 126 { "good", DLADM_WLAN_STRENGTH_GOOD }, 127 { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, 128 { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } 129 }; 130 131 static val_desc_t mode_vals[] = { 132 { "a", DLADM_WLAN_MODE_80211A }, 133 { "b", DLADM_WLAN_MODE_80211B }, 134 { "g", DLADM_WLAN_MODE_80211G }, 135 }; 136 137 static val_desc_t auth_vals[] = { 138 { "open", DLADM_WLAN_AUTH_OPEN }, 139 { "shared", DLADM_WLAN_AUTH_SHARED } 140 }; 141 142 static val_desc_t bsstype_vals[] = { 143 { "bss", DLADM_WLAN_BSSTYPE_BSS }, 144 { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, 145 { "any", DLADM_WLAN_BSSTYPE_ANY } 146 }; 147 148 static val_desc_t radio_vals[] = { 149 { "on", DLADM_WLAN_RADIO_ON }, 150 { "off", DLADM_WLAN_RADIO_OFF } 151 }; 152 153 static val_desc_t powermode_vals[] = { 154 { "off", DLADM_WLAN_PM_OFF }, 155 { "fast", DLADM_WLAN_PM_FAST }, 156 { "max", DLADM_WLAN_PM_MAX } 157 }; 158 159 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 160 static prop_desc_t prop_table[] = { 161 162 { "channel", { NULL, 0 }, NULL, 0, 163 NULL, NULL, do_get_channel_prop, do_check_prop}, 164 165 { "powermode", { "off", DLADM_WLAN_PM_OFF }, powermode_vals, 166 VALCNT(powermode_vals), 167 do_set_powermode_prop, NULL, 168 do_get_powermode_prop, do_check_prop}, 169 170 { "radio", { "on", DLADM_WLAN_RADIO_ON }, radio_vals, 171 VALCNT(radio_vals), 172 do_set_radio_prop, NULL, 173 do_get_radio_prop, do_check_prop}, 174 175 { "speed", { "", 0 }, NULL, 0, 176 do_set_rate_prop, do_get_rate_mod, 177 do_get_rate_prop, do_check_rate} 178 }; 179 /* 180 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 181 * rates to be retrieved. However, we cannot increase it at this 182 * time because it will break binary comatibility with unbundled 183 * WiFi drivers and utilities. So for now we define an additional 184 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 185 */ 186 #define MAX_SUPPORT_RATES 64 187 #define DLADM_WLAN_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 188 #define IS_CONNECTED(gbuf) \ 189 ((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED)) 190 191 static dladm_status_t 192 dladm_wlan_wlresult2status(wldp_t *gbuf) 193 { 194 switch (gbuf->wldp_result) { 195 case WL_SUCCESS: 196 return (DLADM_STATUS_OK); 197 198 case WL_NOTSUPPORTED: 199 case WL_LACK_FEATURE: 200 return (DLADM_STATUS_NOTSUP); 201 202 case WL_READONLY: 203 return (DLADM_STATUS_PROPRDONLY); 204 205 default: 206 break; 207 } 208 209 return (DLADM_STATUS_FAILED); 210 } 211 212 static int 213 open_link(const char *link) 214 { 215 char linkname[MAXPATHLEN]; 216 wldp_t *gbuf; 217 int fd; 218 219 if (link == NULL) 220 return (-1); 221 222 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 223 if ((fd = open(linkname, O_RDWR)) < 0) 224 return (-1); 225 226 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 227 (void) close(fd); 228 return (-1); 229 } 230 231 /* 232 * Check to see if the link is wireless. 233 */ 234 if (do_get_bsstype(fd, gbuf) < 0) { 235 free(gbuf); 236 (void) close(fd); 237 return (-1); 238 } 239 240 free(gbuf); 241 return (fd); 242 } 243 244 static dladm_wlan_mode_t 245 do_convert_mode(wl_phy_conf_t *phyp) 246 { 247 switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) { 248 case WL_ERP: 249 return (DLADM_WLAN_MODE_80211G); 250 case WL_OFDM: 251 return (DLADM_WLAN_MODE_80211A); 252 case WL_DSSS: 253 case WL_FHSS: 254 return (DLADM_WLAN_MODE_80211B); 255 default: 256 break; 257 } 258 259 return (DLADM_WLAN_MODE_NONE); 260 } 261 262 static boolean_t 263 do_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) 264 { 265 wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf; 266 wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf; 267 268 switch (wlfp->wl_fhss_subtype) { 269 case WL_FHSS: 270 case WL_DSSS: 271 case WL_IRBASE: 272 case WL_HRDS: 273 case WL_ERP: 274 *channelp = wlfp->wl_fhss_channel; 275 break; 276 case WL_OFDM: 277 *channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency); 278 break; 279 default: 280 return (B_FALSE); 281 } 282 return (B_TRUE); 283 } 284 285 #define IEEE80211_RATE 0x7f 286 static void 287 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp) 288 { 289 int i; 290 291 (void) memset(attrp, 0, sizeof (*attrp)); 292 293 (void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN, 294 "%s", wlp->wl_ess_conf_essid.wl_essid_essid); 295 attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 296 297 (void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid, 298 DLADM_WLAN_BSSID_LEN); 299 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 300 301 attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled == 302 WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE); 303 if (wlp->wl_ess_conf_reserved[0] > 0) 304 attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 305 attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 306 307 attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ? 308 DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS); 309 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 310 311 attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ? 312 DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED); 313 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 314 315 attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl); 316 attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 317 318 attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf); 319 attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 320 321 for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) { 322 wlp->wl_supported_rates[i] &= IEEE80211_RATE; 323 if (wlp->wl_supported_rates[i] > attrp->wa_speed) 324 attrp->wa_speed = wlp->wl_supported_rates[i]; 325 } 326 if (attrp->wa_speed > 0) 327 attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 328 329 if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, 330 &attrp->wa_channel)) 331 attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL; 332 } 333 334 dladm_status_t 335 dladm_wlan_scan(const char *link, void *arg, 336 boolean_t (*func)(void *, dladm_wlan_attr_t *)) 337 { 338 int fd, i; 339 uint32_t count; 340 wl_ess_conf_t *wlp; 341 wldp_t *gbuf; 342 dladm_wlan_attr_t wlattr; 343 dladm_status_t status; 344 boolean_t connected; 345 346 if ((fd = open_link(link)) < 0) 347 return (DLADM_STATUS_LINKINVAL); 348 349 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 350 status = DLADM_STATUS_NOMEM; 351 goto done; 352 } 353 354 if (do_get_linkstatus(fd, gbuf) < 0) { 355 status = DLADM_STATUS_FAILED; 356 goto done; 357 } 358 connected = IS_CONNECTED(gbuf); 359 360 if (do_scan(fd, gbuf) < 0) { 361 status = DLADM_STATUS_FAILED; 362 goto done; 363 } 364 365 if (func == NULL) { 366 status = DLADM_STATUS_OK; 367 goto done; 368 } 369 370 if (do_get_esslist(fd, gbuf) < 0) { 371 status = DLADM_STATUS_FAILED; 372 goto done; 373 } 374 375 wlp = ((wl_ess_list_t *)gbuf->wldp_buf)->wl_ess_list_ess; 376 count = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num; 377 378 for (i = 0; i < count; i++, wlp++) { 379 fill_wlan_attr(wlp, &wlattr); 380 if (!func(arg, &wlattr)) 381 break; 382 } 383 384 if (!connected) { 385 if (do_get_linkstatus(fd, gbuf) < 0) { 386 status = DLADM_STATUS_FAILED; 387 goto done; 388 } 389 if (IS_CONNECTED(gbuf)) 390 (void) do_disconnect(link, fd, gbuf); 391 } 392 393 status = DLADM_STATUS_OK; 394 done: 395 free(gbuf); 396 (void) close(fd); 397 return (status); 398 } 399 400 /* 401 * Structures used in building the list of eligible WLANs to connect to. 402 * Specifically, `connect_state' has the WLAN attributes that must be matched 403 * (in `cs_attr') and a growing list of WLANs that matched those attributes 404 * chained through `cs_list'. Each element in the list is of type `attr_node' 405 * and has the matching WLAN's attributes and a pointer to the next element. 406 * For convenience, `cs_count' tracks the number of elements in the list. 407 */ 408 typedef struct attr_node { 409 dladm_wlan_attr_t an_attr; 410 struct attr_node *an_next; 411 } attr_node_t; 412 413 typedef struct connect_state { 414 dladm_wlan_attr_t *cs_attr; 415 uint_t cs_count; 416 attr_node_t *cs_list; 417 } connect_state_t; 418 419 /* 420 * Compare two sets of WLAN attributes. For now, we only consider strength 421 * and speed (in that order), which matches the documented default policy for 422 * dladm_wlan_connect(). 423 */ 424 static int 425 attr_compare(const void *p1, const void *p2) 426 { 427 dladm_wlan_attr_t *attrp1, *attrp2; 428 429 attrp1 = (*(dladm_wlan_attr_t **)p1); 430 attrp2 = (*(dladm_wlan_attr_t **)p2); 431 432 if (attrp1->wa_strength < attrp2->wa_strength) 433 return (1); 434 435 if (attrp1->wa_strength > attrp2->wa_strength) 436 return (-1); 437 438 return (attrp2->wa_speed - attrp1->wa_speed); 439 } 440 441 /* 442 * Callback function used by dladm_wlan_connect() to filter out unwanted 443 * WLANs when scanning for available WLANs. Always returns B_TRUE to 444 * continue the scan. 445 */ 446 static boolean_t 447 connect_cb(void *arg, dladm_wlan_attr_t *attrp) 448 { 449 attr_node_t *nodep; 450 dladm_wlan_attr_t *fattrp; 451 connect_state_t *statep = (connect_state_t *)arg; 452 453 fattrp = statep->cs_attr; 454 if (fattrp == NULL) 455 goto append; 456 457 if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid) 458 return (B_TRUE); 459 460 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 && 461 strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes, 462 DLADM_WLAN_MAX_ESSID_LEN) != 0) 463 return (B_TRUE); 464 465 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 466 fattrp->wa_secmode != attrp->wa_secmode) 467 return (B_TRUE); 468 469 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 && 470 fattrp->wa_mode != attrp->wa_mode) 471 return (B_TRUE); 472 473 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 && 474 fattrp->wa_strength != attrp->wa_strength) 475 return (B_TRUE); 476 477 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 && 478 fattrp->wa_speed != attrp->wa_speed) 479 return (B_TRUE); 480 481 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) { 482 attrp->wa_auth = fattrp->wa_auth; 483 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 484 } 485 486 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 487 fattrp->wa_bsstype != attrp->wa_bsstype) 488 return (B_TRUE); 489 490 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 && 491 memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes, 492 DLADM_WLAN_BSSID_LEN) != 0) 493 return (B_TRUE); 494 append: 495 nodep = malloc(sizeof (attr_node_t)); 496 if (nodep == NULL) 497 return (B_TRUE); 498 499 (void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t)); 500 nodep->an_next = statep->cs_list; 501 statep->cs_list = nodep; 502 statep->cs_count++; 503 504 return (B_TRUE); 505 } 506 507 #define IEEE80211_C_WPA 0x01800000 508 509 static dladm_status_t 510 do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, 511 boolean_t create_ibss, void *keys, uint_t key_count, int timeout) 512 { 513 dladm_wlan_secmode_t secmode; 514 dladm_wlan_auth_t authmode; 515 dladm_wlan_bsstype_t bsstype; 516 dladm_wlan_essid_t essid; 517 boolean_t essid_valid = B_FALSE; 518 dladm_wlan_channel_t channel; 519 hrtime_t start; 520 wl_capability_t *caps; 521 522 if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) { 523 channel = attrp->wa_channel; 524 if (do_set_channel(fd, gbuf, &channel) < 0) 525 goto fail; 526 } 527 528 secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ? 529 attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE; 530 531 if (do_set_encryption(fd, gbuf, &secmode) < 0) 532 goto fail; 533 534 authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ? 535 attrp->wa_auth : DLADM_WLAN_AUTH_OPEN; 536 537 if (do_set_authmode(fd, gbuf, &authmode) < 0) 538 goto fail; 539 540 bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ? 541 attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS; 542 543 if (do_set_bsstype(fd, gbuf, &bsstype) < 0) 544 goto fail; 545 546 if (secmode == DLADM_WLAN_SECMODE_WEP) { 547 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 548 return (DLADM_STATUS_BADARG); 549 if (do_set_key(fd, gbuf, keys, key_count) < 0) 550 goto fail; 551 } else if (secmode == DLADM_WLAN_SECMODE_WPA) { 552 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 553 return (DLADM_STATUS_BADARG); 554 if (do_get_capability(fd, gbuf) < 0) 555 goto fail; 556 caps = (wl_capability_t *)(gbuf->wldp_buf); 557 if ((caps->caps & IEEE80211_C_WPA) == 0) 558 return (DLADM_STATUS_NOTSUP); 559 } 560 561 if (create_ibss) { 562 if (do_set_channel(fd, gbuf, &channel) < 0) 563 goto fail; 564 565 if (do_set_createibss(fd, gbuf, &create_ibss) < 0) 566 goto fail; 567 568 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) { 569 generate_essid(&essid); 570 essid_valid = B_TRUE; 571 } 572 } 573 574 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) { 575 essid = attrp->wa_essid; 576 essid_valid = B_TRUE; 577 } 578 579 if (!essid_valid) 580 return (DLADM_STATUS_FAILED); 581 if (do_set_essid(fd, gbuf, &essid) < 0) 582 goto fail; 583 584 /* 585 * Because wpa daemon needs getting essid from driver, 586 * we need call do_set_essid() first, then call wpa_instance_create(). 587 */ 588 if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) 589 (void) wpa_instance_create(link, keys); 590 591 start = gethrtime(); 592 for (;;) { 593 if (do_get_linkstatus(fd, gbuf) < 0) 594 goto fail; 595 596 if (IS_CONNECTED(gbuf)) 597 break; 598 599 (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE); 600 if ((timeout >= 0) && (gethrtime() - start) / 601 NANOSEC >= timeout) 602 return (DLADM_STATUS_TIMEDOUT); 603 } 604 return (DLADM_STATUS_OK); 605 fail: 606 return (dladm_wlan_wlresult2status(gbuf)); 607 } 608 609 dladm_status_t 610 dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, 611 int timeout, void *keys, uint_t key_count, uint_t flags) 612 { 613 int fd, i; 614 wldp_t *gbuf = NULL; 615 connect_state_t state = {0, NULL, NULL}; 616 attr_node_t *nodep = NULL; 617 boolean_t create_ibss, set_authmode; 618 dladm_wlan_attr_t **wl_list = NULL; 619 dladm_status_t status = DLADM_STATUS_FAILED; 620 621 if ((fd = open_link(link)) < 0) 622 return (DLADM_STATUS_LINKINVAL); 623 624 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 625 status = DLADM_STATUS_NOMEM; 626 goto done; 627 } 628 629 if (do_get_linkstatus(fd, gbuf) < 0) { 630 status = DLADM_STATUS_FAILED; 631 goto done; 632 } 633 634 if (IS_CONNECTED(gbuf)) { 635 status = DLADM_STATUS_ISCONN; 636 goto done; 637 } 638 639 set_authmode = ((attrp != NULL) && 640 (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0); 641 create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 && 642 attrp != NULL && 643 (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 644 attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS); 645 646 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 || 647 (create_ibss && attrp != NULL && 648 (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) { 649 status = do_connect(link, fd, gbuf, attrp, 650 create_ibss, keys, key_count, timeout); 651 goto done; 652 } 653 654 state.cs_attr = attrp; 655 state.cs_list = NULL; 656 state.cs_count = 0; 657 658 status = dladm_wlan_scan(link, &state, connect_cb); 659 if (status != DLADM_STATUS_OK) 660 goto done; 661 662 if (state.cs_count == 0) { 663 if (!create_ibss) { 664 status = DLADM_STATUS_NOTFOUND; 665 goto done; 666 } 667 status = do_connect(link, fd, gbuf, attrp, create_ibss, 668 keys, key_count, timeout); 669 goto done; 670 } 671 672 wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *)); 673 if (wl_list == NULL) { 674 status = DLADM_STATUS_NOMEM; 675 goto done; 676 } 677 678 nodep = state.cs_list; 679 for (i = 0; i < state.cs_count; i++) { 680 wl_list[i] = &nodep->an_attr; 681 nodep = nodep->an_next; 682 } 683 qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *), 684 attr_compare); 685 686 for (i = 0; i < state.cs_count; i++) { 687 dladm_wlan_attr_t *ap = wl_list[i]; 688 689 status = do_connect(link, fd, gbuf, ap, create_ibss, keys, 690 key_count, timeout); 691 if (status == DLADM_STATUS_OK) 692 break; 693 694 if (!set_authmode) { 695 ap->wa_auth = DLADM_WLAN_AUTH_SHARED; 696 ap->wa_valid |= DLADM_WLAN_ATTR_AUTH; 697 status = do_connect(link, fd, gbuf, ap, create_ibss, 698 keys, key_count, timeout); 699 if (status == DLADM_STATUS_OK) 700 break; 701 } 702 } 703 done: 704 if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN)) 705 (void) do_disconnect(link, fd, gbuf); 706 707 while (state.cs_list != NULL) { 708 nodep = state.cs_list; 709 state.cs_list = nodep->an_next; 710 free(nodep); 711 } 712 free(gbuf); 713 free(wl_list); 714 (void) close(fd); 715 return (status); 716 } 717 718 dladm_status_t 719 dladm_wlan_disconnect(const char *link) 720 { 721 int fd; 722 wldp_t *gbuf; 723 dladm_status_t status; 724 725 if ((fd = open_link(link)) < 0) 726 return (DLADM_STATUS_BADARG); 727 728 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 729 status = DLADM_STATUS_NOMEM; 730 goto done; 731 } 732 733 if (do_get_linkstatus(fd, gbuf) < 0) { 734 status = DLADM_STATUS_FAILED; 735 goto done; 736 } 737 738 if (!IS_CONNECTED(gbuf)) { 739 status = DLADM_STATUS_NOTCONN; 740 goto done; 741 } 742 743 if (do_disconnect(link, fd, gbuf) < 0) { 744 status = DLADM_STATUS_FAILED; 745 goto done; 746 } 747 748 if (do_get_linkstatus(fd, gbuf) < 0) { 749 status = DLADM_STATUS_FAILED; 750 goto done; 751 } 752 753 if (IS_CONNECTED(gbuf)) { 754 status = DLADM_STATUS_FAILED; 755 goto done; 756 } 757 758 status = DLADM_STATUS_OK; 759 done: 760 free(gbuf); 761 (void) close(fd); 762 return (status); 763 } 764 765 typedef struct dladm_wlan_linkname { 766 char wl_name[MAXNAMELEN]; 767 struct dladm_wlan_linkname *wl_next; 768 } dladm_wlan_linkname_t; 769 770 typedef struct dladm_wlan_walk { 771 dladm_wlan_linkname_t *ww_list; 772 dladm_status_t ww_status; 773 } dladm_wlan_walk_t; 774 775 /* ARGSUSED */ 776 static int 777 append_linkname(di_node_t node, di_minor_t minor, void *arg) 778 { 779 dladm_wlan_walk_t *statep = arg; 780 dladm_wlan_linkname_t **lastp = &statep->ww_list; 781 dladm_wlan_linkname_t *wlp = *lastp; 782 char name[MAXNAMELEN]; 783 784 (void) snprintf(name, MAXNAMELEN, "%s%d", 785 di_driver_name(node), di_instance(node)); 786 787 while (wlp != NULL) { 788 if (strcmp(wlp->wl_name, name) == 0) 789 return (DI_WALK_CONTINUE); 790 791 lastp = &wlp->wl_next; 792 wlp = wlp->wl_next; 793 } 794 if ((wlp = malloc(sizeof (*wlp))) == NULL) { 795 statep->ww_status = DLADM_STATUS_NOMEM; 796 return (DI_WALK_CONTINUE); 797 } 798 799 (void) strlcpy(wlp->wl_name, name, MAXNAMELEN); 800 wlp->wl_next = NULL; 801 *lastp = wlp; 802 803 return (DI_WALK_CONTINUE); 804 } 805 806 dladm_status_t 807 dladm_wlan_walk(void *arg, boolean_t (*func)(void *, const char *)) 808 { 809 di_node_t root; 810 dladm_wlan_walk_t state; 811 dladm_wlan_linkname_t *wlp, *wlp_next; 812 boolean_t cont = B_TRUE; 813 814 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 815 return (DLADM_STATUS_FAILED); 816 817 state.ww_list = NULL; 818 state.ww_status = DLADM_STATUS_OK; 819 (void) di_walk_minor(root, DDI_NT_NET_WIFI, DI_CHECK_ALIAS, 820 &state, append_linkname); 821 di_fini(root); 822 823 for (wlp = state.ww_list; wlp != NULL; wlp = wlp_next) { 824 /* 825 * NOTE: even if (*func)() returns B_FALSE, the loop continues 826 * since all memory must be freed. 827 */ 828 if (cont) 829 cont = (*func)(arg, wlp->wl_name); 830 wlp_next = wlp->wl_next; 831 free(wlp); 832 } 833 return (state.ww_status); 834 } 835 836 dladm_status_t 837 dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) 838 { 839 int fd; 840 wldp_t *gbuf; 841 wl_rssi_t signal; 842 wl_bss_type_t bsstype; 843 wl_authmode_t authmode; 844 wl_encryption_t encryption; 845 wl_rates_t *ratesp; 846 dladm_wlan_attr_t *wl_attrp; 847 dladm_status_t status = DLADM_STATUS_FAILED; 848 849 if (attrp == NULL) 850 return (DLADM_STATUS_BADARG); 851 852 if ((fd = open_link(link)) < 0) 853 return (DLADM_STATUS_LINKINVAL); 854 855 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 856 status = DLADM_STATUS_NOMEM; 857 goto done; 858 } 859 860 (void) memset(attrp, 0, sizeof (*attrp)); 861 wl_attrp = &attrp->la_wlan_attr; 862 863 if (do_get_linkstatus(fd, gbuf) < 0) 864 goto done; 865 866 attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS; 867 if (!IS_CONNECTED(gbuf)) { 868 attrp->la_status = DLADM_WLAN_LINKSTATUS_DISCONNECTED; 869 } else { 870 attrp->la_status = DLADM_WLAN_LINKSTATUS_CONNECTED; 871 } 872 873 if (do_get_essid(fd, gbuf) < 0) 874 goto done; 875 876 (void) strlcpy(wl_attrp->wa_essid.we_bytes, 877 ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid, 878 DLADM_WLAN_MAX_ESSID_LEN); 879 880 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 881 882 if (do_get_bssid(fd, gbuf) < 0) 883 goto done; 884 885 (void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf, 886 DLADM_WLAN_BSSID_LEN); 887 888 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 889 890 if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) { 891 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 892 status = DLADM_STATUS_OK; 893 goto done; 894 } 895 896 if (do_get_encryption(fd, gbuf) < 0) 897 goto done; 898 899 encryption = *(wl_encryption_t *)(gbuf->wldp_buf); 900 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 901 902 switch (encryption) { 903 case WL_NOENCRYPTION: 904 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE; 905 break; 906 case WL_ENC_WEP: 907 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP; 908 break; 909 case WL_ENC_WPA: 910 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 911 break; 912 default: 913 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE; 914 break; 915 } 916 917 if (do_get_signal(fd, gbuf) < 0) 918 goto done; 919 920 signal = *(wl_rssi_t *)(gbuf->wldp_buf); 921 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 922 wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal); 923 924 if (do_get_rate(fd, gbuf) < 0) 925 goto done; 926 927 ratesp = (wl_rates_t *)(gbuf->wldp_buf); 928 if (ratesp->wl_rates_num > 0) { 929 uint_t i, r = 0; 930 931 for (i = 0; i < ratesp->wl_rates_num; i++) { 932 if (ratesp->wl_rates_rates[i] > r) 933 r = ratesp->wl_rates_rates[i]; 934 } 935 wl_attrp->wa_speed = r; 936 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 937 } 938 939 if (do_get_authmode(fd, gbuf) < 0) 940 goto done; 941 942 authmode = *(wl_authmode_t *)(gbuf->wldp_buf); 943 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 944 945 switch (authmode) { 946 case WL_OPENSYSTEM: 947 wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN; 948 break; 949 case WL_SHAREDKEY: 950 wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED; 951 break; 952 default: 953 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH; 954 break; 955 } 956 957 if (do_get_bsstype(fd, gbuf) < 0) 958 goto done; 959 960 bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf); 961 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 962 963 switch (bsstype) { 964 case WL_BSS_BSS: 965 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS; 966 break; 967 case WL_BSS_IBSS: 968 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS; 969 break; 970 case WL_BSS_ANY: 971 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY; 972 break; 973 default: 974 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE; 975 break; 976 } 977 978 if (do_get_mode(fd, gbuf) < 0) 979 goto done; 980 981 wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf)); 982 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 983 if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE) 984 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 985 986 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 987 status = DLADM_STATUS_OK; 988 989 done: 990 free(gbuf); 991 (void) close(fd); 992 return (status); 993 } 994 995 boolean_t 996 dladm_wlan_is_valid(const char *link) 997 { 998 int fd = open_link(link); 999 1000 if (fd < 0) 1001 return (B_FALSE); 1002 1003 (void) close(fd); 1004 return (B_TRUE); 1005 } 1006 1007 /* ARGSUSED */ 1008 static dladm_status_t 1009 do_check_prop(int fd, wldp_t *guf, prop_desc_t *pdp, char **prop_val, 1010 uint_t val_cnt, val_desc_t **vdpp) 1011 { 1012 int i; 1013 val_desc_t *vdp; 1014 1015 if (pdp->pd_nmodval == 0) 1016 return (DLADM_STATUS_PROPRDONLY); 1017 1018 if (val_cnt != 1) 1019 return (DLADM_STATUS_BADVALCNT); 1020 1021 for (i = 0; i < pdp->pd_nmodval; i++) 1022 if (strcasecmp(*prop_val, pdp->pd_modval[i].vd_name) == 0) 1023 break; 1024 1025 if (i == pdp->pd_nmodval) 1026 return (DLADM_STATUS_BADVAL); 1027 1028 vdp = malloc(sizeof (val_desc_t)); 1029 if (vdp == NULL) 1030 return (DLADM_STATUS_NOMEM); 1031 1032 (void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t)); 1033 *vdpp = vdp; 1034 return (DLADM_STATUS_OK); 1035 } 1036 1037 static dladm_status_t 1038 do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp, 1039 char **prop_val, uint_t val_cnt) 1040 { 1041 dladm_status_t status; 1042 val_desc_t *vdp = NULL; 1043 uint_t cnt; 1044 1045 if (pdp->pd_set == NULL) 1046 return (DLADM_STATUS_PROPRDONLY); 1047 1048 if (prop_val != NULL) { 1049 status = pdp->pd_check(fd, gbuf, pdp, prop_val, 1050 val_cnt, &vdp); 1051 1052 if (status != DLADM_STATUS_OK) 1053 return (status); 1054 1055 cnt = val_cnt; 1056 } else { 1057 if (pdp->pd_defval.vd_name == NULL) 1058 return (DLADM_STATUS_NOTSUP); 1059 1060 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 1061 return (DLADM_STATUS_NOMEM); 1062 1063 *vdp = pdp->pd_defval; 1064 cnt = 1; 1065 } 1066 status = pdp->pd_set(fd, gbuf, vdp, cnt); 1067 if (status == DLADM_STATUS_OK) { 1068 /* 1069 * Some ioctls return 0 but store error code in 1070 * wldp_result. Need to fix them. 1071 */ 1072 if (gbuf->wldp_result != WL_SUCCESS) 1073 status = dladm_wlan_wlresult2status(gbuf); 1074 } 1075 free(vdp); 1076 return (status); 1077 } 1078 1079 dladm_status_t 1080 dladm_wlan_set_prop(const char *link, const char *prop_name, 1081 char **prop_val, uint_t val_cnt, char **errprop) 1082 { 1083 int fd, i; 1084 wldp_t *gbuf = NULL; 1085 boolean_t found = B_FALSE; 1086 dladm_status_t status = DLADM_STATUS_OK; 1087 1088 if ((prop_name == NULL && prop_val != NULL) || 1089 (prop_val != NULL && val_cnt == 0)) 1090 return (DLADM_STATUS_BADARG); 1091 1092 if ((fd = open_link(link)) < 0) 1093 return (DLADM_STATUS_LINKINVAL); 1094 1095 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 1096 status = DLADM_STATUS_NOMEM; 1097 goto done; 1098 } 1099 1100 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { 1101 prop_desc_t *pdp = &prop_table[i]; 1102 dladm_status_t s; 1103 1104 if (prop_name != NULL && 1105 (strcasecmp(prop_name, pdp->pd_name) != 0)) 1106 continue; 1107 1108 found = B_TRUE; 1109 s = do_set_prop(fd, gbuf, pdp, prop_val, val_cnt); 1110 1111 if (prop_name != NULL) { 1112 status = s; 1113 break; 1114 } else { 1115 if (s != DLADM_STATUS_OK && 1116 s != DLADM_STATUS_NOTSUP) { 1117 if (errprop != NULL) 1118 *errprop = pdp->pd_name; 1119 status = s; 1120 break; 1121 } 1122 } 1123 } 1124 if (!found) 1125 status = DLADM_STATUS_NOTFOUND; 1126 done: 1127 free(gbuf); 1128 (void) close(fd); 1129 return (status); 1130 } 1131 1132 /* ARGSUSED */ 1133 dladm_status_t 1134 dladm_wlan_walk_prop(const char *link, void *arg, 1135 boolean_t (*func)(void *, const char *)) 1136 { 1137 int i; 1138 1139 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { 1140 if (!func(arg, prop_table[i].pd_name)) 1141 break; 1142 } 1143 return (DLADM_STATUS_OK); 1144 } 1145 1146 dladm_status_t 1147 dladm_wlan_get_prop(const char *link, dladm_prop_type_t type, 1148 const char *prop_name, char **prop_val, uint_t *val_cnt) 1149 { 1150 int fd; 1151 int i; 1152 wldp_t *gbuf; 1153 dladm_status_t status; 1154 uint_t cnt; 1155 prop_desc_t *pdp; 1156 1157 if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0) 1158 return (DLADM_STATUS_BADARG); 1159 1160 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) 1161 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 1162 break; 1163 1164 if (i == DLADM_WLAN_MAX_PROPS) 1165 return (DLADM_STATUS_NOTFOUND); 1166 1167 if ((fd = open_link(link)) < 0) 1168 return (DLADM_STATUS_LINKINVAL); 1169 1170 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 1171 status = DLADM_STATUS_NOMEM; 1172 goto done; 1173 } 1174 pdp = &prop_table[i]; 1175 status = DLADM_STATUS_OK; 1176 1177 switch (type) { 1178 case DLADM_PROP_VAL_CURRENT: 1179 status = pdp->pd_get(fd, gbuf, prop_val, val_cnt); 1180 break; 1181 1182 case DLADM_PROP_VAL_DEFAULT: 1183 if (pdp->pd_defval.vd_name == NULL) { 1184 status = DLADM_STATUS_NOTSUP; 1185 break; 1186 } 1187 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 1188 *val_cnt = 1; 1189 break; 1190 1191 case DLADM_PROP_VAL_MODIFIABLE: 1192 if (pdp->pd_getmod != NULL) { 1193 status = pdp->pd_getmod(fd, gbuf, prop_val, val_cnt); 1194 break; 1195 } 1196 cnt = pdp->pd_nmodval; 1197 if (cnt == 0) { 1198 status = DLADM_STATUS_NOTSUP; 1199 } else if (cnt > *val_cnt) { 1200 status = DLADM_STATUS_TOOSMALL; 1201 } else { 1202 for (i = 0; i < cnt; i++) { 1203 (void) strcpy(prop_val[i], 1204 pdp->pd_modval[i].vd_name); 1205 } 1206 *val_cnt = cnt; 1207 } 1208 break; 1209 default: 1210 status = DLADM_STATUS_BADARG; 1211 break; 1212 } 1213 done: 1214 free(gbuf); 1215 (void) close(fd); 1216 return (status); 1217 } 1218 1219 static boolean_t 1220 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp) 1221 { 1222 int i; 1223 1224 for (i = 0; i < cnt; i++) { 1225 if (strcasecmp(str, vdp[i].vd_name) == 0) { 1226 *valp = vdp[i].vd_val; 1227 return (B_TRUE); 1228 } 1229 } 1230 return (B_FALSE); 1231 } 1232 1233 static boolean_t 1234 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp) 1235 { 1236 int i; 1237 1238 for (i = 0; i < cnt; i++) { 1239 if (val == vdp[i].vd_val) { 1240 *strp = vdp[i].vd_name; 1241 return (B_TRUE); 1242 } 1243 } 1244 return (B_FALSE); 1245 } 1246 1247 const char * 1248 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf) 1249 { 1250 (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes); 1251 return (buf); 1252 } 1253 1254 const char * 1255 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf) 1256 { 1257 return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN, 1258 IFT_OTHER)); 1259 } 1260 1261 static const char * 1262 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf) 1263 { 1264 char *s; 1265 1266 if (!find_name_by_val(val, vdp, cnt, &s)) 1267 s = ""; 1268 1269 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 1270 return (buf); 1271 } 1272 1273 const char * 1274 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf) 1275 { 1276 return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals, 1277 VALCNT(secmode_vals), buf)); 1278 } 1279 1280 const char * 1281 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf) 1282 { 1283 return (dladm_wlan_val2str((uint_t)*strength, strength_vals, 1284 VALCNT(strength_vals), buf)); 1285 } 1286 1287 const char * 1288 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf) 1289 { 1290 return (dladm_wlan_val2str((uint_t)*mode, mode_vals, 1291 VALCNT(mode_vals), buf)); 1292 } 1293 1294 const char * 1295 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf) 1296 { 1297 (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2, 1298 (float)(*speed) / 2); 1299 return (buf); 1300 } 1301 1302 const char * 1303 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf) 1304 { 1305 return (dladm_wlan_val2str((uint_t)*auth, auth_vals, 1306 VALCNT(auth_vals), buf)); 1307 } 1308 1309 const char * 1310 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf) 1311 { 1312 return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals, 1313 VALCNT(bsstype_vals), buf)); 1314 } 1315 1316 const char * 1317 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf) 1318 { 1319 return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals, 1320 VALCNT(linkstatus_vals), buf)); 1321 } 1322 1323 dladm_status_t 1324 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid) 1325 { 1326 if (str[0] == '\0') 1327 return (DLADM_STATUS_BADARG); 1328 1329 (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN); 1330 return (DLADM_STATUS_OK); 1331 } 1332 1333 dladm_status_t 1334 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid) 1335 { 1336 int len; 1337 uchar_t *buf; 1338 1339 buf = _link_aton(str, &len); 1340 if (buf == NULL) 1341 return (DLADM_STATUS_BADARG); 1342 1343 if (len != DLADM_WLAN_BSSID_LEN) { 1344 free(buf); 1345 return (DLADM_STATUS_BADARG); 1346 } 1347 1348 (void) memcpy(bssid->wb_bytes, buf, len); 1349 free(buf); 1350 return (DLADM_STATUS_OK); 1351 } 1352 1353 dladm_status_t 1354 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode) 1355 { 1356 uint_t val; 1357 1358 if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val)) 1359 return (DLADM_STATUS_BADARG); 1360 1361 *secmode = (dladm_wlan_secmode_t)val; 1362 return (DLADM_STATUS_OK); 1363 } 1364 1365 dladm_status_t 1366 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength) 1367 { 1368 uint_t val; 1369 1370 if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val)) 1371 return (DLADM_STATUS_BADARG); 1372 1373 *strength = (dladm_wlan_strength_t)val; 1374 return (DLADM_STATUS_OK); 1375 } 1376 1377 dladm_status_t 1378 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode) 1379 { 1380 uint_t val; 1381 1382 if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val)) 1383 return (DLADM_STATUS_BADARG); 1384 1385 *mode = (dladm_wlan_mode_t)val; 1386 return (DLADM_STATUS_OK); 1387 } 1388 1389 dladm_status_t 1390 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed) 1391 { 1392 *speed = (dladm_wlan_speed_t)(atof(str) * 2); 1393 return (DLADM_STATUS_OK); 1394 } 1395 1396 dladm_status_t 1397 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth) 1398 { 1399 uint_t val; 1400 1401 if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val)) 1402 return (DLADM_STATUS_BADARG); 1403 1404 *auth = (dladm_wlan_auth_t)val; 1405 return (DLADM_STATUS_OK); 1406 } 1407 1408 dladm_status_t 1409 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype) 1410 { 1411 uint_t val; 1412 1413 if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val)) 1414 return (DLADM_STATUS_BADARG); 1415 1416 *bsstype = (dladm_wlan_bsstype_t)val; 1417 return (DLADM_STATUS_OK); 1418 } 1419 1420 dladm_status_t 1421 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus) 1422 { 1423 uint_t val; 1424 1425 if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals), 1426 &val)) 1427 return (DLADM_STATUS_BADARG); 1428 1429 *linkstatus = (dladm_wlan_linkstatus_t)val; 1430 return (DLADM_STATUS_OK); 1431 } 1432 1433 static int 1434 do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) 1435 { 1436 int rc; 1437 struct strioctl stri; 1438 1439 gbuf->wldp_type = NET_802_11; 1440 gbuf->wldp_id = id; 1441 gbuf->wldp_length = len; 1442 1443 stri.ic_timout = 0; 1444 stri.ic_dp = (char *)gbuf; 1445 stri.ic_cmd = cmd; 1446 stri.ic_len = cmdlen; 1447 1448 if ((rc = ioctl(fd, I_STR, &stri)) != 0) { 1449 if (rc > 0) 1450 errno = rc; 1451 return (-1); 1452 } 1453 return (0); 1454 } 1455 1456 static int 1457 do_get_ioctl(int fd, wldp_t *gbuf, uint_t id) 1458 { 1459 (void) memset(gbuf, 0, MAX_BUF_LEN); 1460 return (do_ioctl(fd, gbuf, id, MAX_BUF_LEN, WLAN_GET_PARAM, 1461 MAX_BUF_LEN)); 1462 } 1463 1464 static int 1465 do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen) 1466 { 1467 (void) memset(gbuf, 0, MAX_BUF_LEN); 1468 (void) memcpy(gbuf->wldp_buf, buf, buflen); 1469 buflen += WIFI_BUF_OFFSET; 1470 return (do_ioctl(fd, gbuf, id, buflen, WLAN_SET_PARAM, buflen)); 1471 } 1472 1473 static int 1474 do_cmd_ioctl(int fd, wldp_t *gbuf, uint_t cmd) 1475 { 1476 (void) memset(gbuf, 0, MAX_BUF_LEN); 1477 return (do_ioctl(fd, gbuf, cmd, sizeof (wldp_t), WLAN_COMMAND, 1478 sizeof (wldp_t))); 1479 } 1480 1481 static int 1482 do_scan(int fd, wldp_t *gbuf) 1483 { 1484 return (do_cmd_ioctl(fd, gbuf, WL_SCAN)); 1485 } 1486 1487 static int 1488 do_disconnect(const char *link, int fd, wldp_t *gbuf) 1489 { 1490 if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf-> 1491 wldp_buf))->wpa_flag > 0) 1492 (void) wpa_instance_delete(link); 1493 1494 return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE)); 1495 } 1496 1497 static int 1498 do_get_esslist(int fd, wldp_t *gbuf) 1499 { 1500 (void) memset(gbuf, 0, MAX_BUF_LEN); 1501 return (do_ioctl(fd, gbuf, WL_ESS_LIST, MAX_BUF_LEN, 1502 WLAN_GET_PARAM, sizeof (wldp_t))); 1503 } 1504 1505 static int 1506 do_get_bssid(int fd, wldp_t *gbuf) 1507 { 1508 return (do_get_ioctl(fd, gbuf, WL_BSSID)); 1509 } 1510 1511 static int 1512 do_get_essid(int fd, wldp_t *gbuf) 1513 { 1514 return (do_get_ioctl(fd, gbuf, WL_ESSID)); 1515 } 1516 1517 static int 1518 do_get_bsstype(int fd, wldp_t *gbuf) 1519 { 1520 return (do_get_ioctl(fd, gbuf, WL_BSS_TYPE)); 1521 } 1522 1523 static int 1524 do_get_linkstatus(int fd, wldp_t *gbuf) 1525 { 1526 return (do_get_ioctl(fd, gbuf, WL_LINKSTATUS)); 1527 } 1528 1529 static int 1530 do_get_rate(int fd, wldp_t *gbuf) 1531 { 1532 return (do_get_ioctl(fd, gbuf, WL_DESIRED_RATES)); 1533 } 1534 1535 static int 1536 do_get_phyconf(int fd, wldp_t *gbuf) 1537 { 1538 return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); 1539 } 1540 1541 static int 1542 do_get_powermode(int fd, wldp_t *gbuf) 1543 { 1544 return (do_get_ioctl(fd, gbuf, WL_POWER_MODE)); 1545 } 1546 1547 static int 1548 do_get_radio(int fd, wldp_t *gbuf) 1549 { 1550 return (do_get_ioctl(fd, gbuf, WL_RADIO)); 1551 } 1552 1553 static int 1554 do_get_authmode(int fd, wldp_t *gbuf) 1555 { 1556 return (do_get_ioctl(fd, gbuf, WL_AUTH_MODE)); 1557 } 1558 1559 static int 1560 do_get_encryption(int fd, wldp_t *gbuf) 1561 { 1562 return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION)); 1563 } 1564 1565 static int 1566 do_get_signal(int fd, wldp_t *gbuf) 1567 { 1568 return (do_get_ioctl(fd, gbuf, WL_RSSI)); 1569 } 1570 1571 static int 1572 do_get_mode(int fd, wldp_t *gbuf) 1573 { 1574 return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); 1575 } 1576 1577 static dladm_status_t 1578 do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1579 { 1580 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 1581 uint_t cnt = wrp->wl_rates_num; 1582 uint_t i; 1583 1584 if (cnt > *val_cnt) 1585 return (DLADM_STATUS_TOOSMALL); 1586 if (wrp->wl_rates_rates[0] == 0) { 1587 prop_val[0][0] = '\0'; 1588 *val_cnt = 1; 1589 return (DLADM_STATUS_OK); 1590 } 1591 1592 for (i = 0; i < cnt; i++) { 1593 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1594 wrp->wl_rates_rates[i] % 2, 1595 (float)wrp->wl_rates_rates[i] / 2); 1596 } 1597 *val_cnt = cnt; 1598 return (DLADM_STATUS_OK); 1599 } 1600 1601 static dladm_status_t 1602 do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1603 { 1604 if (do_get_rate(fd, gbuf) < 0) 1605 return (dladm_wlan_wlresult2status(gbuf)); 1606 1607 return (do_get_rate_common(gbuf, prop_val, val_cnt)); 1608 } 1609 1610 static dladm_status_t 1611 do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1612 { 1613 if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0) 1614 return (DLADM_STATUS_FAILED); 1615 1616 return (do_get_rate_common(gbuf, prop_val, val_cnt)); 1617 } 1618 1619 static dladm_status_t 1620 do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1621 { 1622 uint32_t channel; 1623 1624 if (do_get_phyconf(fd, gbuf) < 0) 1625 return (dladm_wlan_wlresult2status(gbuf)); 1626 1627 if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel)) 1628 return (DLADM_STATUS_NOTFOUND); 1629 1630 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1631 *val_cnt = 1; 1632 1633 return (DLADM_STATUS_OK); 1634 } 1635 1636 static dladm_status_t 1637 do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1638 { 1639 wl_ps_mode_t *mode; 1640 const char *s; 1641 1642 if (do_get_powermode(fd, gbuf) < 0) 1643 return (dladm_wlan_wlresult2status(gbuf)); 1644 1645 mode = (wl_ps_mode_t *)(gbuf->wldp_buf); 1646 switch (mode->wl_ps_mode) { 1647 case WL_PM_AM: 1648 s = "off"; 1649 break; 1650 case WL_PM_MPS: 1651 s = "max"; 1652 break; 1653 case WL_PM_FAST: 1654 s = "fast"; 1655 break; 1656 default: 1657 return (DLADM_STATUS_NOTFOUND); 1658 } 1659 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1660 *val_cnt = 1; 1661 1662 return (DLADM_STATUS_OK); 1663 } 1664 1665 static dladm_status_t 1666 do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1667 { 1668 wl_radio_t radio; 1669 const char *s; 1670 1671 if (do_get_radio(fd, gbuf) < 0) 1672 return (dladm_wlan_wlresult2status(gbuf)); 1673 1674 radio = *(wl_radio_t *)(gbuf->wldp_buf); 1675 switch (radio) { 1676 case B_TRUE: 1677 s = "on"; 1678 break; 1679 case B_FALSE: 1680 s = "off"; 1681 break; 1682 default: 1683 return (DLADM_STATUS_NOTFOUND); 1684 } 1685 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1686 *val_cnt = 1; 1687 1688 return (DLADM_STATUS_OK); 1689 } 1690 1691 static int 1692 do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) 1693 { 1694 wl_bss_type_t ibsstype; 1695 1696 switch (*bsstype) { 1697 case DLADM_WLAN_BSSTYPE_BSS: 1698 ibsstype = WL_BSS_BSS; 1699 break; 1700 case DLADM_WLAN_BSSTYPE_IBSS: 1701 ibsstype = WL_BSS_IBSS; 1702 break; 1703 default: 1704 ibsstype = WL_BSS_ANY; 1705 break; 1706 } 1707 return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype, 1708 sizeof (ibsstype))); 1709 } 1710 1711 static int 1712 do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) 1713 { 1714 wl_authmode_t auth_mode; 1715 1716 switch (*auth) { 1717 case DLADM_WLAN_AUTH_OPEN: 1718 auth_mode = WL_OPENSYSTEM; 1719 break; 1720 case DLADM_WLAN_AUTH_SHARED: 1721 auth_mode = WL_SHAREDKEY; 1722 break; 1723 default: 1724 return (-1); 1725 } 1726 return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode, 1727 sizeof (auth_mode))); 1728 } 1729 1730 static int 1731 do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) 1732 { 1733 wl_encryption_t encryption; 1734 1735 switch (*secmode) { 1736 case DLADM_WLAN_SECMODE_NONE: 1737 encryption = WL_NOENCRYPTION; 1738 break; 1739 case DLADM_WLAN_SECMODE_WEP: 1740 encryption = WL_ENC_WEP; 1741 break; 1742 case DLADM_WLAN_SECMODE_WPA: 1743 return (0); 1744 default: 1745 return (-1); 1746 } 1747 return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption, 1748 sizeof (encryption))); 1749 } 1750 1751 static int 1752 do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, 1753 uint_t key_count) 1754 { 1755 int i; 1756 wl_wep_key_t *wkp; 1757 wl_wep_key_tab_t wepkey_tab; 1758 dladm_wlan_key_t *kp; 1759 1760 if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL) 1761 return (-1); 1762 1763 (void) memset(wepkey_tab, 0, sizeof (wepkey_tab)); 1764 for (i = 0; i < MAX_NWEPKEYS; i++) 1765 wepkey_tab[i].wl_wep_operation = WL_NUL; 1766 1767 for (i = 0; i < key_count; i++) { 1768 kp = &keys[i]; 1769 if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS) 1770 return (-1); 1771 if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN && 1772 kp->wk_len != DLADM_WLAN_WEPKEY128_LEN) 1773 return (-1); 1774 1775 wkp = &wepkey_tab[kp->wk_idx - 1]; 1776 wkp->wl_wep_operation = WL_ADD; 1777 wkp->wl_wep_length = kp->wk_len; 1778 (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len); 1779 } 1780 1781 return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab, 1782 sizeof (wepkey_tab))); 1783 } 1784 1785 static int 1786 do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) 1787 { 1788 wl_essid_t iessid; 1789 1790 (void) memset(&iessid, 0, sizeof (essid)); 1791 1792 if (essid != NULL && essid->we_bytes[0] != '\0') { 1793 iessid.wl_essid_length = strlen(essid->we_bytes); 1794 (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes, 1795 sizeof (iessid.wl_essid_essid)); 1796 } else { 1797 return (-1); 1798 } 1799 return (do_set_ioctl(fd, gbuf, WL_ESSID, &iessid, sizeof (iessid))); 1800 } 1801 1802 /* ARGSUSED */ 1803 static dladm_status_t 1804 do_check_rate(int fd, wldp_t *gbuf, prop_desc_t *pdp, char **prop_val, 1805 uint_t val_cnt, val_desc_t **vdpp) 1806 { 1807 int i; 1808 uint_t modval_cnt = MAX_SUPPORT_RATES; 1809 char *buf, **modval; 1810 dladm_status_t status; 1811 val_desc_t *vdp = NULL; 1812 1813 if (val_cnt != 1) 1814 return (DLADM_STATUS_BADVALCNT); 1815 1816 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * MAX_SUPPORT_RATES); 1817 if (buf == NULL) 1818 goto done; 1819 1820 modval = (char **)(void *)buf; 1821 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1822 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1823 i * DLADM_STRSIZE; 1824 } 1825 1826 status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt); 1827 if (status != DLADM_STATUS_OK) 1828 goto done; 1829 1830 vdp = malloc(sizeof (val_desc_t)); 1831 if (vdp == NULL) { 1832 status = DLADM_STATUS_NOMEM; 1833 goto done; 1834 } 1835 1836 for (i = 0; i < modval_cnt; i++) { 1837 if (strcasecmp(*prop_val, modval[i]) == 0) { 1838 vdp->vd_val = (uint_t)(atof(*prop_val) * 2); 1839 status = DLADM_STATUS_OK; 1840 *vdpp = vdp; 1841 vdp = NULL; 1842 break; 1843 } 1844 } 1845 if (i == modval_cnt) 1846 status = DLADM_STATUS_BADVAL; 1847 done: 1848 free(buf); 1849 free(vdp); 1850 return (status); 1851 } 1852 1853 static dladm_status_t 1854 do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 1855 { 1856 dladm_wlan_rates_t rates; 1857 1858 if (val_cnt != 1) 1859 return (DLADM_STATUS_BADVALCNT); 1860 1861 rates.wr_cnt = 1; 1862 rates.wr_rates[0] = vdp[0].vd_val; 1863 1864 if (do_set_rate(fd, gbuf, &rates) < 0) 1865 return (dladm_wlan_wlresult2status(gbuf)); 1866 1867 return (DLADM_STATUS_OK); 1868 } 1869 1870 static int 1871 do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates) 1872 { 1873 int i; 1874 uint_t len; 1875 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 1876 1877 (void) memset(gbuf, 0, MAX_BUF_LEN); 1878 1879 for (i = 0; i < rates->wr_cnt; i++) 1880 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1881 wrp->wl_rates_num = rates->wr_cnt; 1882 1883 len = offsetof(wl_rates_t, wl_rates_rates) + 1884 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1885 return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len)); 1886 } 1887 1888 /* ARGSUSED */ 1889 static dladm_status_t 1890 do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 1891 { 1892 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1893 1894 if (do_set_powermode(fd, gbuf, &powermode) < 0) 1895 return (dladm_wlan_wlresult2status(gbuf)); 1896 1897 return (DLADM_STATUS_OK); 1898 } 1899 1900 static int 1901 do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm) 1902 { 1903 wl_ps_mode_t ps_mode; 1904 1905 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1906 1907 switch (*pm) { 1908 case DLADM_WLAN_PM_OFF: 1909 ps_mode.wl_ps_mode = WL_PM_AM; 1910 break; 1911 case DLADM_WLAN_PM_MAX: 1912 ps_mode.wl_ps_mode = WL_PM_MPS; 1913 break; 1914 case DLADM_WLAN_PM_FAST: 1915 ps_mode.wl_ps_mode = WL_PM_FAST; 1916 break; 1917 default: 1918 return (-1); 1919 } 1920 return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode, 1921 sizeof (ps_mode))); 1922 } 1923 1924 /* ARGSUSED */ 1925 static dladm_status_t 1926 do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 1927 { 1928 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 1929 1930 if (do_set_radio(fd, gbuf, &radio) < 0) 1931 return (dladm_wlan_wlresult2status(gbuf)); 1932 1933 return (DLADM_STATUS_OK); 1934 } 1935 1936 static int 1937 do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio) 1938 { 1939 wl_radio_t r; 1940 1941 switch (*radio) { 1942 case DLADM_WLAN_RADIO_ON: 1943 r = B_TRUE; 1944 break; 1945 case DLADM_WLAN_RADIO_OFF: 1946 r = B_FALSE; 1947 break; 1948 default: 1949 return (-1); 1950 } 1951 return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r))); 1952 } 1953 1954 static int 1955 do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel) 1956 { 1957 wl_phy_conf_t phy_conf; 1958 1959 if (*channel > MAX_CHANNEL_NUM) 1960 return (-1); 1961 1962 (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); 1963 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; 1964 1965 return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf, 1966 sizeof (phy_conf))); 1967 } 1968 1969 static int 1970 do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss) 1971 { 1972 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); 1973 1974 return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr))); 1975 } 1976 1977 static void 1978 generate_essid(dladm_wlan_essid_t *essid) 1979 { 1980 srandom(gethrtime()); 1981 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d", 1982 random()); 1983 } 1984 1985 static int 1986 do_get_capability(int fd, wldp_t *gbuf) 1987 { 1988 return (do_get_ioctl(fd, gbuf, WL_CAPABILITY)); 1989 } 1990 1991 static int 1992 do_get_wpamode(int fd, wldp_t *gbuf) 1993 { 1994 return (do_get_ioctl(fd, gbuf, WL_WPA)); 1995 } 1996 1997 static dladm_status_t 1998 ioctl_get(const char *link, int id, void *gbuf) 1999 { 2000 int fd; 2001 2002 if ((fd = open_link(link)) < 0) 2003 return (DLADM_STATUS_LINKINVAL); 2004 (void) do_get_ioctl(fd, gbuf, id); 2005 2006 (void) close(fd); 2007 return (dladm_wlan_wlresult2status(gbuf)); 2008 } 2009 2010 static dladm_status_t 2011 ioctl_set(const char *link, int id, void *buf, uint_t buflen) 2012 { 2013 int fd; 2014 wldp_t *gbuf; 2015 dladm_status_t status; 2016 2017 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2018 return (DLADM_STATUS_NOMEM); 2019 2020 if ((fd = open_link(link)) < 0) 2021 return (DLADM_STATUS_LINKINVAL); 2022 (void) do_set_ioctl(fd, gbuf, id, buf, buflen); 2023 2024 (void) close(fd); 2025 status = dladm_wlan_wlresult2status(gbuf); 2026 free(gbuf); 2027 2028 return (status); 2029 } 2030 2031 dladm_status_t 2032 dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, 2033 uint_t *estot) 2034 { 2035 int i, n; 2036 wldp_t *gbuf; 2037 wl_wpa_ess_t *es; 2038 dladm_status_t status; 2039 2040 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2041 return (DLADM_STATUS_NOMEM); 2042 2043 status = ioctl_get(link, WL_SCANRESULTS, gbuf); 2044 2045 if (status == DLADM_STATUS_OK) { 2046 es = (wl_wpa_ess_t *)(gbuf->wldp_buf); 2047 n = (es->count > escnt) ? escnt : es->count; 2048 for (i = 0; i < n; i ++) { 2049 (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid, 2050 DLADM_WLAN_BSSID_LEN); 2051 sr[i].we_ssid_len = es->ess[i].ssid_len; 2052 (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid, 2053 es->ess[i].ssid_len); 2054 sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len; 2055 (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie, 2056 es->ess[i].wpa_ie_len); 2057 sr[i].we_freq = es->ess[i].freq; 2058 } 2059 *estot = n; 2060 } 2061 2062 free(gbuf); 2063 return (status); 2064 } 2065 2066 dladm_status_t 2067 dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, 2068 uint_t wpa_ie_len) 2069 { 2070 wl_wpa_ie_t *ie; 2071 uint_t len; 2072 dladm_status_t status; 2073 2074 if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN) 2075 return (DLADM_STATUS_BADARG); 2076 len = sizeof (wl_wpa_ie_t) + wpa_ie_len; 2077 ie = malloc(len); 2078 if (ie == NULL) 2079 return (DLADM_STATUS_NOMEM); 2080 2081 (void) memset(ie, 0, len); 2082 ie->wpa_ie_len = wpa_ie_len; 2083 (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); 2084 2085 status = ioctl_set(link, WL_SETOPTIE, ie, len); 2086 free(ie); 2087 2088 return (status); 2089 } 2090 2091 dladm_status_t 2092 dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag) 2093 { 2094 wl_wpa_t wpa; 2095 2096 wpa.wpa_flag = flag; 2097 return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t))); 2098 } 2099 2100 dladm_status_t 2101 dladm_wlan_wpa_del_key(const char *link, uint_t key_idx, 2102 const dladm_wlan_bssid_t *addr) 2103 { 2104 wl_del_key_t wk; 2105 2106 wk.idk_keyix = key_idx; 2107 if (addr != NULL) 2108 (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, 2109 DLADM_WLAN_BSSID_LEN); 2110 2111 return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t))); 2112 } 2113 2114 dladm_status_t 2115 dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, 2116 const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, 2117 uint_t key_idx, uint8_t *key, uint_t key_len) 2118 { 2119 wl_key_t wk; 2120 2121 (void) memset(&wk, 0, sizeof (wl_key_t)); 2122 switch (cipher) { 2123 case DLADM_WLAN_CIPHER_WEP: 2124 wk.ik_type = IEEE80211_CIPHER_WEP; 2125 break; 2126 case DLADM_WLAN_CIPHER_TKIP: 2127 wk.ik_type = IEEE80211_CIPHER_TKIP; 2128 break; 2129 case DLADM_WLAN_CIPHER_AES_OCB: 2130 wk.ik_type = IEEE80211_CIPHER_AES_OCB; 2131 break; 2132 case DLADM_WLAN_CIPHER_AES_CCM: 2133 wk.ik_type = IEEE80211_CIPHER_AES_CCM; 2134 break; 2135 case DLADM_WLAN_CIPHER_CKIP: 2136 wk.ik_type = IEEE80211_CIPHER_CKIP; 2137 break; 2138 case DLADM_WLAN_CIPHER_NONE: 2139 wk.ik_type = IEEE80211_CIPHER_NONE; 2140 break; 2141 default: 2142 return (DLADM_STATUS_BADARG); 2143 } 2144 wk.ik_flags = IEEE80211_KEY_RECV; 2145 if (set_tx) { 2146 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; 2147 (void) memcpy(wk.ik_macaddr, addr->wb_bytes, 2148 DLADM_WLAN_BSSID_LEN); 2149 } else 2150 (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN); 2151 wk.ik_keyix = key_idx; 2152 wk.ik_keylen = key_len; 2153 (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ 2154 (void) memcpy(wk.ik_keydata, key, key_len); 2155 2156 return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t))); 2157 } 2158 2159 dladm_status_t 2160 dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, 2161 dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) 2162 { 2163 wl_mlme_t mlme; 2164 2165 (void) memset(&mlme, 0, sizeof (wl_mlme_t)); 2166 switch (op) { 2167 case DLADM_WLAN_MLME_ASSOC: 2168 mlme.im_op = IEEE80211_MLME_ASSOC; 2169 break; 2170 case DLADM_WLAN_MLME_DISASSOC: 2171 mlme.im_op = IEEE80211_MLME_DISASSOC; 2172 break; 2173 default: 2174 return (DLADM_STATUS_BADARG); 2175 } 2176 mlme.im_reason = reason; 2177 if (bssid != NULL) 2178 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, 2179 DLADM_WLAN_BSSID_LEN); 2180 2181 return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t))); 2182 } 2183 2184 /* 2185 * routines of create instance 2186 */ 2187 static scf_propertygroup_t * 2188 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, 2189 const char *pg_name, const char *pg_type) 2190 { 2191 scf_propertygroup_t *pg; 2192 2193 pg = scf_pg_create(handle); 2194 if (pg == NULL) 2195 return (NULL); 2196 2197 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) { 2198 scf_pg_destroy(pg); 2199 return (NULL); 2200 } 2201 2202 return (pg); 2203 } 2204 2205 static int 2206 add_new_property(scf_handle_t *handle, const char *prop_name, 2207 scf_type_t type, const char *val, scf_transaction_t *tx) 2208 { 2209 scf_value_t *value = NULL; 2210 scf_transaction_entry_t *entry = NULL; 2211 2212 entry = scf_entry_create(handle); 2213 if (entry == NULL) 2214 goto out; 2215 2216 value = scf_value_create(handle); 2217 if (value == NULL) 2218 goto out; 2219 2220 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) 2221 goto out; 2222 2223 if (scf_value_set_from_string(value, type, val) != 0) 2224 goto out; 2225 2226 if (scf_entry_add_value(entry, value) != 0) 2227 goto out; 2228 2229 return (DLADM_WLAN_SVC_SUCCESS); 2230 2231 out: 2232 if (value != NULL) 2233 scf_value_destroy(value); 2234 if (entry != NULL) 2235 scf_entry_destroy(entry); 2236 2237 return (DLADM_WLAN_SVC_FAILURE); 2238 } 2239 2240 /* 2241 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 2242 */ 2243 static int 2244 add_pg_method(scf_handle_t *handle, scf_instance_t *instance, 2245 const char *pg_name, const char *flags) 2246 { 2247 int rv, size; 2248 int status = DLADM_WLAN_SVC_FAILURE; 2249 char *command = NULL; 2250 scf_transaction_t *tran = NULL; 2251 scf_propertygroup_t *pg; 2252 2253 pg = add_property_group_to_instance(handle, instance, 2254 pg_name, SCF_GROUP_METHOD); 2255 if (pg == NULL) 2256 goto out; 2257 2258 tran = scf_transaction_create(handle); 2259 if (tran == NULL) 2260 goto out; 2261 2262 size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; 2263 command = malloc(size); 2264 if (command == NULL) { 2265 status = DLADM_WLAN_SVC_APP_FAILURE; 2266 goto out; 2267 } 2268 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); 2269 2270 do { 2271 if (scf_transaction_start(tran, pg) != 0) 2272 goto out; 2273 2274 if (add_new_property(handle, SCF_PROPERTY_EXEC, 2275 SCF_TYPE_ASTRING, command, tran) != 2276 DLADM_WLAN_SVC_SUCCESS) { 2277 goto out; 2278 } 2279 2280 rv = scf_transaction_commit(tran); 2281 switch (rv) { 2282 case 1: 2283 status = DLADM_WLAN_SVC_SUCCESS; 2284 goto out; 2285 case 0: 2286 scf_transaction_destroy_children(tran); 2287 if (scf_pg_update(pg) == -1) { 2288 goto out; 2289 } 2290 break; 2291 case -1: 2292 default: 2293 goto out; 2294 } 2295 } while (rv == 0); 2296 2297 out: 2298 if (tran != NULL) { 2299 scf_transaction_destroy_children(tran); 2300 scf_transaction_destroy(tran); 2301 } 2302 2303 if (pg != NULL) 2304 scf_pg_destroy(pg); 2305 2306 if (command != NULL) 2307 free(command); 2308 2309 return (status); 2310 } 2311 2312 static int 2313 do_create_instance(scf_handle_t *handle, scf_service_t *svc, 2314 const char *instance_name, const char *command) 2315 { 2316 int status = DLADM_WLAN_SVC_FAILURE; 2317 char *buf; 2318 ssize_t max_fmri_len; 2319 scf_instance_t *instance; 2320 2321 instance = scf_instance_create(handle); 2322 if (instance == NULL) 2323 goto out; 2324 2325 if (scf_service_add_instance(svc, instance_name, instance) != 0) { 2326 if (scf_error() == SCF_ERROR_EXISTS) 2327 /* Let the caller deal with the duplicate instance */ 2328 status = DLADM_WLAN_SVC_INSTANCE_EXISTS; 2329 goto out; 2330 } 2331 2332 if (add_pg_method(handle, instance, "start", 2333 command) != DLADM_WLAN_SVC_SUCCESS) { 2334 goto out; 2335 } 2336 2337 /* enabling the instance */ 2338 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 2339 if ((buf = malloc(max_fmri_len + 1)) == NULL) 2340 goto out; 2341 2342 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 2343 if ((smf_disable_instance(buf, 0) != 0) || 2344 (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { 2345 goto out; 2346 } 2347 status = DLADM_WLAN_SVC_SUCCESS; 2348 } 2349 2350 out: 2351 if (instance != NULL) 2352 scf_instance_destroy(instance); 2353 return (status); 2354 } 2355 2356 static int 2357 create_instance(const char *instance_name, const char *command) 2358 { 2359 int status = DLADM_WLAN_SVC_FAILURE; 2360 scf_service_t *svc = NULL; 2361 scf_handle_t *handle = NULL; 2362 2363 handle = scf_handle_create(SCF_VERSION); 2364 if (handle == NULL) 2365 goto out; 2366 2367 if (scf_handle_bind(handle) == -1) 2368 goto out; 2369 2370 if ((svc = scf_service_create(handle)) == NULL) 2371 goto out; 2372 2373 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc, 2374 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 2375 goto out; 2376 2377 status = do_create_instance(handle, svc, instance_name, command); 2378 2379 out: 2380 if (svc != NULL) 2381 scf_service_destroy(svc); 2382 2383 if (handle != NULL) { 2384 (void) scf_handle_unbind(handle); 2385 scf_handle_destroy(handle); 2386 } 2387 2388 return (status); 2389 } 2390 2391 /* 2392 * routines of delete instance 2393 */ 2394 #define DEFAULT_TIMEOUT 60000000 2395 #define INIT_WAIT_USECS 50000 2396 2397 static void 2398 wait_until_disabled(scf_handle_t *handle, char *fmri) 2399 { 2400 char *state; 2401 useconds_t max; 2402 useconds_t usecs; 2403 uint64_t *cp = NULL; 2404 scf_simple_prop_t *sp = NULL; 2405 2406 max = DEFAULT_TIMEOUT; 2407 2408 if (((sp = scf_simple_prop_get(handle, fmri, "stop", 2409 SCF_PROPERTY_TIMEOUT)) != NULL) && 2410 ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0)) 2411 max = (*cp) * 1000000; /* convert to usecs */ 2412 2413 if (sp != NULL) 2414 scf_simple_prop_free(sp); 2415 2416 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) { 2417 /* incremental wait */ 2418 usecs *= 2; 2419 usecs = (usecs > max) ? max : usecs; 2420 2421 (void) usleep(usecs); 2422 2423 /* Check state after the wait */ 2424 if ((state = smf_get_state(fmri)) != NULL) { 2425 if (strcmp(state, "disabled") == 0) 2426 return; 2427 } 2428 } 2429 } 2430 2431 static int 2432 delete_instance(const char *instance_name) 2433 { 2434 int status = DLADM_WLAN_SVC_FAILURE; 2435 char *buf; 2436 ssize_t max_fmri_len; 2437 scf_scope_t *scope = NULL; 2438 scf_service_t *svc = NULL; 2439 scf_handle_t *handle = NULL; 2440 scf_instance_t *instance; 2441 2442 handle = scf_handle_create(SCF_VERSION); 2443 if (handle == NULL) 2444 goto out; 2445 2446 if (scf_handle_bind(handle) == -1) 2447 goto out; 2448 2449 if ((scope = scf_scope_create(handle)) == NULL) 2450 goto out; 2451 2452 if ((svc = scf_service_create(handle)) == NULL) 2453 goto out; 2454 2455 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1) 2456 goto out; 2457 2458 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0) 2459 goto out; 2460 2461 instance = scf_instance_create(handle); 2462 if (instance == NULL) 2463 goto out; 2464 2465 if (scf_service_get_instance(svc, instance_name, instance) != 0) { 2466 scf_error_t scf_errnum = scf_error(); 2467 2468 if (scf_errnum == SCF_ERROR_NOT_FOUND) 2469 status = DLADM_WLAN_SVC_SUCCESS; 2470 2471 scf_instance_destroy(instance); 2472 goto out; 2473 } 2474 2475 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 2476 if ((buf = malloc(max_fmri_len + 1)) == NULL) { 2477 scf_instance_destroy(instance); 2478 goto out; 2479 } 2480 2481 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 2482 char *state; 2483 2484 state = smf_get_state(buf); 2485 if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 || 2486 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) { 2487 if (smf_disable_instance(buf, 0) == 0) { 2488 /* 2489 * Wait for some time till timeout to avoid 2490 * a race with scf_instance_delete() below. 2491 */ 2492 wait_until_disabled(handle, buf); 2493 } 2494 } 2495 } 2496 2497 if (scf_instance_delete(instance) != 0) { 2498 scf_instance_destroy(instance); 2499 goto out; 2500 } 2501 2502 scf_instance_destroy(instance); 2503 2504 status = DLADM_WLAN_SVC_SUCCESS; 2505 2506 out: 2507 if (svc != NULL) 2508 scf_service_destroy(svc); 2509 2510 if (scope != NULL) 2511 scf_scope_destroy(scope); 2512 2513 if (handle != NULL) { 2514 (void) scf_handle_unbind(handle); 2515 scf_handle_destroy(handle); 2516 } 2517 2518 return (status); 2519 } 2520 2521 /* 2522 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 2523 */ 2524 static int 2525 wpa_instance_create(const char *instance_name, void *key) 2526 { 2527 int status = DLADM_WLAN_SVC_FAILURE; 2528 char *command = NULL; 2529 char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; 2530 int size; 2531 2532 size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; 2533 command = malloc(size); 2534 if (command == NULL) { 2535 status = DLADM_WLAN_SVC_APP_FAILURE; 2536 goto out; 2537 } 2538 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); 2539 2540 status = create_instance(instance_name, command); 2541 if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) { 2542 /* 2543 * Delete the existing instance and create a new instance 2544 * with the supplied arguments. 2545 */ 2546 if ((status = delete_instance(instance_name)) == 2547 DLADM_WLAN_SVC_SUCCESS) { 2548 status = create_instance(instance_name, command); 2549 } 2550 } 2551 2552 out: 2553 if (command != NULL) 2554 free(command); 2555 2556 return (status); 2557 } 2558 2559 static int 2560 wpa_instance_delete(const char *instance_name) 2561 { 2562 int status; 2563 2564 status = delete_instance(instance_name); 2565 2566 return (status); 2567 } 2568