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