xref: /illumos-gate/usr/src/lib/libdladm/common/libdlwlan.c (revision bea83d026ee1bd1b2a2419e1d0232f107a5d7d9b)
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;
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 		goto done;
534 
535 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
536 		status = DLADM_STATUS_NOMEM;
537 		goto done;
538 	}
539 
540 	if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK)
541 		goto done;
542 
543 	if (IS_CONNECTED(gbuf)) {
544 		status = DLADM_STATUS_ISCONN;
545 		goto done;
546 	}
547 
548 	set_authmode = ((attrp != NULL) &&
549 	    (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0);
550 	create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 &&
551 	    attrp != NULL &&
552 	    (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
553 	    attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS);
554 
555 	if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 ||
556 	    (create_ibss && attrp != NULL &&
557 	    (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) {
558 		status = do_connect(linkid, gbuf, attrp, create_ibss, keys,
559 		    key_count, timeout);
560 		goto done;
561 	}
562 
563 	state.cs_attr = attrp;
564 	state.cs_list = NULL;
565 	state.cs_count = 0;
566 
567 	status = dladm_wlan_scan(linkid, &state, connect_cb);
568 	if (status != DLADM_STATUS_OK)
569 		goto done;
570 
571 	if (state.cs_count == 0) {
572 		if (!create_ibss) {
573 			status = DLADM_STATUS_NOTFOUND;
574 			goto done;
575 		}
576 		status = do_connect(linkid, gbuf, attrp, create_ibss, keys,
577 		    key_count, timeout);
578 		goto done;
579 	}
580 
581 	wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *));
582 	if (wl_list == NULL) {
583 		status = DLADM_STATUS_NOMEM;
584 		goto done;
585 	}
586 
587 	nodep = state.cs_list;
588 	for (i = 0; i < state.cs_count; i++) {
589 		wl_list[i] = &nodep->an_attr;
590 		nodep = nodep->an_next;
591 	}
592 	qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
593 	    attr_compare);
594 
595 	for (i = 0; i < state.cs_count; i++) {
596 		dladm_wlan_attr_t	*ap = wl_list[i];
597 
598 		status = do_connect(linkid, gbuf, ap, create_ibss, keys,
599 		    key_count, timeout);
600 		if (status == DLADM_STATUS_OK)
601 			break;
602 
603 		if (!set_authmode) {
604 			ap->wa_auth = DLADM_WLAN_AUTH_SHARED;
605 			ap->wa_valid |= DLADM_WLAN_ATTR_AUTH;
606 			status = do_connect(linkid, gbuf, ap, create_ibss, keys,
607 			    key_count, timeout);
608 			if (status == DLADM_STATUS_OK)
609 				break;
610 		}
611 	}
612 done:
613 	if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
614 		(void) do_disconnect(linkid, gbuf);
615 
616 	while (state.cs_list != NULL) {
617 		nodep = state.cs_list;
618 		state.cs_list = nodep->an_next;
619 		free(nodep);
620 	}
621 	free(gbuf);
622 	free(wl_list);
623 	return (status);
624 }
625 
626 dladm_status_t
627 dladm_wlan_disconnect(datalink_id_t linkid)
628 {
629 	wldp_t		*gbuf;
630 	dladm_status_t	status;
631 
632 	if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK)
633 		return (status);
634 
635 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
636 		status = DLADM_STATUS_NOMEM;
637 		goto done;
638 	}
639 
640 	if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK)
641 		goto done;
642 
643 	if (!IS_CONNECTED(gbuf)) {
644 		status = DLADM_STATUS_NOTCONN;
645 		goto done;
646 	}
647 
648 	if ((status = do_disconnect(linkid, gbuf)) != DLADM_STATUS_OK)
649 		goto done;
650 
651 	if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK)
652 		goto done;
653 
654 	if (IS_CONNECTED(gbuf)) {
655 		status = DLADM_STATUS_FAILED;
656 		goto done;
657 	}
658 
659 	status = DLADM_STATUS_OK;
660 done:
661 	free(gbuf);
662 	return (status);
663 }
664 
665 dladm_status_t
666 dladm_wlan_get_linkattr(datalink_id_t linkid, dladm_wlan_linkattr_t *attrp)
667 {
668 	wldp_t			*gbuf;
669 	wl_rssi_t		signal;
670 	wl_bss_type_t		bsstype;
671 	wl_authmode_t		authmode;
672 	wl_encryption_t		encryption;
673 	wl_rates_t		*ratesp;
674 	dladm_wlan_attr_t	*wl_attrp;
675 	dladm_status_t		status;
676 
677 	if (attrp == NULL)
678 		return (DLADM_STATUS_BADARG);
679 
680 	if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK)
681 		goto done;
682 
683 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
684 		status = DLADM_STATUS_NOMEM;
685 		goto done;
686 	}
687 
688 	(void) memset(attrp, 0, sizeof (*attrp));
689 	wl_attrp = &attrp->la_wlan_attr;
690 
691 	if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK)
692 		goto done;
693 
694 	attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS;
695 	if (!IS_CONNECTED(gbuf))
696 		attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED;
697 	else
698 		attrp->la_status = DLADM_WLAN_LINK_CONNECTED;
699 
700 	if ((status = do_get_essid(linkid, gbuf)) != DLADM_STATUS_OK)
701 		goto done;
702 
703 	(void) strlcpy(wl_attrp->wa_essid.we_bytes,
704 	    ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
705 	    DLADM_WLAN_MAX_ESSID_LEN);
706 
707 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
708 
709 	if ((status = do_get_bssid(linkid, gbuf)) != DLADM_STATUS_OK)
710 		goto done;
711 
712 	(void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf,
713 	    DLADM_WLAN_BSSID_LEN);
714 
715 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
716 
717 	if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) {
718 		attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
719 		status = DLADM_STATUS_OK;
720 		goto done;
721 	}
722 
723 	if ((status = do_get_encryption(linkid, gbuf)) != DLADM_STATUS_OK)
724 		goto done;
725 
726 	encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
727 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
728 
729 	switch (encryption) {
730 	case WL_NOENCRYPTION:
731 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
732 		break;
733 	case WL_ENC_WEP:
734 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
735 		break;
736 	case WL_ENC_WPA:
737 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
738 		break;
739 	default:
740 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE;
741 		break;
742 	}
743 
744 	if ((status = do_get_signal(linkid, gbuf)) != DLADM_STATUS_OK)
745 		goto done;
746 
747 	signal = *(wl_rssi_t *)(gbuf->wldp_buf);
748 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
749 	wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
750 
751 	if ((status = do_get_rate(linkid, gbuf)) != DLADM_STATUS_OK)
752 		goto done;
753 
754 	ratesp = (wl_rates_t *)(gbuf->wldp_buf);
755 	if (ratesp->wl_rates_num > 0) {
756 		uint_t	i, r = 0;
757 
758 		for (i = 0; i < ratesp->wl_rates_num; i++) {
759 			if (ratesp->wl_rates_rates[i] > r)
760 				r = ratesp->wl_rates_rates[i];
761 		}
762 		wl_attrp->wa_speed = r;
763 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
764 	}
765 
766 	if ((status = do_get_authmode(linkid, gbuf)) != DLADM_STATUS_OK)
767 		goto done;
768 
769 	authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
770 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
771 
772 	switch (authmode) {
773 	case WL_OPENSYSTEM:
774 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
775 		break;
776 	case WL_SHAREDKEY:
777 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
778 		break;
779 	default:
780 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
781 		break;
782 	}
783 
784 	if ((status = do_get_bsstype(linkid, gbuf)) != DLADM_STATUS_OK)
785 		goto done;
786 
787 	bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
788 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
789 
790 	switch (bsstype) {
791 	case WL_BSS_BSS:
792 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
793 		break;
794 	case WL_BSS_IBSS:
795 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
796 		break;
797 	case WL_BSS_ANY:
798 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
799 		break;
800 	default:
801 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
802 		break;
803 	}
804 
805 	if ((status = do_get_mode(linkid, gbuf)) != DLADM_STATUS_OK)
806 		goto done;
807 
808 	wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf));
809 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
810 	if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
811 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
812 
813 	attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
814 	status = DLADM_STATUS_OK;
815 
816 done:
817 	free(gbuf);
818 	return (status);
819 }
820 
821 static dladm_status_t
822 dladm_wlan_validate(datalink_id_t linkid)
823 {
824 	wldp_t		*gbuf;
825 	dladm_status_t	status;
826 
827 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
828 		status = DLADM_STATUS_NOMEM;
829 		goto done;
830 	}
831 
832 	/*
833 	 * Check to see if the link is wireless.
834 	 */
835 	if ((status = do_get_bsstype(linkid, gbuf)) != DLADM_STATUS_OK) {
836 		status = DLADM_STATUS_LINKINVAL;
837 		goto done;
838 	}
839 
840 done:
841 	free(gbuf);
842 	return (status);
843 }
844 
845 static boolean_t
846 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
847 {
848 	int	i;
849 
850 	for (i = 0; i < cnt; i++) {
851 		if (strcasecmp(str, vdp[i].vd_name) == 0) {
852 			*valp = vdp[i].vd_val;
853 			return (B_TRUE);
854 		}
855 	}
856 	return (B_FALSE);
857 }
858 
859 static boolean_t
860 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
861 {
862 	int	i;
863 
864 	for (i = 0; i < cnt; i++) {
865 		if (val == vdp[i].vd_val) {
866 			*strp = vdp[i].vd_name;
867 			return (B_TRUE);
868 		}
869 	}
870 	return (B_FALSE);
871 }
872 
873 const char *
874 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
875 {
876 	(void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
877 	return (buf);
878 }
879 
880 const char *
881 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
882 {
883 	return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
884 	    IFT_OTHER));
885 }
886 
887 static const char *
888 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
889 {
890 	char	*s;
891 
892 	if (!find_name_by_val(val, vdp, cnt, &s))
893 		s = "";
894 
895 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
896 	return (buf);
897 }
898 
899 const char *
900 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
901 {
902 	return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
903 	    VALCNT(secmode_vals), buf));
904 }
905 
906 const char *
907 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
908 {
909 	return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
910 	    VALCNT(strength_vals), buf));
911 }
912 
913 const char *
914 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
915 {
916 	return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
917 	    VALCNT(mode_vals), buf));
918 }
919 
920 const char *
921 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
922 {
923 	(void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
924 	    (float)(*speed) / 2);
925 	return (buf);
926 }
927 
928 const char *
929 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
930 {
931 	return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
932 	    VALCNT(auth_vals), buf));
933 }
934 
935 const char *
936 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
937 {
938 	return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
939 	    VALCNT(bsstype_vals), buf));
940 }
941 
942 const char *
943 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
944 {
945 	return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
946 	    VALCNT(linkstatus_vals), buf));
947 }
948 
949 dladm_status_t
950 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
951 {
952 	if (str[0] == '\0')
953 		return (DLADM_STATUS_BADARG);
954 
955 	(void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
956 	return (DLADM_STATUS_OK);
957 }
958 
959 dladm_status_t
960 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
961 {
962 	int	len;
963 	uchar_t	*buf;
964 
965 	buf = _link_aton(str, &len);
966 	if (buf == NULL)
967 		return (DLADM_STATUS_BADARG);
968 
969 	if (len != DLADM_WLAN_BSSID_LEN) {
970 		free(buf);
971 		return (DLADM_STATUS_BADARG);
972 	}
973 
974 	(void) memcpy(bssid->wb_bytes, buf, len);
975 	free(buf);
976 	return (DLADM_STATUS_OK);
977 }
978 
979 dladm_status_t
980 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
981 {
982 	uint_t	val;
983 
984 	if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
985 		return (DLADM_STATUS_BADARG);
986 
987 	*secmode = (dladm_wlan_secmode_t)val;
988 	return (DLADM_STATUS_OK);
989 }
990 
991 dladm_status_t
992 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
993 {
994 	uint_t	val;
995 
996 	if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
997 		return (DLADM_STATUS_BADARG);
998 
999 	*strength = (dladm_wlan_strength_t)val;
1000 	return (DLADM_STATUS_OK);
1001 }
1002 
1003 dladm_status_t
1004 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
1005 {
1006 	uint_t	val;
1007 
1008 	if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
1009 		return (DLADM_STATUS_BADARG);
1010 
1011 	*mode = (dladm_wlan_mode_t)val;
1012 	return (DLADM_STATUS_OK);
1013 }
1014 
1015 dladm_status_t
1016 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
1017 {
1018 	*speed = (dladm_wlan_speed_t)(atof(str) * 2);
1019 	return (DLADM_STATUS_OK);
1020 }
1021 
1022 dladm_status_t
1023 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
1024 {
1025 	uint_t	val;
1026 
1027 	if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
1028 		return (DLADM_STATUS_BADARG);
1029 
1030 	*auth = (dladm_wlan_auth_t)val;
1031 	return (DLADM_STATUS_OK);
1032 }
1033 
1034 dladm_status_t
1035 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
1036 {
1037 	uint_t	val;
1038 
1039 	if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
1040 		return (DLADM_STATUS_BADARG);
1041 
1042 	*bsstype = (dladm_wlan_bsstype_t)val;
1043 	return (DLADM_STATUS_OK);
1044 }
1045 
1046 dladm_status_t
1047 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
1048 {
1049 	uint_t	val;
1050 
1051 	if (!find_val_by_name(str, linkstatus_vals,
1052 	    VALCNT(linkstatus_vals), &val)) {
1053 		return (DLADM_STATUS_BADARG);
1054 	}
1055 
1056 	*linkstatus = (dladm_wlan_linkstatus_t)val;
1057 	return (DLADM_STATUS_OK);
1058 }
1059 
1060 dladm_status_t
1061 i_dladm_wlan_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id, size_t len,
1062     uint_t cmd, size_t cmdlen)
1063 {
1064 	char			linkname[MAXPATHLEN];
1065 	int			fd, rc;
1066 	struct	strioctl	stri;
1067 	uint32_t		flags;
1068 	dladm_status_t		status;
1069 	uint32_t		media;
1070 	char			link[MAXLINKNAMELEN];
1071 
1072 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media,
1073 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1074 		return (status);
1075 	}
1076 
1077 	if (media != DL_WIFI)
1078 		return (DLADM_STATUS_BADARG);
1079 
1080 	if (!(flags & DLADM_OPT_ACTIVE))
1081 		return (DLADM_STATUS_TEMPONLY);
1082 
1083 	/*
1084 	 * dlpi_open() is not used here because libdlpi depends on libdladm,
1085 	 * and we do not want to introduce recursive dependencies.
1086 	 */
1087 	(void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
1088 	if ((fd = open(linkname, O_RDWR)) < 0)
1089 		return (DLADM_STATUS_LINKINVAL);
1090 
1091 	gbuf->wldp_type = NET_802_11;
1092 	gbuf->wldp_id	= id;
1093 	gbuf->wldp_length = len;
1094 
1095 	stri.ic_timout	= 0;
1096 	stri.ic_dp	= (char *)gbuf;
1097 	stri.ic_cmd	= cmd;
1098 	stri.ic_len	= cmdlen;
1099 
1100 	if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
1101 		if (rc > 0) {
1102 			/*
1103 			 * Non-negative return value indicates the specific
1104 			 * operation failed and the reason for the failure
1105 			 * was stored in gbuf->wldp_result.
1106 			 */
1107 			status = dladm_wlan_wlresult2status(gbuf);
1108 		} else {
1109 			/*
1110 			 * Negative return value indicates the ioctl failed.
1111 			 */
1112 			status = dladm_errno2status(errno);
1113 		}
1114 	}
1115 	(void) close(fd);
1116 	return (status);
1117 }
1118 
1119 dladm_status_t
1120 i_dladm_wlan_get_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id)
1121 {
1122 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1123 	return (i_dladm_wlan_ioctl(linkid, gbuf, id, MAX_BUF_LEN,
1124 	    WLAN_GET_PARAM, MAX_BUF_LEN));
1125 }
1126 
1127 dladm_status_t
1128 i_dladm_wlan_set_ioctl(datalink_id_t linkid, uint_t id, void *buf,
1129     uint_t buflen)
1130 {
1131 	wldp_t *gbuf;
1132 	dladm_status_t status = DLADM_STATUS_OK;
1133 
1134 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1135 		return (DLADM_STATUS_NOMEM);
1136 
1137 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1138 	(void) memcpy(gbuf->wldp_buf, buf, buflen);
1139 	buflen += WIFI_BUF_OFFSET;
1140 	status = i_dladm_wlan_ioctl(linkid, gbuf, id, buflen,
1141 	    WLAN_SET_PARAM, buflen);
1142 
1143 	free(gbuf);
1144 	return (status);
1145 }
1146 
1147 static dladm_status_t
1148 do_cmd_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t cmd)
1149 {
1150 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1151 	return (i_dladm_wlan_ioctl(linkid, gbuf, cmd, sizeof (wldp_t),
1152 	    WLAN_COMMAND, sizeof (wldp_t)));
1153 }
1154 
1155 static dladm_status_t
1156 do_scan(datalink_id_t linkid, wldp_t *gbuf)
1157 {
1158 	return (do_cmd_ioctl(linkid, gbuf, WL_SCAN));
1159 }
1160 
1161 static dladm_status_t
1162 do_disconnect(datalink_id_t linkid, wldp_t *gbuf)
1163 {
1164 	if (do_get_wpamode(linkid, gbuf) == 0 &&
1165 	    ((wl_wpa_t *)(gbuf->wldp_buf))->wpa_flag > 0)
1166 		(void) wpa_instance_delete(linkid);
1167 
1168 	return (do_cmd_ioctl(linkid, gbuf, WL_DISASSOCIATE));
1169 }
1170 
1171 static dladm_status_t
1172 do_get_esslist(datalink_id_t linkid, wldp_t *gbuf)
1173 {
1174 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1175 	return (i_dladm_wlan_ioctl(linkid, gbuf, WL_ESS_LIST, MAX_BUF_LEN,
1176 	    WLAN_GET_PARAM, sizeof (wldp_t)));
1177 }
1178 
1179 static dladm_status_t
1180 do_get_bssid(datalink_id_t linkid, wldp_t *gbuf)
1181 {
1182 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_BSSID));
1183 }
1184 
1185 static dladm_status_t
1186 do_get_essid(datalink_id_t linkid, wldp_t *gbuf)
1187 {
1188 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_ESSID));
1189 }
1190 
1191 static dladm_status_t
1192 do_get_bsstype(datalink_id_t linkid, wldp_t *gbuf)
1193 {
1194 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_BSS_TYPE));
1195 }
1196 
1197 static dladm_status_t
1198 do_get_linkstatus(datalink_id_t linkid, wldp_t *gbuf)
1199 {
1200 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_LINKSTATUS));
1201 }
1202 
1203 static dladm_status_t
1204 do_get_rate(datalink_id_t linkid, wldp_t *gbuf)
1205 {
1206 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_DESIRED_RATES));
1207 }
1208 
1209 static dladm_status_t
1210 do_get_authmode(datalink_id_t linkid, wldp_t *gbuf)
1211 {
1212 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_AUTH_MODE));
1213 }
1214 
1215 static dladm_status_t
1216 do_get_encryption(datalink_id_t linkid, wldp_t *gbuf)
1217 {
1218 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_ENCRYPTION));
1219 }
1220 
1221 static dladm_status_t
1222 do_get_signal(datalink_id_t linkid, wldp_t *gbuf)
1223 {
1224 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RSSI));
1225 }
1226 
1227 static dladm_status_t
1228 do_get_mode(datalink_id_t linkid, wldp_t *gbuf)
1229 {
1230 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
1231 }
1232 
1233 static dladm_status_t
1234 do_set_bsstype(datalink_id_t linkid, dladm_wlan_bsstype_t *bsstype)
1235 {
1236 	wl_bss_type_t	ibsstype;
1237 
1238 	switch (*bsstype) {
1239 	case DLADM_WLAN_BSSTYPE_BSS:
1240 		ibsstype = WL_BSS_BSS;
1241 		break;
1242 	case DLADM_WLAN_BSSTYPE_IBSS:
1243 		ibsstype = WL_BSS_IBSS;
1244 		break;
1245 	default:
1246 		ibsstype = WL_BSS_ANY;
1247 		break;
1248 	}
1249 	return (i_dladm_wlan_set_ioctl(linkid, WL_BSS_TYPE, &ibsstype,
1250 	    sizeof (ibsstype)));
1251 }
1252 
1253 static dladm_status_t
1254 do_set_authmode(datalink_id_t linkid, dladm_wlan_auth_t *auth)
1255 {
1256 	wl_authmode_t	auth_mode;
1257 
1258 	switch (*auth) {
1259 	case DLADM_WLAN_AUTH_OPEN:
1260 		auth_mode = WL_OPENSYSTEM;
1261 		break;
1262 	case DLADM_WLAN_AUTH_SHARED:
1263 		auth_mode = WL_SHAREDKEY;
1264 		break;
1265 	default:
1266 		return (DLADM_STATUS_NOTSUP);
1267 	}
1268 	return (i_dladm_wlan_set_ioctl(linkid, WL_AUTH_MODE, &auth_mode,
1269 	    sizeof (auth_mode)));
1270 }
1271 
1272 static dladm_status_t
1273 do_set_encryption(datalink_id_t linkid, dladm_wlan_secmode_t *secmode)
1274 {
1275 	wl_encryption_t	encryption;
1276 
1277 	switch (*secmode) {
1278 	case DLADM_WLAN_SECMODE_NONE:
1279 		encryption = WL_NOENCRYPTION;
1280 		break;
1281 	case DLADM_WLAN_SECMODE_WEP:
1282 		encryption = WL_ENC_WEP;
1283 		break;
1284 	case DLADM_WLAN_SECMODE_WPA:
1285 		return (0);
1286 	default:
1287 		return (DLADM_STATUS_NOTSUP);
1288 	}
1289 	return (i_dladm_wlan_set_ioctl(linkid, WL_ENCRYPTION, &encryption,
1290 	    sizeof (encryption)));
1291 }
1292 
1293 static dladm_status_t
1294 do_set_key(datalink_id_t linkid, dladm_wlan_key_t *keys,
1295     uint_t key_count)
1296 {
1297 	int			i;
1298 	wl_wep_key_t		*wkp;
1299 	wl_wep_key_tab_t	wepkey_tab;
1300 	dladm_wlan_key_t	*kp;
1301 
1302 	if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
1303 		return (DLADM_STATUS_BADARG);
1304 
1305 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
1306 	for (i = 0; i < MAX_NWEPKEYS; i++)
1307 		wepkey_tab[i].wl_wep_operation = WL_NUL;
1308 
1309 	for (i = 0; i < key_count; i++) {
1310 		kp = &keys[i];
1311 		if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
1312 			return (DLADM_STATUS_BADARG);
1313 		if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
1314 		    kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
1315 			return (DLADM_STATUS_BADARG);
1316 
1317 		wkp = &wepkey_tab[kp->wk_idx - 1];
1318 		wkp->wl_wep_operation = WL_ADD;
1319 		wkp->wl_wep_length = kp->wk_len;
1320 		(void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
1321 	}
1322 
1323 	return (i_dladm_wlan_set_ioctl(linkid, WL_WEP_KEY_TAB, &wepkey_tab,
1324 	    sizeof (wepkey_tab)));
1325 }
1326 
1327 static dladm_status_t
1328 do_set_essid(datalink_id_t linkid, dladm_wlan_essid_t *essid)
1329 {
1330 	wl_essid_t	iessid;
1331 
1332 	(void) memset(&iessid, 0, sizeof (essid));
1333 
1334 	if (essid != NULL && essid->we_bytes[0] != '\0') {
1335 		iessid.wl_essid_length = strlen(essid->we_bytes);
1336 		(void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
1337 		    sizeof (iessid.wl_essid_essid));
1338 	} else {
1339 		return (DLADM_STATUS_BADARG);
1340 	}
1341 	return (i_dladm_wlan_set_ioctl(linkid, WL_ESSID, &iessid,
1342 	    sizeof (iessid)));
1343 }
1344 
1345 static dladm_status_t
1346 do_set_channel(datalink_id_t linkid, dladm_wlan_channel_t *channel)
1347 {
1348 	wl_phy_conf_t phy_conf;
1349 
1350 	if (*channel > MAX_CHANNEL_NUM)
1351 		return (DLADM_STATUS_BADVAL);
1352 
1353 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
1354 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
1355 
1356 	return (i_dladm_wlan_set_ioctl(linkid, WL_PHY_CONFIG, &phy_conf,
1357 	    sizeof (phy_conf)));
1358 }
1359 
1360 static dladm_status_t
1361 do_set_createibss(datalink_id_t linkid, boolean_t *create_ibss)
1362 {
1363 	wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
1364 
1365 	return (i_dladm_wlan_set_ioctl(linkid, WL_CREATE_IBSS,
1366 	    &cr, sizeof (cr)));
1367 }
1368 
1369 static void
1370 generate_essid(dladm_wlan_essid_t *essid)
1371 {
1372 	srandom(gethrtime());
1373 	(void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
1374 	    random());
1375 }
1376 
1377 static dladm_status_t
1378 do_get_capability(datalink_id_t linkid, wldp_t *gbuf)
1379 {
1380 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_CAPABILITY));
1381 }
1382 
1383 static dladm_status_t
1384 do_get_wpamode(datalink_id_t linkid, wldp_t *gbuf)
1385 {
1386 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_WPA));
1387 }
1388 
1389 dladm_status_t
1390 dladm_wlan_wpa_get_sr(datalink_id_t linkid, dladm_wlan_ess_t *sr,
1391     uint_t escnt, uint_t *estot)
1392 {
1393 	int		i, n;
1394 	wldp_t 		*gbuf;
1395 	wl_wpa_ess_t	*es;
1396 	dladm_status_t	status;
1397 
1398 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1399 		return (DLADM_STATUS_NOMEM);
1400 
1401 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, WL_SCANRESULTS);
1402 
1403 	if (status == DLADM_STATUS_OK) {
1404 		es = (wl_wpa_ess_t *)(gbuf->wldp_buf);
1405 		n = (es->count > escnt) ? escnt : es->count;
1406 		for (i = 0; i < n; i ++) {
1407 			(void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
1408 			    DLADM_WLAN_BSSID_LEN);
1409 			sr[i].we_ssid_len = es->ess[i].ssid_len;
1410 			(void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
1411 			    es->ess[i].ssid_len);
1412 			sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
1413 			(void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
1414 			    es->ess[i].wpa_ie_len);
1415 			sr[i].we_freq = es->ess[i].freq;
1416 		}
1417 		*estot = n;
1418 	}
1419 
1420 	free(gbuf);
1421 	return (status);
1422 }
1423 
1424 dladm_status_t
1425 dladm_wlan_wpa_set_ie(datalink_id_t linkid, uint8_t *wpa_ie, uint_t wpa_ie_len)
1426 {
1427 	wl_wpa_ie_t *ie;
1428 	uint_t len;
1429 	dladm_status_t	status;
1430 
1431 	if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
1432 		return (DLADM_STATUS_BADARG);
1433 	len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
1434 	ie = malloc(len);
1435 	if (ie == NULL)
1436 		return (DLADM_STATUS_NOMEM);
1437 
1438 	(void) memset(ie, 0, len);
1439 	ie->wpa_ie_len = wpa_ie_len;
1440 	(void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
1441 
1442 	status = i_dladm_wlan_set_ioctl(linkid, WL_SETOPTIE, ie, len);
1443 	free(ie);
1444 
1445 	return (status);
1446 }
1447 
1448 dladm_status_t
1449 dladm_wlan_wpa_set_wpa(datalink_id_t linkid, boolean_t flag)
1450 {
1451 	wl_wpa_t	wpa;
1452 
1453 	wpa.wpa_flag = flag;
1454 	return (i_dladm_wlan_set_ioctl(linkid, WL_WPA, &wpa,
1455 	    sizeof (wl_wpa_t)));
1456 }
1457 
1458 dladm_status_t
1459 dladm_wlan_wpa_del_key(datalink_id_t linkid, uint_t key_idx,
1460     const dladm_wlan_bssid_t *addr)
1461 {
1462 	wl_del_key_t	wk;
1463 
1464 	wk.idk_keyix = key_idx;
1465 	if (addr != NULL)
1466 		(void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
1467 		    DLADM_WLAN_BSSID_LEN);
1468 
1469 	return (i_dladm_wlan_set_ioctl(linkid, WL_DELKEY, &wk,
1470 	    sizeof (wl_del_key_t)));
1471 }
1472 
1473 dladm_status_t
1474 dladm_wlan_wpa_set_key(datalink_id_t linkid, dladm_wlan_cipher_t cipher,
1475     const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq,
1476     uint_t key_idx, uint8_t *key, uint_t key_len)
1477 {
1478 	wl_key_t	wk;
1479 
1480 	(void) memset(&wk, 0, sizeof (wl_key_t));
1481 	switch (cipher) {
1482 	case DLADM_WLAN_CIPHER_WEP:
1483 		wk.ik_type = IEEE80211_CIPHER_WEP;
1484 		break;
1485 	case DLADM_WLAN_CIPHER_TKIP:
1486 		wk.ik_type = IEEE80211_CIPHER_TKIP;
1487 		break;
1488 	case DLADM_WLAN_CIPHER_AES_OCB:
1489 		wk.ik_type = IEEE80211_CIPHER_AES_OCB;
1490 		break;
1491 	case DLADM_WLAN_CIPHER_AES_CCM:
1492 		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
1493 		break;
1494 	case DLADM_WLAN_CIPHER_CKIP:
1495 		wk.ik_type = IEEE80211_CIPHER_CKIP;
1496 		break;
1497 	case DLADM_WLAN_CIPHER_NONE:
1498 		wk.ik_type = IEEE80211_CIPHER_NONE;
1499 		break;
1500 	default:
1501 		return (DLADM_STATUS_BADARG);
1502 	}
1503 	wk.ik_flags = IEEE80211_KEY_RECV;
1504 	if (set_tx) {
1505 		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
1506 		(void) memcpy(wk.ik_macaddr, addr->wb_bytes,
1507 		    DLADM_WLAN_BSSID_LEN);
1508 	} else
1509 		(void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
1510 	wk.ik_keyix = key_idx;
1511 	wk.ik_keylen = key_len;
1512 	(void) memcpy(&wk.ik_keyrsc, &seq, 6);	/* only use 48-bit of seq */
1513 	(void) memcpy(wk.ik_keydata, key, key_len);
1514 
1515 	return (i_dladm_wlan_set_ioctl(linkid, WL_KEY, &wk, sizeof (wl_key_t)));
1516 }
1517 
1518 dladm_status_t
1519 dladm_wlan_wpa_set_mlme(datalink_id_t linkid, dladm_wlan_mlme_op_t op,
1520     dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid)
1521 {
1522 	wl_mlme_t mlme;
1523 
1524 	(void) memset(&mlme, 0, sizeof (wl_mlme_t));
1525 	switch (op) {
1526 	case DLADM_WLAN_MLME_ASSOC:
1527 		mlme.im_op = IEEE80211_MLME_ASSOC;
1528 		break;
1529 	case DLADM_WLAN_MLME_DISASSOC:
1530 		mlme.im_op = IEEE80211_MLME_DISASSOC;
1531 		break;
1532 	default:
1533 		return (DLADM_STATUS_BADARG);
1534 	}
1535 	mlme.im_reason = reason;
1536 	if (bssid != NULL)
1537 		(void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
1538 		    DLADM_WLAN_BSSID_LEN);
1539 
1540 	return (i_dladm_wlan_set_ioctl(linkid, WL_MLME, &mlme,
1541 	    sizeof (wl_mlme_t)));
1542 }
1543 
1544 /*
1545  * routines of create instance
1546  */
1547 static scf_propertygroup_t *
1548 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
1549     const char *pg_name, const char *pg_type)
1550 {
1551 	scf_propertygroup_t *pg;
1552 
1553 	pg = scf_pg_create(handle);
1554 	if (pg == NULL)
1555 		return (NULL);
1556 
1557 	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
1558 		scf_pg_destroy(pg);
1559 		return (NULL);
1560 	}
1561 
1562 	return (pg);
1563 }
1564 
1565 static dladm_status_t
1566 add_new_property(scf_handle_t *handle, const char *prop_name,
1567     scf_type_t type, const char *val, scf_transaction_t *tx)
1568 {
1569 	scf_value_t *value = NULL;
1570 	scf_transaction_entry_t *entry = NULL;
1571 
1572 	entry = scf_entry_create(handle);
1573 	if (entry == NULL)
1574 		goto out;
1575 
1576 	value = scf_value_create(handle);
1577 	if (value == NULL)
1578 		goto out;
1579 
1580 	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
1581 		goto out;
1582 
1583 	if (scf_value_set_from_string(value, type, val) != 0)
1584 		goto out;
1585 
1586 	if (scf_entry_add_value(entry, value) != 0)
1587 		goto out;
1588 
1589 	return (DLADM_STATUS_OK);
1590 
1591 out:
1592 	if (value != NULL)
1593 		scf_value_destroy(value);
1594 	if (entry != NULL)
1595 		scf_entry_destroy(entry);
1596 
1597 	return (DLADM_STATUS_FAILED);
1598 }
1599 
1600 static dladm_status_t
1601 add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
1602     const char *pg_name, const char *flags)
1603 {
1604 	int			rv, size;
1605 	dladm_status_t		status = DLADM_STATUS_FAILED;
1606 	char			*command = NULL;
1607 	scf_transaction_t	*tran = NULL;
1608 	scf_propertygroup_t	*pg;
1609 
1610 	pg = add_property_group_to_instance(handle, instance,
1611 	    pg_name, SCF_GROUP_METHOD);
1612 	if (pg == NULL)
1613 		goto out;
1614 
1615 	tran = scf_transaction_create(handle);
1616 	if (tran == NULL)
1617 		goto out;
1618 
1619 	size = strlen(SVC_METHOD) + strlen("  ") + strlen(flags) + 1;
1620 	command = malloc(size);
1621 	if (command == NULL) {
1622 		status = DLADM_STATUS_NOMEM;
1623 		goto out;
1624 	}
1625 	(void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
1626 
1627 	do {
1628 		if (scf_transaction_start(tran, pg) != 0)
1629 			goto out;
1630 
1631 		if (add_new_property(handle, SCF_PROPERTY_EXEC,
1632 		    SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
1633 			goto out;
1634 		}
1635 
1636 		rv = scf_transaction_commit(tran);
1637 		switch (rv) {
1638 		case 1:
1639 			status = DLADM_STATUS_OK;
1640 			goto out;
1641 		case 0:
1642 			scf_transaction_destroy_children(tran);
1643 			if (scf_pg_update(pg) == -1) {
1644 				goto out;
1645 			}
1646 			break;
1647 		case -1:
1648 		default:
1649 			goto out;
1650 		}
1651 	} while (rv == 0);
1652 
1653 out:
1654 	if (tran != NULL) {
1655 		scf_transaction_destroy_children(tran);
1656 		scf_transaction_destroy(tran);
1657 	}
1658 
1659 	if (pg != NULL)
1660 		scf_pg_destroy(pg);
1661 
1662 	if (command != NULL)
1663 		free(command);
1664 
1665 	return (status);
1666 }
1667 
1668 static dladm_status_t
1669 do_create_instance(scf_handle_t *handle, scf_service_t *svc,
1670     const char *instance_name, const char *command)
1671 {
1672 	dladm_status_t status = DLADM_STATUS_FAILED;
1673 	char *buf;
1674 	ssize_t max_fmri_len;
1675 	scf_instance_t *instance;
1676 
1677 	instance = scf_instance_create(handle);
1678 	if (instance == NULL)
1679 		goto out;
1680 
1681 	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
1682 		if (scf_error() == SCF_ERROR_EXISTS)
1683 			/* Let the caller deal with the duplicate instance */
1684 			status = DLADM_STATUS_EXIST;
1685 		goto out;
1686 	}
1687 
1688 	if (add_pg_method(handle, instance, "start",
1689 	    command) != DLADM_STATUS_OK) {
1690 		goto out;
1691 	}
1692 
1693 	/* enabling the instance */
1694 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1695 	if ((buf = malloc(max_fmri_len + 1)) == NULL)
1696 		goto out;
1697 
1698 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1699 		if ((smf_disable_instance(buf, 0) != 0) ||
1700 		    (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
1701 			goto out;
1702 		}
1703 		status = DLADM_STATUS_OK;
1704 	}
1705 
1706 out:
1707 	if (instance != NULL)
1708 		scf_instance_destroy(instance);
1709 	return (status);
1710 }
1711 
1712 static dladm_status_t
1713 create_instance(const char *instance_name, const char *command)
1714 {
1715 	dladm_status_t status = DLADM_STATUS_FAILED;
1716 	scf_service_t *svc = NULL;
1717 	scf_handle_t *handle = NULL;
1718 
1719 	handle = scf_handle_create(SCF_VERSION);
1720 	if (handle == NULL)
1721 		goto out;
1722 
1723 	if (scf_handle_bind(handle) == -1)
1724 		goto out;
1725 
1726 	if ((svc = scf_service_create(handle)) == NULL)
1727 		goto out;
1728 
1729 	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
1730 	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
1731 		goto out;
1732 
1733 	status = do_create_instance(handle, svc, instance_name, command);
1734 
1735 out:
1736 	if (svc != NULL)
1737 		scf_service_destroy(svc);
1738 
1739 	if (handle != NULL) {
1740 		(void) scf_handle_unbind(handle);
1741 		scf_handle_destroy(handle);
1742 	}
1743 
1744 	return (status);
1745 }
1746 
1747 /*
1748  * routines of delete instance
1749  */
1750 #define	DEFAULT_TIMEOUT	60000000
1751 #define	INIT_WAIT_USECS	50000
1752 
1753 static void
1754 wait_until_disabled(scf_handle_t *handle, char *fmri)
1755 {
1756 	char		*state;
1757 	useconds_t	max;
1758 	useconds_t	usecs;
1759 	uint64_t	*cp = NULL;
1760 	scf_simple_prop_t *sp = NULL;
1761 
1762 	max = DEFAULT_TIMEOUT;
1763 
1764 	if (((sp = scf_simple_prop_get(handle, fmri, "stop",
1765 	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
1766 	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
1767 		max = (*cp) * 1000000;	/* convert to usecs */
1768 
1769 	if (sp != NULL)
1770 		scf_simple_prop_free(sp);
1771 
1772 	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
1773 		/* incremental wait */
1774 		usecs *= 2;
1775 		usecs = (usecs > max) ? max : usecs;
1776 
1777 		(void) usleep(usecs);
1778 
1779 		/* Check state after the wait */
1780 		if ((state = smf_get_state(fmri)) != NULL) {
1781 			if (strcmp(state, "disabled") == 0)
1782 				return;
1783 		}
1784 	}
1785 }
1786 
1787 static dladm_status_t
1788 delete_instance(const char *instance_name)
1789 {
1790 	dladm_status_t	status = DLADM_STATUS_FAILED;
1791 	char		*buf;
1792 	ssize_t		max_fmri_len;
1793 	scf_scope_t	*scope = NULL;
1794 	scf_service_t	*svc = NULL;
1795 	scf_handle_t	*handle = NULL;
1796 	scf_instance_t	*instance;
1797 
1798 	handle = scf_handle_create(SCF_VERSION);
1799 	if (handle == NULL)
1800 		goto out;
1801 
1802 	if (scf_handle_bind(handle) == -1)
1803 		goto out;
1804 
1805 	if ((scope = scf_scope_create(handle)) == NULL)
1806 		goto out;
1807 
1808 	if ((svc = scf_service_create(handle)) == NULL)
1809 		goto out;
1810 
1811 	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
1812 		goto out;
1813 
1814 	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
1815 		goto out;
1816 
1817 	instance = scf_instance_create(handle);
1818 	if (instance == NULL)
1819 		goto out;
1820 
1821 	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
1822 		scf_error_t scf_errnum = scf_error();
1823 
1824 		if (scf_errnum == SCF_ERROR_NOT_FOUND)
1825 			status = DLADM_STATUS_OK;
1826 
1827 		scf_instance_destroy(instance);
1828 		goto out;
1829 	}
1830 
1831 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1832 	if ((buf = malloc(max_fmri_len + 1)) == NULL) {
1833 		scf_instance_destroy(instance);
1834 		goto out;
1835 	}
1836 
1837 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1838 		char *state;
1839 
1840 		state = smf_get_state(buf);
1841 		if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
1842 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
1843 			if (smf_disable_instance(buf, 0) == 0) {
1844 				/*
1845 				 * Wait for some time till timeout to avoid
1846 				 * a race with scf_instance_delete() below.
1847 				 */
1848 				wait_until_disabled(handle, buf);
1849 			}
1850 		}
1851 	}
1852 
1853 	if (scf_instance_delete(instance) != 0) {
1854 		scf_instance_destroy(instance);
1855 		goto out;
1856 	}
1857 
1858 	scf_instance_destroy(instance);
1859 
1860 	status = DLADM_STATUS_OK;
1861 
1862 out:
1863 	if (svc != NULL)
1864 		scf_service_destroy(svc);
1865 
1866 	if (scope != NULL)
1867 		scf_scope_destroy(scope);
1868 
1869 	if (handle != NULL) {
1870 		(void) scf_handle_unbind(handle);
1871 		scf_handle_destroy(handle);
1872 	}
1873 
1874 	return (status);
1875 }
1876 
1877 static dladm_status_t
1878 wpa_instance_create(datalink_id_t linkid, void *key)
1879 {
1880 	dladm_status_t	status = DLADM_STATUS_FAILED;
1881 	char		*command = NULL;
1882 	char		*wk_name = ((dladm_wlan_key_t *)key)->wk_name;
1883 	int		size;
1884 	char		instance_name[MAXLINKNAMELEN];
1885 
1886 	/*
1887 	 * Use the link name as the instance name of the network/wpad service.
1888 	 */
1889 	status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name,
1890 	    sizeof (instance_name));
1891 	if (status != DLADM_STATUS_OK)
1892 		goto out;
1893 
1894 	size = strlen(instance_name) + strlen(" -i  -k ") + strlen(wk_name) + 1;
1895 	command = malloc(size);
1896 	if (command == NULL) {
1897 		status = DLADM_STATUS_NOMEM;
1898 		goto out;
1899 	}
1900 	(void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
1901 
1902 	status = create_instance(instance_name, command);
1903 	if (status == DLADM_STATUS_EXIST) {
1904 		/*
1905 		 * Delete the existing instance and create a new instance
1906 		 * with the supplied arguments.
1907 		 */
1908 		if ((status = delete_instance(instance_name)) ==
1909 		    DLADM_STATUS_OK) {
1910 			status = create_instance(instance_name, command);
1911 		}
1912 	}
1913 
1914 out:
1915 	if (command != NULL)
1916 		free(command);
1917 
1918 	return (status);
1919 }
1920 
1921 static dladm_status_t
1922 wpa_instance_delete(datalink_id_t linkid)
1923 {
1924 	char	instance_name[MAXLINKNAMELEN];
1925 
1926 	/*
1927 	 * Get the instance name of the network/wpad service (the same as
1928 	 * the link name).
1929 	 */
1930 	if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name,
1931 	    sizeof (instance_name)) != DLADM_STATUS_OK)
1932 		return (DLADM_STATUS_FAILED);
1933 
1934 	return (delete_instance(instance_name));
1935 }
1936