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