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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <libintl.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <fcntl.h> 31 #include <stddef.h> 32 #include <string.h> 33 #include <stropts.h> 34 #include <libdevinfo.h> 35 #include <net/if.h> 36 #include <net/if_dl.h> 37 #include <net/if_types.h> 38 #include <libdlpi.h> 39 #include <libdllink.h> 40 #include <libscf.h> 41 #include <libdlwlan.h> 42 #include <libdladm_impl.h> 43 #include <libdlwlan_impl.h> 44 #include <net/wpa.h> 45 46 static dladm_status_t wpa_instance_create(datalink_id_t, void *); 47 static dladm_status_t wpa_instance_delete(datalink_id_t); 48 49 static dladm_status_t do_get_bsstype(datalink_id_t, void *, int); 50 static dladm_status_t do_get_essid(datalink_id_t, void *, int); 51 static dladm_status_t do_get_bssid(datalink_id_t, void *, int); 52 static dladm_status_t do_get_signal(datalink_id_t, void *, int); 53 static dladm_status_t do_get_encryption(datalink_id_t, void *, int); 54 static dladm_status_t do_get_authmode(datalink_id_t, void *, int); 55 static dladm_status_t do_get_linkstatus(datalink_id_t, void *, int); 56 static dladm_status_t do_get_esslist(datalink_id_t, void *, int); 57 static dladm_status_t do_get_rate(datalink_id_t, void *, int); 58 static dladm_status_t do_get_mode(datalink_id_t, void *, int); 59 static dladm_status_t do_get_capability(datalink_id_t, void *, int); 60 static dladm_status_t do_get_wpamode(datalink_id_t, void *, int); 61 62 static dladm_status_t do_set_bsstype(datalink_id_t, dladm_wlan_bsstype_t *); 63 static dladm_status_t do_set_authmode(datalink_id_t, dladm_wlan_auth_t *); 64 static dladm_status_t do_set_encryption(datalink_id_t, 65 dladm_wlan_secmode_t *); 66 static dladm_status_t do_set_essid(datalink_id_t, dladm_wlan_essid_t *); 67 static dladm_status_t do_set_createibss(datalink_id_t, boolean_t *); 68 static dladm_status_t do_set_key(datalink_id_t, dladm_wlan_key_t *, uint_t); 69 static dladm_status_t do_set_channel(datalink_id_t, dladm_wlan_channel_t *); 70 71 static dladm_status_t do_scan(datalink_id_t, void *, int); 72 static dladm_status_t do_connect(datalink_id_t, void *, int, 73 dladm_wlan_attr_t *, boolean_t, void *, uint_t, 74 int); 75 static dladm_status_t do_disconnect(datalink_id_t, void *, int); 76 static boolean_t find_val_by_name(const char *, val_desc_t *, 77 uint_t, uint_t *); 78 static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); 79 static void generate_essid(dladm_wlan_essid_t *); 80 81 static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); 82 static dladm_status_t dladm_wlan_validate(datalink_id_t); 83 84 static val_desc_t linkstatus_vals[] = { 85 { "disconnected", DLADM_WLAN_LINK_DISCONNECTED }, 86 { "connected", DLADM_WLAN_LINK_CONNECTED } 87 }; 88 89 static val_desc_t secmode_vals[] = { 90 { "none", DLADM_WLAN_SECMODE_NONE }, 91 { "wep", DLADM_WLAN_SECMODE_WEP }, 92 { "wpa", DLADM_WLAN_SECMODE_WPA } 93 }; 94 95 static val_desc_t strength_vals[] = { 96 { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, 97 { "weak", DLADM_WLAN_STRENGTH_WEAK }, 98 { "good", DLADM_WLAN_STRENGTH_GOOD }, 99 { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, 100 { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } 101 }; 102 103 static val_desc_t mode_vals[] = { 104 { "a", DLADM_WLAN_MODE_80211A }, 105 { "b", DLADM_WLAN_MODE_80211B }, 106 { "g", DLADM_WLAN_MODE_80211G }, 107 }; 108 109 static val_desc_t auth_vals[] = { 110 { "open", DLADM_WLAN_AUTH_OPEN }, 111 { "shared", DLADM_WLAN_AUTH_SHARED } 112 }; 113 114 static val_desc_t bsstype_vals[] = { 115 { "bss", DLADM_WLAN_BSSTYPE_BSS }, 116 { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, 117 { "any", DLADM_WLAN_BSSTYPE_ANY } 118 }; 119 120 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 121 122 static dladm_status_t 123 dladm_wlan_wlresult2status(wldp_t *gbuf) 124 { 125 switch (gbuf->wldp_result) { 126 case WL_SUCCESS: 127 return (DLADM_STATUS_OK); 128 129 case WL_NOTSUPPORTED: 130 case WL_LACK_FEATURE: 131 return (DLADM_STATUS_NOTSUP); 132 133 case WL_READONLY: 134 return (DLADM_STATUS_PROPRDONLY); 135 136 default: 137 break; 138 } 139 140 return (DLADM_STATUS_FAILED); 141 } 142 143 static dladm_wlan_mode_t 144 do_convert_mode(wl_phy_conf_t *phyp) 145 { 146 switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) { 147 case WL_ERP: 148 return (DLADM_WLAN_MODE_80211G); 149 case WL_OFDM: 150 return (DLADM_WLAN_MODE_80211A); 151 case WL_DSSS: 152 case WL_FHSS: 153 return (DLADM_WLAN_MODE_80211B); 154 default: 155 break; 156 } 157 158 return (DLADM_WLAN_MODE_NONE); 159 } 160 161 boolean_t 162 i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) 163 { 164 wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf; 165 wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf; 166 167 switch (wlfp->wl_fhss_subtype) { 168 case WL_FHSS: 169 case WL_DSSS: 170 case WL_IRBASE: 171 case WL_HRDS: 172 case WL_ERP: 173 *channelp = wlfp->wl_fhss_channel; 174 break; 175 case WL_OFDM: 176 *channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency); 177 break; 178 default: 179 return (B_FALSE); 180 } 181 return (B_TRUE); 182 } 183 184 #define IEEE80211_RATE 0x7f 185 static void 186 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp) 187 { 188 int i; 189 190 (void) memset(attrp, 0, sizeof (*attrp)); 191 192 (void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN, 193 "%s", wlp->wl_ess_conf_essid.wl_essid_essid); 194 attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 195 196 (void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid, 197 DLADM_WLAN_BSSID_LEN); 198 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 199 200 attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled == 201 WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE); 202 if (wlp->wl_ess_conf_reserved[0] > 0) 203 attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 204 attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 205 206 attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ? 207 DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS); 208 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 209 210 attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ? 211 DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED); 212 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 213 214 attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl); 215 attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 216 217 attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf); 218 attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 219 220 for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) { 221 wlp->wl_supported_rates[i] &= IEEE80211_RATE; 222 if (wlp->wl_supported_rates[i] > attrp->wa_speed) 223 attrp->wa_speed = wlp->wl_supported_rates[i]; 224 } 225 if (attrp->wa_speed > 0) 226 attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 227 228 if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, 229 &attrp->wa_channel)) 230 attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL; 231 } 232 233 dladm_status_t 234 dladm_wlan_scan(datalink_id_t linkid, void *arg, 235 boolean_t (*func)(void *, dladm_wlan_attr_t *)) 236 { 237 int i; 238 uint32_t count; 239 wl_ess_conf_t *wlp; 240 wl_ess_list_t *wls = NULL; 241 char buf[WLDP_BUFSIZE]; 242 wl_linkstatus_t wl_status; 243 dladm_wlan_attr_t wlattr; 244 dladm_status_t status; 245 246 if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) 247 goto done; 248 249 status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status)); 250 if (status != DLADM_STATUS_OK) 251 goto done; 252 253 if ((status = do_scan(linkid, buf, sizeof (buf))) != DLADM_STATUS_OK) 254 goto done; 255 256 if (func == NULL) { 257 status = DLADM_STATUS_OK; 258 goto done; 259 } 260 261 wls = malloc(WLDP_BUFSIZE); 262 if (wls == NULL) { 263 status = DLADM_STATUS_NOMEM; 264 goto done; 265 } 266 267 if ((status = do_get_esslist(linkid, wls, WLDP_BUFSIZE)) 268 != DLADM_STATUS_OK) 269 goto done; 270 271 wlp = wls->wl_ess_list_ess; 272 count = wls->wl_ess_list_num; 273 274 for (i = 0; i < count; i++, wlp++) { 275 fill_wlan_attr(wlp, &wlattr); 276 if (!func(arg, &wlattr)) 277 break; 278 } 279 280 if (wl_status != WL_CONNECTED) { 281 status = do_get_linkstatus(linkid, &wl_status, 282 sizeof (&wl_status)); 283 if (status != DLADM_STATUS_OK) 284 goto done; 285 if (wl_status == WL_CONNECTED) 286 (void) do_disconnect(linkid, buf, sizeof (buf)); 287 } 288 289 status = DLADM_STATUS_OK; 290 done: 291 free(wls); 292 return (status); 293 } 294 295 /* 296 * Structures used in building the list of eligible WLANs to connect to. 297 * Specifically, `connect_state' has the WLAN attributes that must be matched 298 * (in `cs_attr') and a growing list of WLANs that matched those attributes 299 * chained through `cs_list'. Each element in the list is of type `attr_node' 300 * and has the matching WLAN's attributes and a pointer to the next element. 301 * For convenience, `cs_count' tracks the number of elements in the list. 302 */ 303 typedef struct attr_node { 304 dladm_wlan_attr_t an_attr; 305 struct attr_node *an_next; 306 } attr_node_t; 307 308 typedef struct connect_state { 309 dladm_wlan_attr_t *cs_attr; 310 uint_t cs_count; 311 attr_node_t *cs_list; 312 } connect_state_t; 313 314 /* 315 * Compare two sets of WLAN attributes. For now, we only consider strength 316 * and speed (in that order), which matches the documented default policy for 317 * dladm_wlan_connect(). 318 */ 319 static int 320 attr_compare(const void *p1, const void *p2) 321 { 322 dladm_wlan_attr_t *attrp1, *attrp2; 323 324 attrp1 = (*(dladm_wlan_attr_t **)p1); 325 attrp2 = (*(dladm_wlan_attr_t **)p2); 326 327 if (attrp1->wa_strength < attrp2->wa_strength) 328 return (1); 329 330 if (attrp1->wa_strength > attrp2->wa_strength) 331 return (-1); 332 333 return (attrp2->wa_speed - attrp1->wa_speed); 334 } 335 336 /* 337 * Callback function used by dladm_wlan_connect() to filter out unwanted 338 * WLANs when scanning for available WLANs. Always returns B_TRUE to 339 * continue the scan. 340 */ 341 static boolean_t 342 connect_cb(void *arg, dladm_wlan_attr_t *attrp) 343 { 344 attr_node_t *nodep; 345 dladm_wlan_attr_t *fattrp; 346 connect_state_t *statep = (connect_state_t *)arg; 347 348 fattrp = statep->cs_attr; 349 if (fattrp == NULL) 350 goto append; 351 352 if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid) 353 return (B_TRUE); 354 355 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 && 356 strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes, 357 DLADM_WLAN_MAX_ESSID_LEN) != 0) 358 return (B_TRUE); 359 360 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 361 fattrp->wa_secmode != attrp->wa_secmode) 362 return (B_TRUE); 363 364 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 && 365 fattrp->wa_mode != attrp->wa_mode) 366 return (B_TRUE); 367 368 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 && 369 fattrp->wa_strength != attrp->wa_strength) 370 return (B_TRUE); 371 372 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 && 373 fattrp->wa_speed != attrp->wa_speed) 374 return (B_TRUE); 375 376 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) { 377 attrp->wa_auth = fattrp->wa_auth; 378 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 379 } 380 381 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 382 fattrp->wa_bsstype != attrp->wa_bsstype) 383 return (B_TRUE); 384 385 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 && 386 memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes, 387 DLADM_WLAN_BSSID_LEN) != 0) 388 return (B_TRUE); 389 append: 390 nodep = malloc(sizeof (attr_node_t)); 391 if (nodep == NULL) 392 return (B_TRUE); 393 394 (void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t)); 395 nodep->an_next = statep->cs_list; 396 statep->cs_list = nodep; 397 statep->cs_count++; 398 399 return (B_TRUE); 400 } 401 402 #define IEEE80211_C_WPA 0x01800000 403 404 static dladm_status_t 405 do_connect(datalink_id_t linkid, void *buf, int bufsize, 406 dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys, 407 uint_t key_count, int timeout) 408 { 409 dladm_wlan_secmode_t secmode; 410 dladm_wlan_auth_t authmode; 411 dladm_wlan_bsstype_t bsstype; 412 dladm_wlan_essid_t essid; 413 boolean_t essid_valid = B_FALSE; 414 dladm_status_t status; 415 dladm_wlan_channel_t channel; 416 hrtime_t start; 417 wl_capability_t *caps; 418 wl_linkstatus_t wl_status; 419 420 if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) { 421 channel = attrp->wa_channel; 422 status = do_set_channel(linkid, &channel); 423 if (status != DLADM_STATUS_OK) 424 goto fail; 425 } 426 427 secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ? 428 attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE; 429 430 if ((status = do_set_encryption(linkid, &secmode)) != DLADM_STATUS_OK) 431 goto fail; 432 433 authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ? 434 attrp->wa_auth : DLADM_WLAN_AUTH_OPEN; 435 436 if ((status = do_set_authmode(linkid, &authmode)) != DLADM_STATUS_OK) 437 goto fail; 438 439 bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ? 440 attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS; 441 442 if ((status = do_set_bsstype(linkid, &bsstype)) != DLADM_STATUS_OK) 443 goto fail; 444 445 if (secmode == DLADM_WLAN_SECMODE_WEP) { 446 if (keys == NULL || key_count == 0 || 447 key_count > MAX_NWEPKEYS) { 448 status = DLADM_STATUS_BADARG; 449 goto fail; 450 } 451 status = do_set_key(linkid, keys, key_count); 452 if (status != DLADM_STATUS_OK) 453 goto fail; 454 } else if (secmode == DLADM_WLAN_SECMODE_WPA) { 455 if (keys == NULL || key_count == 0 || 456 key_count > MAX_NWEPKEYS) { 457 status = DLADM_STATUS_BADARG; 458 goto fail; 459 } 460 status = do_get_capability(linkid, buf, bufsize); 461 if (status != DLADM_STATUS_OK) 462 goto fail; 463 caps = (wl_capability_t *)buf; 464 if ((caps->caps & IEEE80211_C_WPA) == 0) 465 return (DLADM_STATUS_NOTSUP); 466 } 467 468 if (create_ibss) { 469 status = do_set_channel(linkid, &channel); 470 if (status != DLADM_STATUS_OK) 471 goto fail; 472 473 status = do_set_createibss(linkid, &create_ibss); 474 if (status != DLADM_STATUS_OK) 475 goto fail; 476 477 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) { 478 generate_essid(&essid); 479 essid_valid = B_TRUE; 480 } 481 } 482 483 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) { 484 essid = attrp->wa_essid; 485 essid_valid = B_TRUE; 486 } 487 488 if (!essid_valid) { 489 status = DLADM_STATUS_FAILED; 490 goto fail; 491 } 492 493 if ((status = do_set_essid(linkid, &essid)) != DLADM_STATUS_OK) 494 goto fail; 495 496 /* 497 * Because wpa daemon needs getting essid from driver, 498 * we need call do_set_essid() first, then call wpa_instance_create(). 499 */ 500 if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) 501 (void) wpa_instance_create(linkid, keys); 502 503 start = gethrtime(); 504 for (;;) { 505 status = do_get_linkstatus(linkid, &wl_status, 506 sizeof (wl_status)); 507 if (status != DLADM_STATUS_OK) 508 goto fail; 509 510 if (wl_status == WL_CONNECTED) 511 break; 512 513 (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE); 514 if ((timeout >= 0) && (gethrtime() - start) / 515 NANOSEC >= timeout) { 516 status = DLADM_STATUS_TIMEDOUT; 517 goto fail; 518 } 519 } 520 status = DLADM_STATUS_OK; 521 fail: 522 return (status); 523 } 524 525 dladm_status_t 526 dladm_wlan_connect(datalink_id_t linkid, dladm_wlan_attr_t *attrp, 527 int timeout, void *keys, uint_t key_count, uint_t flags) 528 { 529 int i; 530 char buf[WLDP_BUFSIZE]; 531 connect_state_t state = {0, NULL, NULL}; 532 attr_node_t *nodep = NULL; 533 boolean_t create_ibss, set_authmode; 534 dladm_wlan_attr_t **wl_list = NULL; 535 dladm_status_t status; 536 wl_linkstatus_t wl_status; 537 538 if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) 539 return (status); 540 541 if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status))) 542 != DLADM_STATUS_OK) 543 goto done; 544 545 if (wl_status == WL_CONNECTED) { 546 status = DLADM_STATUS_ISCONN; 547 goto done; 548 } 549 550 set_authmode = ((attrp != NULL) && 551 (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0); 552 create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 && 553 attrp != NULL && 554 (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 555 attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS); 556 557 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 || 558 (create_ibss && attrp != NULL && 559 (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) { 560 status = do_connect(linkid, buf, sizeof (buf), attrp, 561 create_ibss, keys, key_count, timeout); 562 goto done; 563 } 564 565 state.cs_attr = attrp; 566 state.cs_list = NULL; 567 state.cs_count = 0; 568 569 status = dladm_wlan_scan(linkid, &state, connect_cb); 570 if (status != DLADM_STATUS_OK) 571 goto done; 572 573 if (state.cs_count == 0) { 574 if (!create_ibss) { 575 status = DLADM_STATUS_NOTFOUND; 576 goto done; 577 } 578 status = do_connect(linkid, buf, sizeof (buf), 579 attrp, create_ibss, keys, key_count, timeout); 580 goto done; 581 } 582 583 wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *)); 584 if (wl_list == NULL) { 585 status = DLADM_STATUS_NOMEM; 586 goto done; 587 } 588 589 nodep = state.cs_list; 590 for (i = 0; i < state.cs_count; i++) { 591 wl_list[i] = &nodep->an_attr; 592 nodep = nodep->an_next; 593 } 594 qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *), 595 attr_compare); 596 597 for (i = 0; i < state.cs_count; i++) { 598 dladm_wlan_attr_t *ap = wl_list[i]; 599 600 status = do_connect(linkid, buf, sizeof (buf), 601 ap, create_ibss, keys, key_count, timeout); 602 if (status == DLADM_STATUS_OK) 603 break; 604 605 if (!set_authmode) { 606 ap->wa_auth = DLADM_WLAN_AUTH_SHARED; 607 ap->wa_valid |= DLADM_WLAN_ATTR_AUTH; 608 status = do_connect(linkid, buf, sizeof (buf), 609 ap, create_ibss, keys, key_count, timeout); 610 if (status == DLADM_STATUS_OK) 611 break; 612 } 613 } 614 done: 615 if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN)) 616 (void) do_disconnect(linkid, buf, sizeof (buf)); 617 618 while (state.cs_list != NULL) { 619 nodep = state.cs_list; 620 state.cs_list = nodep->an_next; 621 free(nodep); 622 } 623 free(wl_list); 624 return (status); 625 } 626 627 dladm_status_t 628 dladm_wlan_disconnect(datalink_id_t linkid) 629 { 630 char buf[WLDP_BUFSIZE]; 631 dladm_status_t status; 632 wl_linkstatus_t wl_status; 633 634 if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) 635 return (status); 636 637 if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status))) 638 != DLADM_STATUS_OK) 639 goto done; 640 641 if (wl_status != WL_CONNECTED) { 642 status = DLADM_STATUS_NOTCONN; 643 goto done; 644 } 645 646 if ((status = do_disconnect(linkid, buf, sizeof (buf))) 647 != DLADM_STATUS_OK) 648 goto done; 649 650 if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status))) 651 != DLADM_STATUS_OK) 652 goto done; 653 654 if (wl_status == WL_CONNECTED) { 655 status = DLADM_STATUS_FAILED; 656 goto done; 657 } 658 659 status = DLADM_STATUS_OK; 660 done: 661 return (status); 662 } 663 664 dladm_status_t 665 dladm_wlan_get_linkattr(datalink_id_t linkid, dladm_wlan_linkattr_t *attrp) 666 { 667 wl_rssi_t signal; 668 wl_bss_type_t bsstype; 669 wl_authmode_t authmode; 670 wl_encryption_t encryption; 671 wl_rates_t *ratesp = NULL; 672 dladm_wlan_attr_t *wl_attrp; 673 dladm_status_t status; 674 char buf[WLDP_BUFSIZE]; 675 wl_essid_t wls; 676 wl_phy_conf_t wl_phy_conf; 677 wl_linkstatus_t wl_status; 678 679 if (attrp == NULL) 680 return (DLADM_STATUS_BADARG); 681 682 if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) 683 goto done; 684 685 (void) memset(attrp, 0, sizeof (*attrp)); 686 wl_attrp = &attrp->la_wlan_attr; 687 688 if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status))) 689 != DLADM_STATUS_OK) 690 goto done; 691 692 attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS; 693 if (wl_status != WL_CONNECTED) 694 attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED; 695 else 696 attrp->la_status = DLADM_WLAN_LINK_CONNECTED; 697 698 if ((status = do_get_essid(linkid, &wls, sizeof (wls))) 699 != DLADM_STATUS_OK) 700 goto done; 701 702 (void) strlcpy(wl_attrp->wa_essid.we_bytes, wls.wl_essid_essid, 703 DLADM_WLAN_MAX_ESSID_LEN); 704 705 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 706 707 if ((status = do_get_bssid(linkid, buf, sizeof (buf))) 708 != DLADM_STATUS_OK) 709 goto done; 710 711 (void) memcpy(wl_attrp->wa_bssid.wb_bytes, buf, DLADM_WLAN_BSSID_LEN); 712 713 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 714 715 if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) { 716 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 717 status = DLADM_STATUS_OK; 718 goto done; 719 } 720 721 if ((status = do_get_encryption(linkid, &encryption, 722 sizeof (encryption))) != DLADM_STATUS_OK) 723 goto done; 724 725 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 726 727 switch (encryption) { 728 case WL_NOENCRYPTION: 729 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE; 730 break; 731 case WL_ENC_WEP: 732 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP; 733 break; 734 case WL_ENC_WPA: 735 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 736 break; 737 default: 738 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE; 739 break; 740 } 741 742 if ((status = do_get_signal(linkid, &signal, sizeof (signal))) 743 != DLADM_STATUS_OK) 744 goto done; 745 746 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 747 wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal); 748 749 ratesp = malloc(WLDP_BUFSIZE); 750 if (ratesp == NULL) { 751 status = DLADM_STATUS_NOMEM; 752 goto done; 753 } 754 755 if ((status = do_get_rate(linkid, ratesp, WLDP_BUFSIZE)) 756 != DLADM_STATUS_OK) 757 goto done; 758 759 if (ratesp->wl_rates_num > 0) { 760 uint_t i, r = 0; 761 762 for (i = 0; i < ratesp->wl_rates_num; i++) { 763 if (ratesp->wl_rates_rates[i] > r) 764 r = ratesp->wl_rates_rates[i]; 765 } 766 wl_attrp->wa_speed = r; 767 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 768 } 769 770 if ((status = do_get_authmode(linkid, &authmode, 771 sizeof (authmode))) != DLADM_STATUS_OK) 772 goto done; 773 774 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 775 776 switch (authmode) { 777 case WL_OPENSYSTEM: 778 wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN; 779 break; 780 case WL_SHAREDKEY: 781 wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED; 782 break; 783 default: 784 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH; 785 break; 786 } 787 788 if ((status = do_get_bsstype(linkid, &bsstype, 789 sizeof (bsstype))) != DLADM_STATUS_OK) 790 goto done; 791 792 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 793 794 switch (bsstype) { 795 case WL_BSS_BSS: 796 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS; 797 break; 798 case WL_BSS_IBSS: 799 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS; 800 break; 801 case WL_BSS_ANY: 802 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY; 803 break; 804 default: 805 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE; 806 break; 807 } 808 809 if ((status = do_get_mode(linkid, &wl_phy_conf, 810 sizeof (wl_phy_conf))) != DLADM_STATUS_OK) 811 goto done; 812 813 wl_attrp->wa_mode = do_convert_mode(&wl_phy_conf); 814 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 815 if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE) 816 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 817 818 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 819 status = DLADM_STATUS_OK; 820 821 done: 822 free(ratesp); 823 return (status); 824 } 825 826 /* 827 * Check to see if the link is wireless. 828 */ 829 static dladm_status_t 830 dladm_wlan_validate(datalink_id_t linkid) 831 { 832 uint32_t media; 833 dladm_status_t status; 834 835 status = dladm_datalink_id2info(linkid, NULL, NULL, &media, NULL, 0); 836 if (status == DLADM_STATUS_OK) { 837 if (media != DL_WIFI) 838 status = DLADM_STATUS_LINKINVAL; 839 } 840 return (status); 841 } 842 843 static boolean_t 844 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp) 845 { 846 int i; 847 848 for (i = 0; i < cnt; i++) { 849 if (strcasecmp(str, vdp[i].vd_name) == 0) { 850 *valp = vdp[i].vd_val; 851 return (B_TRUE); 852 } 853 } 854 return (B_FALSE); 855 } 856 857 static boolean_t 858 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp) 859 { 860 int i; 861 862 for (i = 0; i < cnt; i++) { 863 if (val == vdp[i].vd_val) { 864 *strp = vdp[i].vd_name; 865 return (B_TRUE); 866 } 867 } 868 return (B_FALSE); 869 } 870 871 const char * 872 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf) 873 { 874 (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes); 875 return (buf); 876 } 877 878 const char * 879 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf) 880 { 881 return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN, 882 IFT_OTHER)); 883 } 884 885 static const char * 886 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf) 887 { 888 char *s; 889 890 if (!find_name_by_val(val, vdp, cnt, &s)) 891 s = ""; 892 893 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 894 return (buf); 895 } 896 897 const char * 898 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf) 899 { 900 return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals, 901 VALCNT(secmode_vals), buf)); 902 } 903 904 const char * 905 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf) 906 { 907 return (dladm_wlan_val2str((uint_t)*strength, strength_vals, 908 VALCNT(strength_vals), buf)); 909 } 910 911 const char * 912 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf) 913 { 914 return (dladm_wlan_val2str((uint_t)*mode, mode_vals, 915 VALCNT(mode_vals), buf)); 916 } 917 918 const char * 919 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf) 920 { 921 (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2, 922 (float)(*speed) / 2); 923 return (buf); 924 } 925 926 const char * 927 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf) 928 { 929 return (dladm_wlan_val2str((uint_t)*auth, auth_vals, 930 VALCNT(auth_vals), buf)); 931 } 932 933 const char * 934 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf) 935 { 936 return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals, 937 VALCNT(bsstype_vals), buf)); 938 } 939 940 const char * 941 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf) 942 { 943 return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals, 944 VALCNT(linkstatus_vals), buf)); 945 } 946 947 dladm_status_t 948 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid) 949 { 950 if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1) 951 return (DLADM_STATUS_BADARG); 952 953 (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN); 954 return (DLADM_STATUS_OK); 955 } 956 957 dladm_status_t 958 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid) 959 { 960 int len; 961 uchar_t *buf; 962 963 buf = _link_aton(str, &len); 964 if (buf == NULL) 965 return (DLADM_STATUS_BADARG); 966 967 if (len != DLADM_WLAN_BSSID_LEN) { 968 free(buf); 969 return (DLADM_STATUS_BADARG); 970 } 971 972 (void) memcpy(bssid->wb_bytes, buf, len); 973 free(buf); 974 return (DLADM_STATUS_OK); 975 } 976 977 dladm_status_t 978 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode) 979 { 980 uint_t val; 981 982 if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val)) 983 return (DLADM_STATUS_BADARG); 984 985 *secmode = (dladm_wlan_secmode_t)val; 986 return (DLADM_STATUS_OK); 987 } 988 989 dladm_status_t 990 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength) 991 { 992 uint_t val; 993 994 if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val)) 995 return (DLADM_STATUS_BADARG); 996 997 *strength = (dladm_wlan_strength_t)val; 998 return (DLADM_STATUS_OK); 999 } 1000 1001 dladm_status_t 1002 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode) 1003 { 1004 uint_t val; 1005 1006 if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val)) 1007 return (DLADM_STATUS_BADARG); 1008 1009 *mode = (dladm_wlan_mode_t)val; 1010 return (DLADM_STATUS_OK); 1011 } 1012 1013 dladm_status_t 1014 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed) 1015 { 1016 *speed = (dladm_wlan_speed_t)(atof(str) * 2); 1017 return (DLADM_STATUS_OK); 1018 } 1019 1020 dladm_status_t 1021 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth) 1022 { 1023 uint_t val; 1024 1025 if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val)) 1026 return (DLADM_STATUS_BADARG); 1027 1028 *auth = (dladm_wlan_auth_t)val; 1029 return (DLADM_STATUS_OK); 1030 } 1031 1032 dladm_status_t 1033 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype) 1034 { 1035 uint_t val; 1036 1037 if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val)) 1038 return (DLADM_STATUS_BADARG); 1039 1040 *bsstype = (dladm_wlan_bsstype_t)val; 1041 return (DLADM_STATUS_OK); 1042 } 1043 1044 dladm_status_t 1045 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus) 1046 { 1047 uint_t val; 1048 1049 if (!find_val_by_name(str, linkstatus_vals, 1050 VALCNT(linkstatus_vals), &val)) { 1051 return (DLADM_STATUS_BADARG); 1052 } 1053 1054 *linkstatus = (dladm_wlan_linkstatus_t)val; 1055 return (DLADM_STATUS_OK); 1056 } 1057 1058 dladm_status_t 1059 i_dladm_wlan_legacy_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id, 1060 size_t len, uint_t cmd, size_t cmdlen) 1061 { 1062 char linkname[MAXPATHLEN]; 1063 int fd, rc; 1064 struct strioctl stri; 1065 uint32_t flags; 1066 dladm_status_t status; 1067 uint32_t media; 1068 char link[MAXLINKNAMELEN]; 1069 1070 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, 1071 link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 1072 return (status); 1073 } 1074 1075 if (media != DL_WIFI) 1076 return (DLADM_STATUS_BADARG); 1077 1078 if (!(flags & DLADM_OPT_ACTIVE)) 1079 return (DLADM_STATUS_TEMPONLY); 1080 1081 /* 1082 * dlpi_open() is not used here because libdlpi depends on libdladm, 1083 * and we do not want to introduce recursive dependencies. 1084 */ 1085 (void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link); 1086 if ((fd = open(linkname, O_RDWR)) < 0) 1087 return (dladm_errno2status(errno)); 1088 1089 gbuf->wldp_type = NET_802_11; 1090 gbuf->wldp_id = id; 1091 gbuf->wldp_length = len; 1092 1093 stri.ic_timout = 0; 1094 stri.ic_dp = (char *)gbuf; 1095 stri.ic_cmd = cmd; 1096 stri.ic_len = cmdlen; 1097 1098 if ((rc = ioctl(fd, I_STR, &stri)) != 0) { 1099 if (rc > 0) { 1100 /* 1101 * Non-negative return value indicates the specific 1102 * operation failed and the reason for the failure 1103 * was stored in gbuf->wldp_result. 1104 */ 1105 status = dladm_wlan_wlresult2status(gbuf); 1106 } else { 1107 /* 1108 * Negative return value indicates the ioctl failed. 1109 */ 1110 status = dladm_errno2status(errno); 1111 } 1112 } 1113 (void) close(fd); 1114 return (status); 1115 } 1116 1117 static dladm_status_t 1118 do_cmd_ioctl(datalink_id_t linkid, void *buf, int buflen, uint_t cmd) 1119 { 1120 wldp_t *gbuf; 1121 dladm_status_t status = DLADM_STATUS_OK; 1122 1123 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 1124 return (DLADM_STATUS_NOMEM); 1125 1126 (void) memset(gbuf, 0, MAX_BUF_LEN); 1127 status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, cmd, WLDP_BUFSIZE, 1128 WLAN_COMMAND, sizeof (wldp_t)); 1129 (void) memcpy(buf, gbuf->wldp_buf, buflen); 1130 free(gbuf); 1131 return (status); 1132 } 1133 1134 static dladm_status_t 1135 do_scan(datalink_id_t linkid, void *buf, int buflen) 1136 { 1137 return (do_cmd_ioctl(linkid, buf, buflen, WL_SCAN)); 1138 } 1139 1140 static dladm_status_t 1141 do_disconnect(datalink_id_t linkid, void *buf, int buflen) 1142 { 1143 if (do_get_wpamode(linkid, buf, buflen) == 0 && 1144 ((wl_wpa_t *)(buf))->wpa_flag > 0) 1145 (void) wpa_instance_delete(linkid); 1146 1147 return (do_cmd_ioctl(linkid, buf, buflen, WL_DISASSOCIATE)); 1148 } 1149 1150 static dladm_status_t 1151 do_get_esslist(datalink_id_t linkid, void *buf, int buflen) 1152 { 1153 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_ESS_LIST, buflen, 1154 B_FALSE)); 1155 } 1156 1157 static dladm_status_t 1158 do_get_bssid(datalink_id_t linkid, void *buf, int buflen) 1159 { 1160 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_BSSID, buflen, 1161 B_FALSE)); 1162 } 1163 1164 static dladm_status_t 1165 do_get_essid(datalink_id_t linkid, void *buf, int buflen) 1166 { 1167 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_ESSID, buflen, 1168 B_FALSE)); 1169 } 1170 1171 static dladm_status_t 1172 do_get_bsstype(datalink_id_t linkid, void *buf, int buflen) 1173 { 1174 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_BSSTYPE, buflen, 1175 B_FALSE)); 1176 } 1177 1178 static dladm_status_t 1179 do_get_linkstatus(datalink_id_t linkid, void *buf, int buflen) 1180 { 1181 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_LINKSTATUS, buflen, 1182 B_FALSE)); 1183 } 1184 1185 static dladm_status_t 1186 do_get_rate(datalink_id_t linkid, void *buf, int buflen) 1187 { 1188 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_DESIRED_RATES, 1189 buflen, B_FALSE)); 1190 } 1191 1192 static dladm_status_t 1193 do_get_authmode(datalink_id_t linkid, void *buf, int buflen) 1194 { 1195 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_AUTH_MODE, buflen, 1196 B_FALSE)); 1197 } 1198 1199 static dladm_status_t 1200 do_get_encryption(datalink_id_t linkid, void *buf, int buflen) 1201 { 1202 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_ENCRYPTION, buflen, 1203 B_FALSE)); 1204 } 1205 1206 static dladm_status_t 1207 do_get_signal(datalink_id_t linkid, void *buf, int buflen) 1208 { 1209 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_RSSI, buflen, 1210 B_FALSE)); 1211 } 1212 1213 static dladm_status_t 1214 do_get_mode(datalink_id_t linkid, void *buf, int buflen) 1215 { 1216 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_PHY_CONFIG, 1217 buflen, B_FALSE)); 1218 } 1219 1220 static dladm_status_t 1221 do_set_bsstype(datalink_id_t linkid, dladm_wlan_bsstype_t *bsstype) 1222 { 1223 wl_bss_type_t ibsstype; 1224 1225 switch (*bsstype) { 1226 case DLADM_WLAN_BSSTYPE_BSS: 1227 ibsstype = WL_BSS_BSS; 1228 break; 1229 case DLADM_WLAN_BSSTYPE_IBSS: 1230 ibsstype = WL_BSS_IBSS; 1231 break; 1232 default: 1233 ibsstype = WL_BSS_ANY; 1234 break; 1235 } 1236 return (i_dladm_wlan_param(linkid, &ibsstype, MAC_PROP_WL_BSSTYPE, 1237 sizeof (ibsstype), B_TRUE)); 1238 } 1239 1240 static dladm_status_t 1241 do_set_authmode(datalink_id_t linkid, dladm_wlan_auth_t *auth) 1242 { 1243 wl_authmode_t auth_mode; 1244 1245 switch (*auth) { 1246 case DLADM_WLAN_AUTH_OPEN: 1247 auth_mode = WL_OPENSYSTEM; 1248 break; 1249 case DLADM_WLAN_AUTH_SHARED: 1250 auth_mode = WL_SHAREDKEY; 1251 break; 1252 default: 1253 return (DLADM_STATUS_NOTSUP); 1254 } 1255 return (i_dladm_wlan_param(linkid, &auth_mode, MAC_PROP_WL_AUTH_MODE, 1256 sizeof (auth_mode), B_TRUE)); 1257 } 1258 1259 static dladm_status_t 1260 do_set_encryption(datalink_id_t linkid, dladm_wlan_secmode_t *secmode) 1261 { 1262 wl_encryption_t encryption; 1263 1264 switch (*secmode) { 1265 case DLADM_WLAN_SECMODE_NONE: 1266 encryption = WL_NOENCRYPTION; 1267 break; 1268 case DLADM_WLAN_SECMODE_WEP: 1269 encryption = WL_ENC_WEP; 1270 break; 1271 case DLADM_WLAN_SECMODE_WPA: 1272 return (0); 1273 default: 1274 return (DLADM_STATUS_NOTSUP); 1275 } 1276 return (i_dladm_wlan_param(linkid, &encryption, MAC_PROP_WL_ENCRYPTION, 1277 sizeof (encryption), B_TRUE)); 1278 } 1279 1280 static dladm_status_t 1281 do_set_key(datalink_id_t linkid, dladm_wlan_key_t *keys, 1282 uint_t key_count) 1283 { 1284 int i; 1285 wl_wep_key_t *wkp; 1286 wl_wep_key_tab_t wepkey_tab; 1287 dladm_wlan_key_t *kp; 1288 1289 if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL) 1290 return (DLADM_STATUS_BADARG); 1291 1292 (void) memset(wepkey_tab, 0, sizeof (wepkey_tab)); 1293 for (i = 0; i < MAX_NWEPKEYS; i++) 1294 wepkey_tab[i].wl_wep_operation = WL_NUL; 1295 1296 for (i = 0; i < key_count; i++) { 1297 kp = &keys[i]; 1298 if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS) 1299 return (DLADM_STATUS_BADARG); 1300 if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN && 1301 kp->wk_len != DLADM_WLAN_WEPKEY128_LEN) 1302 return (DLADM_STATUS_BADARG); 1303 1304 wkp = &wepkey_tab[kp->wk_idx - 1]; 1305 wkp->wl_wep_operation = WL_ADD; 1306 wkp->wl_wep_length = kp->wk_len; 1307 (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len); 1308 } 1309 1310 return (i_dladm_wlan_param(linkid, &wepkey_tab, MAC_PROP_WL_KEY_TAB, 1311 sizeof (wepkey_tab), B_TRUE)); 1312 } 1313 1314 static dladm_status_t 1315 do_set_essid(datalink_id_t linkid, dladm_wlan_essid_t *essid) 1316 { 1317 wl_essid_t iessid; 1318 1319 (void) memset(&iessid, 0, sizeof (essid)); 1320 1321 if (essid != NULL && essid->we_bytes[0] != '\0') { 1322 iessid.wl_essid_length = strlen(essid->we_bytes); 1323 (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes, 1324 sizeof (iessid.wl_essid_essid)); 1325 } else { 1326 return (DLADM_STATUS_BADARG); 1327 } 1328 return (i_dladm_wlan_param(linkid, &iessid, MAC_PROP_WL_ESSID, 1329 sizeof (iessid), B_TRUE)); 1330 } 1331 1332 static dladm_status_t 1333 do_set_channel(datalink_id_t linkid, dladm_wlan_channel_t *channel) 1334 { 1335 wl_phy_conf_t phy_conf; 1336 1337 if (*channel > MAX_CHANNEL_NUM) 1338 return (DLADM_STATUS_BADVAL); 1339 1340 (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); 1341 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; 1342 1343 return (i_dladm_wlan_param(linkid, &phy_conf, MAC_PROP_WL_PHY_CONFIG, 1344 sizeof (phy_conf), B_TRUE)); 1345 } 1346 1347 static dladm_status_t 1348 do_set_createibss(datalink_id_t linkid, boolean_t *create_ibss) 1349 { 1350 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); 1351 1352 return (i_dladm_wlan_param(linkid, &cr, MAC_PROP_WL_CREATE_IBSS, 1353 sizeof (cr), B_TRUE)); 1354 } 1355 1356 static void 1357 generate_essid(dladm_wlan_essid_t *essid) 1358 { 1359 srandom(gethrtime()); 1360 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d", 1361 random()); 1362 } 1363 1364 static dladm_status_t 1365 do_get_capability(datalink_id_t linkid, void *buf, int buflen) 1366 { 1367 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_CAPABILITY, 1368 buflen, B_FALSE)); 1369 } 1370 1371 static dladm_status_t 1372 do_get_wpamode(datalink_id_t linkid, void *buf, int buflen) 1373 { 1374 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_WPA, buflen, 1375 B_FALSE)); 1376 } 1377 1378 dladm_status_t 1379 dladm_wlan_wpa_get_sr(datalink_id_t linkid, dladm_wlan_ess_t *sr, 1380 uint_t escnt, uint_t *estot) 1381 { 1382 int i, n; 1383 wl_wpa_ess_t *es; 1384 dladm_status_t status; 1385 1386 es = malloc(WLDP_BUFSIZE); 1387 if (es == NULL) 1388 return (DLADM_STATUS_NOMEM); 1389 1390 status = i_dladm_wlan_param(linkid, es, MAC_PROP_WL_SCANRESULTS, 1391 WLDP_BUFSIZE, B_FALSE); 1392 1393 if (status == DLADM_STATUS_OK) { 1394 n = (es->count > escnt) ? escnt : es->count; 1395 for (i = 0; i < n; i ++) { 1396 (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid, 1397 DLADM_WLAN_BSSID_LEN); 1398 sr[i].we_ssid_len = es->ess[i].ssid_len; 1399 (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid, 1400 es->ess[i].ssid_len); 1401 sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len; 1402 (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie, 1403 es->ess[i].wpa_ie_len); 1404 sr[i].we_freq = es->ess[i].freq; 1405 } 1406 *estot = n; 1407 } 1408 1409 free(es); 1410 return (status); 1411 } 1412 1413 dladm_status_t 1414 dladm_wlan_wpa_set_ie(datalink_id_t linkid, uint8_t *wpa_ie, uint_t wpa_ie_len) 1415 { 1416 wl_wpa_ie_t *ie; 1417 uint_t len; 1418 dladm_status_t status; 1419 1420 if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN) 1421 return (DLADM_STATUS_BADARG); 1422 len = sizeof (wl_wpa_ie_t) + wpa_ie_len; 1423 ie = malloc(len); 1424 if (ie == NULL) 1425 return (DLADM_STATUS_NOMEM); 1426 1427 (void) memset(ie, 0, len); 1428 ie->wpa_ie_len = wpa_ie_len; 1429 (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); 1430 1431 status = i_dladm_wlan_param(linkid, ie, MAC_PROP_WL_SETOPTIE, len, 1432 B_TRUE); 1433 free(ie); 1434 1435 return (status); 1436 } 1437 1438 dladm_status_t 1439 dladm_wlan_wpa_set_wpa(datalink_id_t linkid, boolean_t flag) 1440 { 1441 wl_wpa_t wpa; 1442 1443 wpa.wpa_flag = flag; 1444 return (i_dladm_wlan_param(linkid, &wpa, MAC_PROP_WL_WPA, 1445 sizeof (wpa), B_TRUE)); 1446 } 1447 1448 dladm_status_t 1449 dladm_wlan_wpa_del_key(datalink_id_t linkid, uint_t key_idx, 1450 const dladm_wlan_bssid_t *addr) 1451 { 1452 wl_del_key_t wk; 1453 1454 wk.idk_keyix = key_idx; 1455 if (addr != NULL) 1456 (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, 1457 DLADM_WLAN_BSSID_LEN); 1458 1459 return (i_dladm_wlan_param(linkid, &wk, MAC_PROP_WL_DELKEY, 1460 sizeof (wk), B_TRUE)); 1461 } 1462 1463 dladm_status_t 1464 dladm_wlan_wpa_set_key(datalink_id_t linkid, dladm_wlan_cipher_t cipher, 1465 const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, 1466 uint_t key_idx, uint8_t *key, uint_t key_len) 1467 { 1468 wl_key_t wk; 1469 1470 (void) memset(&wk, 0, sizeof (wl_key_t)); 1471 switch (cipher) { 1472 case DLADM_WLAN_CIPHER_WEP: 1473 wk.ik_type = IEEE80211_CIPHER_WEP; 1474 break; 1475 case DLADM_WLAN_CIPHER_TKIP: 1476 wk.ik_type = IEEE80211_CIPHER_TKIP; 1477 break; 1478 case DLADM_WLAN_CIPHER_AES_OCB: 1479 wk.ik_type = IEEE80211_CIPHER_AES_OCB; 1480 break; 1481 case DLADM_WLAN_CIPHER_AES_CCM: 1482 wk.ik_type = IEEE80211_CIPHER_AES_CCM; 1483 break; 1484 case DLADM_WLAN_CIPHER_CKIP: 1485 wk.ik_type = IEEE80211_CIPHER_CKIP; 1486 break; 1487 case DLADM_WLAN_CIPHER_NONE: 1488 wk.ik_type = IEEE80211_CIPHER_NONE; 1489 break; 1490 default: 1491 return (DLADM_STATUS_BADARG); 1492 } 1493 wk.ik_flags = IEEE80211_KEY_RECV; 1494 if (set_tx) { 1495 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; 1496 (void) memcpy(wk.ik_macaddr, addr->wb_bytes, 1497 DLADM_WLAN_BSSID_LEN); 1498 } else 1499 (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN); 1500 wk.ik_keyix = key_idx; 1501 wk.ik_keylen = key_len; 1502 (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ 1503 (void) memcpy(wk.ik_keydata, key, key_len); 1504 1505 return (i_dladm_wlan_param(linkid, &wk, MAC_PROP_WL_KEY, 1506 sizeof (wk), B_TRUE)); 1507 } 1508 1509 dladm_status_t 1510 dladm_wlan_wpa_set_mlme(datalink_id_t linkid, dladm_wlan_mlme_op_t op, 1511 dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) 1512 { 1513 wl_mlme_t mlme; 1514 1515 (void) memset(&mlme, 0, sizeof (wl_mlme_t)); 1516 switch (op) { 1517 case DLADM_WLAN_MLME_ASSOC: 1518 mlme.im_op = IEEE80211_MLME_ASSOC; 1519 break; 1520 case DLADM_WLAN_MLME_DISASSOC: 1521 mlme.im_op = IEEE80211_MLME_DISASSOC; 1522 break; 1523 default: 1524 return (DLADM_STATUS_BADARG); 1525 } 1526 mlme.im_reason = reason; 1527 if (bssid != NULL) 1528 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, 1529 DLADM_WLAN_BSSID_LEN); 1530 1531 return (i_dladm_wlan_param(linkid, &mlme, MAC_PROP_WL_MLME, 1532 sizeof (mlme), B_TRUE)); 1533 } 1534 1535 /* 1536 * routines of create instance 1537 */ 1538 static scf_propertygroup_t * 1539 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, 1540 const char *pg_name, const char *pg_type) 1541 { 1542 scf_propertygroup_t *pg; 1543 1544 pg = scf_pg_create(handle); 1545 if (pg == NULL) 1546 return (NULL); 1547 1548 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) { 1549 scf_pg_destroy(pg); 1550 return (NULL); 1551 } 1552 1553 return (pg); 1554 } 1555 1556 static dladm_status_t 1557 add_new_property(scf_handle_t *handle, const char *prop_name, 1558 scf_type_t type, const char *val, scf_transaction_t *tx) 1559 { 1560 scf_value_t *value = NULL; 1561 scf_transaction_entry_t *entry = NULL; 1562 1563 entry = scf_entry_create(handle); 1564 if (entry == NULL) 1565 goto out; 1566 1567 value = scf_value_create(handle); 1568 if (value == NULL) 1569 goto out; 1570 1571 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) 1572 goto out; 1573 1574 if (scf_value_set_from_string(value, type, val) != 0) 1575 goto out; 1576 1577 if (scf_entry_add_value(entry, value) != 0) 1578 goto out; 1579 1580 return (DLADM_STATUS_OK); 1581 1582 out: 1583 if (value != NULL) 1584 scf_value_destroy(value); 1585 if (entry != NULL) 1586 scf_entry_destroy(entry); 1587 1588 return (DLADM_STATUS_FAILED); 1589 } 1590 1591 static dladm_status_t 1592 add_pg_method(scf_handle_t *handle, scf_instance_t *instance, 1593 const char *pg_name, const char *flags) 1594 { 1595 int rv, size; 1596 dladm_status_t status = DLADM_STATUS_FAILED; 1597 char *command = NULL; 1598 scf_transaction_t *tran = NULL; 1599 scf_propertygroup_t *pg; 1600 1601 pg = add_property_group_to_instance(handle, instance, 1602 pg_name, SCF_GROUP_METHOD); 1603 if (pg == NULL) 1604 goto out; 1605 1606 tran = scf_transaction_create(handle); 1607 if (tran == NULL) 1608 goto out; 1609 1610 size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; 1611 command = malloc(size); 1612 if (command == NULL) { 1613 status = DLADM_STATUS_NOMEM; 1614 goto out; 1615 } 1616 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); 1617 1618 do { 1619 if (scf_transaction_start(tran, pg) != 0) 1620 goto out; 1621 1622 if (add_new_property(handle, SCF_PROPERTY_EXEC, 1623 SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) { 1624 goto out; 1625 } 1626 1627 rv = scf_transaction_commit(tran); 1628 switch (rv) { 1629 case 1: 1630 status = DLADM_STATUS_OK; 1631 goto out; 1632 case 0: 1633 scf_transaction_destroy_children(tran); 1634 if (scf_pg_update(pg) == -1) { 1635 goto out; 1636 } 1637 break; 1638 case -1: 1639 default: 1640 goto out; 1641 } 1642 } while (rv == 0); 1643 1644 out: 1645 if (tran != NULL) { 1646 scf_transaction_destroy_children(tran); 1647 scf_transaction_destroy(tran); 1648 } 1649 1650 if (pg != NULL) 1651 scf_pg_destroy(pg); 1652 1653 if (command != NULL) 1654 free(command); 1655 1656 return (status); 1657 } 1658 1659 static dladm_status_t 1660 do_create_instance(scf_handle_t *handle, scf_service_t *svc, 1661 const char *instance_name, const char *command) 1662 { 1663 dladm_status_t status = DLADM_STATUS_FAILED; 1664 char *buf; 1665 ssize_t max_fmri_len; 1666 scf_instance_t *instance; 1667 1668 instance = scf_instance_create(handle); 1669 if (instance == NULL) 1670 goto out; 1671 1672 if (scf_service_add_instance(svc, instance_name, instance) != 0) { 1673 if (scf_error() == SCF_ERROR_EXISTS) 1674 /* Let the caller deal with the duplicate instance */ 1675 status = DLADM_STATUS_EXIST; 1676 goto out; 1677 } 1678 1679 if (add_pg_method(handle, instance, "start", 1680 command) != DLADM_STATUS_OK) { 1681 goto out; 1682 } 1683 1684 /* enabling the instance */ 1685 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 1686 if ((buf = malloc(max_fmri_len + 1)) == NULL) 1687 goto out; 1688 1689 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 1690 if ((smf_disable_instance(buf, 0) != 0) || 1691 (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { 1692 goto out; 1693 } 1694 status = DLADM_STATUS_OK; 1695 } 1696 1697 out: 1698 if (instance != NULL) 1699 scf_instance_destroy(instance); 1700 return (status); 1701 } 1702 1703 static dladm_status_t 1704 create_instance(const char *instance_name, const char *command) 1705 { 1706 dladm_status_t status = DLADM_STATUS_FAILED; 1707 scf_service_t *svc = NULL; 1708 scf_handle_t *handle = NULL; 1709 1710 handle = scf_handle_create(SCF_VERSION); 1711 if (handle == NULL) 1712 goto out; 1713 1714 if (scf_handle_bind(handle) == -1) 1715 goto out; 1716 1717 if ((svc = scf_service_create(handle)) == NULL) 1718 goto out; 1719 1720 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc, 1721 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 1722 goto out; 1723 1724 status = do_create_instance(handle, svc, instance_name, command); 1725 1726 out: 1727 if (svc != NULL) 1728 scf_service_destroy(svc); 1729 1730 if (handle != NULL) { 1731 (void) scf_handle_unbind(handle); 1732 scf_handle_destroy(handle); 1733 } 1734 1735 return (status); 1736 } 1737 1738 /* 1739 * routines of delete instance 1740 */ 1741 #define DEFAULT_TIMEOUT 60000000 1742 #define INIT_WAIT_USECS 50000 1743 1744 static void 1745 wait_until_disabled(scf_handle_t *handle, char *fmri) 1746 { 1747 char *state; 1748 useconds_t max; 1749 useconds_t usecs; 1750 uint64_t *cp = NULL; 1751 scf_simple_prop_t *sp = NULL; 1752 1753 max = DEFAULT_TIMEOUT; 1754 1755 if (((sp = scf_simple_prop_get(handle, fmri, "stop", 1756 SCF_PROPERTY_TIMEOUT)) != NULL) && 1757 ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0)) 1758 max = (*cp) * 1000000; /* convert to usecs */ 1759 1760 if (sp != NULL) 1761 scf_simple_prop_free(sp); 1762 1763 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) { 1764 /* incremental wait */ 1765 usecs *= 2; 1766 usecs = (usecs > max) ? max : usecs; 1767 1768 (void) usleep(usecs); 1769 1770 /* Check state after the wait */ 1771 if ((state = smf_get_state(fmri)) != NULL) { 1772 if (strcmp(state, "disabled") == 0) 1773 return; 1774 } 1775 } 1776 } 1777 1778 static dladm_status_t 1779 delete_instance(const char *instance_name) 1780 { 1781 dladm_status_t status = DLADM_STATUS_FAILED; 1782 char *buf; 1783 ssize_t max_fmri_len; 1784 scf_scope_t *scope = NULL; 1785 scf_service_t *svc = NULL; 1786 scf_handle_t *handle = NULL; 1787 scf_instance_t *instance; 1788 1789 handle = scf_handle_create(SCF_VERSION); 1790 if (handle == NULL) 1791 goto out; 1792 1793 if (scf_handle_bind(handle) == -1) 1794 goto out; 1795 1796 if ((scope = scf_scope_create(handle)) == NULL) 1797 goto out; 1798 1799 if ((svc = scf_service_create(handle)) == NULL) 1800 goto out; 1801 1802 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1) 1803 goto out; 1804 1805 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0) 1806 goto out; 1807 1808 instance = scf_instance_create(handle); 1809 if (instance == NULL) 1810 goto out; 1811 1812 if (scf_service_get_instance(svc, instance_name, instance) != 0) { 1813 scf_error_t scf_errnum = scf_error(); 1814 1815 if (scf_errnum == SCF_ERROR_NOT_FOUND) 1816 status = DLADM_STATUS_OK; 1817 1818 scf_instance_destroy(instance); 1819 goto out; 1820 } 1821 1822 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 1823 if ((buf = malloc(max_fmri_len + 1)) == NULL) { 1824 scf_instance_destroy(instance); 1825 goto out; 1826 } 1827 1828 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 1829 char *state; 1830 1831 state = smf_get_state(buf); 1832 if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 || 1833 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) { 1834 if (smf_disable_instance(buf, 0) == 0) { 1835 /* 1836 * Wait for some time till timeout to avoid 1837 * a race with scf_instance_delete() below. 1838 */ 1839 wait_until_disabled(handle, buf); 1840 } 1841 } 1842 } 1843 1844 if (scf_instance_delete(instance) != 0) { 1845 scf_instance_destroy(instance); 1846 goto out; 1847 } 1848 1849 scf_instance_destroy(instance); 1850 1851 status = DLADM_STATUS_OK; 1852 1853 out: 1854 if (svc != NULL) 1855 scf_service_destroy(svc); 1856 1857 if (scope != NULL) 1858 scf_scope_destroy(scope); 1859 1860 if (handle != NULL) { 1861 (void) scf_handle_unbind(handle); 1862 scf_handle_destroy(handle); 1863 } 1864 1865 return (status); 1866 } 1867 1868 static dladm_status_t 1869 wpa_instance_create(datalink_id_t linkid, void *key) 1870 { 1871 dladm_status_t status = DLADM_STATUS_FAILED; 1872 char *command = NULL; 1873 char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; 1874 int size; 1875 char instance_name[MAXLINKNAMELEN]; 1876 1877 /* 1878 * Use the link name as the instance name of the network/wpad service. 1879 */ 1880 status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name, 1881 sizeof (instance_name)); 1882 if (status != DLADM_STATUS_OK) 1883 goto out; 1884 1885 size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; 1886 command = malloc(size); 1887 if (command == NULL) { 1888 status = DLADM_STATUS_NOMEM; 1889 goto out; 1890 } 1891 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); 1892 1893 status = create_instance(instance_name, command); 1894 if (status == DLADM_STATUS_EXIST) { 1895 /* 1896 * Delete the existing instance and create a new instance 1897 * with the supplied arguments. 1898 */ 1899 if ((status = delete_instance(instance_name)) == 1900 DLADM_STATUS_OK) { 1901 status = create_instance(instance_name, command); 1902 } 1903 } 1904 1905 out: 1906 if (command != NULL) 1907 free(command); 1908 1909 return (status); 1910 } 1911 1912 static dladm_status_t 1913 wpa_instance_delete(datalink_id_t linkid) 1914 { 1915 char instance_name[MAXLINKNAMELEN]; 1916 1917 /* 1918 * Get the instance name of the network/wpad service (the same as 1919 * the link name). 1920 */ 1921 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name, 1922 sizeof (instance_name)) != DLADM_STATUS_OK) 1923 return (DLADM_STATUS_FAILED); 1924 1925 return (delete_instance(instance_name)); 1926 } 1927