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