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