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