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