xref: /titanic_52/usr/src/lib/libdladm/common/libdlwlan.c (revision 65d61b8c5bb0da98e137e8d74245d8f53d690237)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <libintl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <stropts.h>
36 #include <libdevinfo.h>
37 #include <net/if.h>
38 #include <net/if_dl.h>
39 #include <net/if_types.h>
40 #include <libscf.h>
41 #include <libdlwlan.h>
42 #include <libdlwlan_impl.h>
43 #include <net/wpa.h>
44 
45 typedef struct val_desc {
46 	char		*vd_name;
47 	uint_t		vd_val;
48 } val_desc_t;
49 
50 struct prop_desc;
51 
52 typedef dladm_status_t	wl_pd_getf_t(int, wldp_t *, char **, uint_t *);
53 typedef dladm_status_t	wl_pd_setf_t(int, wldp_t *, val_desc_t *, uint_t);
54 typedef dladm_status_t	wl_pd_checkf_t(int, wldp_t *, struct prop_desc *,
55 			    char **, uint_t, val_desc_t **);
56 typedef struct prop_desc {
57 	char		*pd_name;
58 	val_desc_t	pd_defval;
59 	val_desc_t	*pd_modval;
60 	uint_t		pd_nmodval;
61 	wl_pd_setf_t	*pd_set;
62 	wl_pd_getf_t	*pd_getmod;
63 	wl_pd_getf_t	*pd_get;
64 	wl_pd_checkf_t	*pd_check;
65 } prop_desc_t;
66 
67 static int	wpa_instance_create(const char *, void *);
68 static int	wpa_instance_delete(const char *);
69 
70 static int 	do_get_bsstype(int, wldp_t *);
71 static int 	do_get_essid(int, wldp_t *);
72 static int 	do_get_bssid(int, wldp_t *);
73 static int 	do_get_signal(int, wldp_t *);
74 static int 	do_get_encryption(int, wldp_t *);
75 static int 	do_get_authmode(int, wldp_t *);
76 static int 	do_get_linkstatus(int, wldp_t *);
77 static int	do_get_esslist(int, wldp_t *);
78 static int 	do_get_rate(int, wldp_t *);
79 static int	do_get_phyconf(int, wldp_t *);
80 static int	do_get_powermode(int, wldp_t *);
81 static int	do_get_radio(int, wldp_t *);
82 static int	do_get_mode(int, wldp_t *);
83 static int	do_get_capability(int, wldp_t *);
84 static int	do_get_wpamode(int, wldp_t *);
85 
86 static int	do_set_bsstype(int, wldp_t *, dladm_wlan_bsstype_t *);
87 static int	do_set_authmode(int, wldp_t *, dladm_wlan_auth_t *);
88 static int	do_set_encryption(int, wldp_t *, dladm_wlan_secmode_t *);
89 static int	do_set_essid(int, wldp_t *, dladm_wlan_essid_t *);
90 static int	do_set_createibss(int, wldp_t *, boolean_t *);
91 static int	do_set_key(int, wldp_t *, dladm_wlan_key_t *, uint_t);
92 static int	do_set_rate(int, wldp_t *, dladm_wlan_rates_t *);
93 static int	do_set_powermode(int, wldp_t *, dladm_wlan_powermode_t *);
94 static int	do_set_radio(int, wldp_t *, dladm_wlan_radio_t *);
95 static int	do_set_channel(int, wldp_t *, dladm_wlan_channel_t *);
96 
97 static int	open_link(const char *);
98 static int	do_scan(int, wldp_t *);
99 static int	do_disconnect(const char *, int, wldp_t *);
100 static boolean_t find_val_by_name(const char *, val_desc_t *, uint_t, uint_t *);
101 static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **);
102 static void	generate_essid(dladm_wlan_essid_t *);
103 
104 static dladm_status_t	dladm_wlan_wlresult2status(wldp_t *);
105 
106 static wl_pd_getf_t	do_get_rate_mod, do_get_rate_prop, do_get_channel_prop,
107 			do_get_powermode_prop, do_get_radio_prop;
108 static wl_pd_setf_t 	do_set_rate_prop, do_set_powermode_prop,
109 			do_set_radio_prop;
110 static wl_pd_checkf_t	do_check_prop, do_check_rate;
111 
112 static val_desc_t	linkstatus_vals[] = {
113 	{ "disconnected", 	DLADM_WLAN_LINKSTATUS_DISCONNECTED	},
114 	{ "connected",		DLADM_WLAN_LINKSTATUS_CONNECTED	}
115 };
116 
117 static val_desc_t 	secmode_vals[] = {
118 	{ "none",	DLADM_WLAN_SECMODE_NONE		},
119 	{ "wep",	DLADM_WLAN_SECMODE_WEP		},
120 	{ "wpa",	DLADM_WLAN_SECMODE_WPA		}
121 };
122 
123 static val_desc_t 	strength_vals[] = {
124 	{ "very weak",	DLADM_WLAN_STRENGTH_VERY_WEAK 	},
125 	{ "weak",	DLADM_WLAN_STRENGTH_WEAK		},
126 	{ "good", 	DLADM_WLAN_STRENGTH_GOOD		},
127 	{ "very good",	DLADM_WLAN_STRENGTH_VERY_GOOD	},
128 	{ "excellent",	DLADM_WLAN_STRENGTH_EXCELLENT	}
129 };
130 
131 static val_desc_t	mode_vals[] = {
132 	{ "a",		DLADM_WLAN_MODE_80211A		},
133 	{ "b",		DLADM_WLAN_MODE_80211B		},
134 	{ "g",		DLADM_WLAN_MODE_80211G		},
135 };
136 
137 static val_desc_t	auth_vals[] = {
138 	{ "open",	DLADM_WLAN_AUTH_OPEN			},
139 	{ "shared",	DLADM_WLAN_AUTH_SHARED		}
140 };
141 
142 static val_desc_t	bsstype_vals[] = {
143 	{ "bss",	DLADM_WLAN_BSSTYPE_BSS		},
144 	{ "ibss",	DLADM_WLAN_BSSTYPE_IBSS		},
145 	{ "any",	DLADM_WLAN_BSSTYPE_ANY		}
146 };
147 
148 static val_desc_t	radio_vals[] = {
149 	{ "on",		DLADM_WLAN_RADIO_ON			},
150 	{ "off",	DLADM_WLAN_RADIO_OFF			}
151 };
152 
153 static val_desc_t	powermode_vals[] = {
154 	{ "off",	DLADM_WLAN_PM_OFF			},
155 	{ "fast",	DLADM_WLAN_PM_FAST			},
156 	{ "max",	DLADM_WLAN_PM_MAX			}
157 };
158 
159 #define	VALCNT(vals)	(sizeof ((vals)) / sizeof (val_desc_t))
160 static	prop_desc_t	prop_table[] = {
161 
162 	{ "channel",	{ NULL, 0 }, NULL, 0,
163 	    NULL, NULL, do_get_channel_prop, do_check_prop},
164 
165 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF }, powermode_vals,
166 	    VALCNT(powermode_vals),
167 	    do_set_powermode_prop, NULL,
168 	    do_get_powermode_prop, do_check_prop},
169 
170 	{ "radio", 	{ "on", DLADM_WLAN_RADIO_ON }, radio_vals,
171 	    VALCNT(radio_vals),
172 	    do_set_radio_prop, NULL,
173 	    do_get_radio_prop, do_check_prop},
174 
175 	{ "speed",	{ "", 0 }, NULL, 0,
176 	    do_set_rate_prop, do_get_rate_mod,
177 	    do_get_rate_prop, do_check_rate}
178 };
179 /*
180  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
181  * rates to be retrieved. However, we cannot increase it at this
182  * time because it will break binary comatibility with unbundled
183  * WiFi drivers and utilities. So for now we define an additional
184  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
185  */
186 #define	MAX_SUPPORT_RATES	64
187 #define	DLADM_WLAN_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
188 #define	IS_CONNECTED(gbuf) \
189 	((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED))
190 
191 static dladm_status_t
192 dladm_wlan_wlresult2status(wldp_t *gbuf)
193 {
194 	switch (gbuf->wldp_result) {
195 	case WL_SUCCESS:
196 		return (DLADM_STATUS_OK);
197 
198 	case WL_NOTSUPPORTED:
199 	case WL_LACK_FEATURE:
200 		return (DLADM_STATUS_NOTSUP);
201 
202 	case WL_READONLY:
203 		return (DLADM_STATUS_PROPRDONLY);
204 
205 	default:
206 		break;
207 	}
208 
209 	return (DLADM_STATUS_FAILED);
210 }
211 
212 static int
213 open_link(const char *link)
214 {
215 	char	linkname[MAXPATHLEN];
216 	wldp_t	*gbuf;
217 	int	fd;
218 
219 	if (link == NULL)
220 		return (-1);
221 
222 	(void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link);
223 	if ((fd = open(linkname, O_RDWR)) < 0)
224 		return (-1);
225 
226 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
227 		(void) close(fd);
228 		return (-1);
229 	}
230 
231 	/*
232 	 * Check to see if the link is wireless.
233 	 */
234 	if (do_get_bsstype(fd, gbuf) < 0) {
235 		free(gbuf);
236 		(void) close(fd);
237 		return (-1);
238 	}
239 
240 	free(gbuf);
241 	return (fd);
242 }
243 
244 static dladm_wlan_mode_t
245 do_convert_mode(wl_phy_conf_t *phyp)
246 {
247 	switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) {
248 	case WL_ERP:
249 		return (DLADM_WLAN_MODE_80211G);
250 	case WL_OFDM:
251 		return (DLADM_WLAN_MODE_80211A);
252 	case WL_DSSS:
253 	case WL_FHSS:
254 		return (DLADM_WLAN_MODE_80211B);
255 	default:
256 		break;
257 	}
258 
259 	return (DLADM_WLAN_MODE_NONE);
260 }
261 
262 static boolean_t
263 do_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp)
264 {
265 	wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf;
266 	wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
267 
268 	switch (wlfp->wl_fhss_subtype) {
269 	case WL_FHSS:
270 	case WL_DSSS:
271 	case WL_IRBASE:
272 	case WL_HRDS:
273 	case WL_ERP:
274 		*channelp = wlfp->wl_fhss_channel;
275 		break;
276 	case WL_OFDM:
277 		*channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency);
278 		break;
279 	default:
280 		return (B_FALSE);
281 	}
282 	return (B_TRUE);
283 }
284 
285 #define	IEEE80211_RATE	0x7f
286 static void
287 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp)
288 {
289 	int		i;
290 
291 	(void) memset(attrp, 0, sizeof (*attrp));
292 
293 	(void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN,
294 	    "%s", wlp->wl_ess_conf_essid.wl_essid_essid);
295 	attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
296 
297 	(void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid,
298 	    DLADM_WLAN_BSSID_LEN);
299 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
300 
301 	attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled ==
302 	    WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE);
303 	if (wlp->wl_ess_conf_reserved[0] > 0)
304 		attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
305 	attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
306 
307 	attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ?
308 	    DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS);
309 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
310 
311 	attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ?
312 	    DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED);
313 	attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
314 
315 	attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
316 	attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
317 
318 	attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
319 	attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
320 
321 	for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
322 		wlp->wl_supported_rates[i] &= IEEE80211_RATE;
323 		if (wlp->wl_supported_rates[i] > attrp->wa_speed)
324 			attrp->wa_speed = wlp->wl_supported_rates[i];
325 	}
326 	if (attrp->wa_speed > 0)
327 		attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
328 
329 	if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf,
330 	    &attrp->wa_channel))
331 		attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL;
332 }
333 
334 dladm_status_t
335 dladm_wlan_scan(const char *link, void *arg,
336     boolean_t (*func)(void *, dladm_wlan_attr_t *))
337 {
338 	int			fd, i;
339 	uint32_t		count;
340 	wl_ess_conf_t		*wlp;
341 	wldp_t 			*gbuf;
342 	dladm_wlan_attr_t	wlattr;
343 	dladm_status_t		status;
344 	boolean_t		connected;
345 
346 	if ((fd = open_link(link)) < 0)
347 		return (DLADM_STATUS_LINKINVAL);
348 
349 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
350 		status = DLADM_STATUS_NOMEM;
351 		goto done;
352 	}
353 
354 	if (do_get_linkstatus(fd, gbuf) < 0) {
355 		status = DLADM_STATUS_FAILED;
356 		goto done;
357 	}
358 	connected = IS_CONNECTED(gbuf);
359 
360 	if (do_scan(fd, gbuf) < 0) {
361 		status = DLADM_STATUS_FAILED;
362 		goto done;
363 	}
364 
365 	if (func == NULL) {
366 		status = DLADM_STATUS_OK;
367 		goto done;
368 	}
369 
370 	if (do_get_esslist(fd, gbuf) < 0) {
371 		status = DLADM_STATUS_FAILED;
372 		goto done;
373 	}
374 
375 	wlp = ((wl_ess_list_t *)gbuf->wldp_buf)->wl_ess_list_ess;
376 	count = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
377 
378 	for (i = 0; i < count; i++, wlp++) {
379 		fill_wlan_attr(wlp, &wlattr);
380 		if (!func(arg, &wlattr))
381 			break;
382 	}
383 
384 	if (!connected) {
385 		if (do_get_linkstatus(fd, gbuf) < 0) {
386 			status = DLADM_STATUS_FAILED;
387 			goto done;
388 		}
389 		if (IS_CONNECTED(gbuf))
390 			(void) do_disconnect(link, fd, gbuf);
391 	}
392 
393 	status = DLADM_STATUS_OK;
394 done:
395 	free(gbuf);
396 	(void) close(fd);
397 	return (status);
398 }
399 
400 /*
401  * Structures used in building the list of eligible WLANs to connect to.
402  * Specifically, `connect_state' has the WLAN attributes that must be matched
403  * (in `cs_attr') and a growing list of WLANs that matched those attributes
404  * chained through `cs_list'.  Each element in the list is of type `attr_node'
405  * and has the matching WLAN's attributes and a pointer to the next element.
406  * For convenience, `cs_count' tracks the number of elements in the list.
407  */
408 typedef struct attr_node {
409 	dladm_wlan_attr_t	an_attr;
410 	struct attr_node	*an_next;
411 } attr_node_t;
412 
413 typedef struct connect_state {
414 	dladm_wlan_attr_t	*cs_attr;
415 	uint_t			cs_count;
416 	attr_node_t		*cs_list;
417 } connect_state_t;
418 
419 /*
420  * Compare two sets of WLAN attributes.  For now, we only consider strength
421  * and speed (in that order), which matches the documented default policy for
422  * dladm_wlan_connect().
423  */
424 static int
425 attr_compare(const void *p1, const void *p2)
426 {
427 	dladm_wlan_attr_t *attrp1, *attrp2;
428 
429 	attrp1 = (*(dladm_wlan_attr_t **)p1);
430 	attrp2 = (*(dladm_wlan_attr_t **)p2);
431 
432 	if (attrp1->wa_strength < attrp2->wa_strength)
433 		return (1);
434 
435 	if (attrp1->wa_strength > attrp2->wa_strength)
436 		return (-1);
437 
438 	return (attrp2->wa_speed - attrp1->wa_speed);
439 }
440 
441 /*
442  * Callback function used by dladm_wlan_connect() to filter out unwanted
443  * WLANs when scanning for available WLANs.  Always returns B_TRUE to
444  * continue the scan.
445  */
446 static boolean_t
447 connect_cb(void *arg, dladm_wlan_attr_t *attrp)
448 {
449 	attr_node_t		*nodep;
450 	dladm_wlan_attr_t	*fattrp;
451 	connect_state_t		*statep = (connect_state_t *)arg;
452 
453 	fattrp = statep->cs_attr;
454 	if (fattrp == NULL)
455 		goto append;
456 
457 	if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
458 		return (B_TRUE);
459 
460 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 &&
461 	    strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes,
462 	    DLADM_WLAN_MAX_ESSID_LEN) != 0)
463 		return (B_TRUE);
464 
465 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
466 	    fattrp->wa_secmode != attrp->wa_secmode)
467 		return (B_TRUE);
468 
469 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 &&
470 	    fattrp->wa_mode != attrp->wa_mode)
471 		return (B_TRUE);
472 
473 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 &&
474 	    fattrp->wa_strength != attrp->wa_strength)
475 		return (B_TRUE);
476 
477 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 &&
478 	    fattrp->wa_speed != attrp->wa_speed)
479 		return (B_TRUE);
480 
481 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) {
482 		attrp->wa_auth = fattrp->wa_auth;
483 		attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
484 	}
485 
486 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
487 	    fattrp->wa_bsstype != attrp->wa_bsstype)
488 		return (B_TRUE);
489 
490 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 &&
491 	    memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes,
492 	    DLADM_WLAN_BSSID_LEN) != 0)
493 		return (B_TRUE);
494 append:
495 	nodep = malloc(sizeof (attr_node_t));
496 	if (nodep == NULL)
497 		return (B_TRUE);
498 
499 	(void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t));
500 	nodep->an_next = statep->cs_list;
501 	statep->cs_list = nodep;
502 	statep->cs_count++;
503 
504 	return (B_TRUE);
505 }
506 
507 #define	IEEE80211_C_WPA		0x01800000
508 
509 static dladm_status_t
510 do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp,
511     boolean_t create_ibss, void *keys, uint_t key_count, int timeout)
512 {
513 	dladm_wlan_secmode_t		secmode;
514 	dladm_wlan_auth_t		authmode;
515 	dladm_wlan_bsstype_t		bsstype;
516 	dladm_wlan_essid_t		essid;
517 	boolean_t			essid_valid = B_FALSE;
518 	dladm_wlan_channel_t		channel;
519 	hrtime_t			start;
520 	wl_capability_t			*caps;
521 
522 	if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) {
523 		channel = attrp->wa_channel;
524 		if (do_set_channel(fd, gbuf, &channel) < 0)
525 			goto fail;
526 	}
527 
528 	secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ?
529 	    attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE;
530 
531 	if (do_set_encryption(fd, gbuf, &secmode) < 0)
532 		goto fail;
533 
534 	authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ?
535 	    attrp->wa_auth : DLADM_WLAN_AUTH_OPEN;
536 
537 	if (do_set_authmode(fd, gbuf, &authmode) < 0)
538 		goto fail;
539 
540 	bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ?
541 	    attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS;
542 
543 	if (do_set_bsstype(fd, gbuf, &bsstype) < 0)
544 		goto fail;
545 
546 	if (secmode == DLADM_WLAN_SECMODE_WEP) {
547 		if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS)
548 			return (DLADM_STATUS_BADARG);
549 		if (do_set_key(fd, gbuf, keys, key_count) < 0)
550 			goto fail;
551 	} else if (secmode == DLADM_WLAN_SECMODE_WPA) {
552 		if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS)
553 			return (DLADM_STATUS_BADARG);
554 		if (do_get_capability(fd, gbuf) < 0)
555 			goto fail;
556 		caps = (wl_capability_t *)(gbuf->wldp_buf);
557 		if ((caps->caps & IEEE80211_C_WPA) == 0)
558 			return (DLADM_STATUS_NOTSUP);
559 	}
560 
561 	if (create_ibss) {
562 		if (do_set_channel(fd, gbuf, &channel) < 0)
563 			goto fail;
564 
565 		if (do_set_createibss(fd, gbuf, &create_ibss) < 0)
566 			goto fail;
567 
568 		if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) {
569 			generate_essid(&essid);
570 			essid_valid = B_TRUE;
571 		}
572 	}
573 
574 	if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) {
575 		essid = attrp->wa_essid;
576 		essid_valid = B_TRUE;
577 	}
578 
579 	if (!essid_valid)
580 		return (DLADM_STATUS_FAILED);
581 	if (do_set_essid(fd, gbuf, &essid) < 0)
582 		goto fail;
583 
584 	/*
585 	 * Because wpa daemon needs getting essid from driver,
586 	 * we need call do_set_essid() first, then call wpa_instance_create().
587 	 */
588 	if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL)
589 		(void) wpa_instance_create(link, keys);
590 
591 	start = gethrtime();
592 	for (;;) {
593 		if (do_get_linkstatus(fd, gbuf) < 0)
594 			goto fail;
595 
596 		if (IS_CONNECTED(gbuf))
597 			break;
598 
599 		(void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE);
600 		if ((timeout >= 0) && (gethrtime() - start) /
601 		    NANOSEC >= timeout)
602 			return (DLADM_STATUS_TIMEDOUT);
603 	}
604 	return (DLADM_STATUS_OK);
605 fail:
606 	return (dladm_wlan_wlresult2status(gbuf));
607 }
608 
609 dladm_status_t
610 dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp,
611     int timeout, void *keys, uint_t key_count, uint_t flags)
612 {
613 	int			fd, i;
614 	wldp_t 			*gbuf = NULL;
615 	connect_state_t		state = {0, NULL, NULL};
616 	attr_node_t		*nodep = NULL;
617 	boolean_t		create_ibss, set_authmode;
618 	dladm_wlan_attr_t	**wl_list = NULL;
619 	dladm_status_t		status = DLADM_STATUS_FAILED;
620 
621 	if ((fd = open_link(link)) < 0)
622 		return (DLADM_STATUS_LINKINVAL);
623 
624 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
625 		status = DLADM_STATUS_NOMEM;
626 		goto done;
627 	}
628 
629 	if (do_get_linkstatus(fd, gbuf) < 0) {
630 		status = DLADM_STATUS_FAILED;
631 		goto done;
632 	}
633 
634 	if (IS_CONNECTED(gbuf)) {
635 		status = DLADM_STATUS_ISCONN;
636 		goto done;
637 	}
638 
639 	set_authmode = ((attrp != NULL) &&
640 	    (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0);
641 	create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 &&
642 	    attrp != NULL &&
643 	    (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
644 	    attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS);
645 
646 	if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 ||
647 	    (create_ibss && attrp != NULL &&
648 	    (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) {
649 		status = do_connect(link, fd, gbuf, attrp,
650 		    create_ibss, keys, key_count, timeout);
651 		goto done;
652 	}
653 
654 	state.cs_attr = attrp;
655 	state.cs_list = NULL;
656 	state.cs_count = 0;
657 
658 	status = dladm_wlan_scan(link, &state, connect_cb);
659 	if (status != DLADM_STATUS_OK)
660 		goto done;
661 
662 	if (state.cs_count == 0) {
663 		if (!create_ibss) {
664 			status = DLADM_STATUS_NOTFOUND;
665 			goto done;
666 		}
667 		status = do_connect(link, fd, gbuf, attrp, create_ibss,
668 		    keys, key_count, timeout);
669 		goto done;
670 	}
671 
672 	wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *));
673 	if (wl_list == NULL) {
674 		status = DLADM_STATUS_NOMEM;
675 		goto done;
676 	}
677 
678 	nodep = state.cs_list;
679 	for (i = 0; i < state.cs_count; i++) {
680 		wl_list[i] = &nodep->an_attr;
681 		nodep = nodep->an_next;
682 	}
683 	qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
684 	    attr_compare);
685 
686 	for (i = 0; i < state.cs_count; i++) {
687 		dladm_wlan_attr_t	*ap = wl_list[i];
688 
689 		status = do_connect(link, fd, gbuf, ap, create_ibss, keys,
690 		    key_count, timeout);
691 		if (status == DLADM_STATUS_OK)
692 			break;
693 
694 		if (!set_authmode) {
695 			ap->wa_auth = DLADM_WLAN_AUTH_SHARED;
696 			ap->wa_valid |= DLADM_WLAN_ATTR_AUTH;
697 			status = do_connect(link, fd, gbuf, ap, create_ibss,
698 			    keys, key_count, timeout);
699 			if (status == DLADM_STATUS_OK)
700 				break;
701 		}
702 	}
703 done:
704 	if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
705 		(void) do_disconnect(link, fd, gbuf);
706 
707 	while (state.cs_list != NULL) {
708 		nodep = state.cs_list;
709 		state.cs_list = nodep->an_next;
710 		free(nodep);
711 	}
712 	free(gbuf);
713 	free(wl_list);
714 	(void) close(fd);
715 	return (status);
716 }
717 
718 dladm_status_t
719 dladm_wlan_disconnect(const char *link)
720 {
721 	int		fd;
722 	wldp_t		*gbuf;
723 	dladm_status_t	status;
724 
725 	if ((fd = open_link(link)) < 0)
726 		return (DLADM_STATUS_BADARG);
727 
728 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
729 		status = DLADM_STATUS_NOMEM;
730 		goto done;
731 	}
732 
733 	if (do_get_linkstatus(fd, gbuf) < 0) {
734 		status = DLADM_STATUS_FAILED;
735 		goto done;
736 	}
737 
738 	if (!IS_CONNECTED(gbuf)) {
739 		status = DLADM_STATUS_NOTCONN;
740 		goto done;
741 	}
742 
743 	if (do_disconnect(link, fd, gbuf) < 0) {
744 		status = DLADM_STATUS_FAILED;
745 		goto done;
746 	}
747 
748 	if (do_get_linkstatus(fd, gbuf) < 0) {
749 		status = DLADM_STATUS_FAILED;
750 		goto done;
751 	}
752 
753 	if (IS_CONNECTED(gbuf)) {
754 		status = DLADM_STATUS_FAILED;
755 		goto done;
756 	}
757 
758 	status = DLADM_STATUS_OK;
759 done:
760 	free(gbuf);
761 	(void) close(fd);
762 	return (status);
763 }
764 
765 typedef struct dladm_wlan_linkname {
766 	char			wl_name[MAXNAMELEN];
767 	struct dladm_wlan_linkname	*wl_next;
768 } dladm_wlan_linkname_t;
769 
770 typedef struct dladm_wlan_walk {
771 	dladm_wlan_linkname_t	*ww_list;
772 	dladm_status_t		ww_status;
773 } dladm_wlan_walk_t;
774 
775 /* ARGSUSED */
776 static int
777 append_linkname(di_node_t node, di_minor_t minor, void *arg)
778 {
779 	dladm_wlan_walk_t		*statep = arg;
780 	dladm_wlan_linkname_t	**lastp = &statep->ww_list;
781 	dladm_wlan_linkname_t	*wlp = *lastp;
782 	char			name[MAXNAMELEN];
783 
784 	(void) snprintf(name, MAXNAMELEN, "%s%d",
785 	    di_driver_name(node), di_instance(node));
786 
787 	while (wlp != NULL) {
788 		if (strcmp(wlp->wl_name, name) == 0)
789 			return (DI_WALK_CONTINUE);
790 
791 		lastp = &wlp->wl_next;
792 		wlp = wlp->wl_next;
793 	}
794 	if ((wlp = malloc(sizeof (*wlp))) == NULL) {
795 		statep->ww_status = DLADM_STATUS_NOMEM;
796 		return (DI_WALK_CONTINUE);
797 	}
798 
799 	(void) strlcpy(wlp->wl_name, name, MAXNAMELEN);
800 	wlp->wl_next = NULL;
801 	*lastp = wlp;
802 
803 	return (DI_WALK_CONTINUE);
804 }
805 
806 dladm_status_t
807 dladm_wlan_walk(void *arg, boolean_t (*func)(void *, const char *))
808 {
809 	di_node_t		root;
810 	dladm_wlan_walk_t		state;
811 	dladm_wlan_linkname_t	*wlp, *wlp_next;
812 	boolean_t		cont = B_TRUE;
813 
814 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
815 		return (DLADM_STATUS_FAILED);
816 
817 	state.ww_list = NULL;
818 	state.ww_status = DLADM_STATUS_OK;
819 	(void) di_walk_minor(root, DDI_NT_NET_WIFI, DI_CHECK_ALIAS,
820 	    &state, append_linkname);
821 	di_fini(root);
822 
823 	for (wlp = state.ww_list; wlp != NULL; wlp = wlp_next) {
824 		/*
825 		 * NOTE: even if (*func)() returns B_FALSE, the loop continues
826 		 * since all memory must be freed.
827 		 */
828 		if (cont)
829 			cont = (*func)(arg, wlp->wl_name);
830 		wlp_next = wlp->wl_next;
831 		free(wlp);
832 	}
833 	return (state.ww_status);
834 }
835 
836 dladm_status_t
837 dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp)
838 {
839 	int			fd;
840 	wldp_t			*gbuf;
841 	wl_rssi_t		signal;
842 	wl_bss_type_t		bsstype;
843 	wl_authmode_t		authmode;
844 	wl_encryption_t		encryption;
845 	wl_rates_t		*ratesp;
846 	dladm_wlan_attr_t	*wl_attrp;
847 	dladm_status_t		status = DLADM_STATUS_FAILED;
848 
849 	if (attrp == NULL)
850 		return (DLADM_STATUS_BADARG);
851 
852 	if ((fd = open_link(link)) < 0)
853 		return (DLADM_STATUS_LINKINVAL);
854 
855 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
856 		status = DLADM_STATUS_NOMEM;
857 		goto done;
858 	}
859 
860 	(void) memset(attrp, 0, sizeof (*attrp));
861 	wl_attrp = &attrp->la_wlan_attr;
862 
863 	if (do_get_linkstatus(fd, gbuf) < 0)
864 		goto done;
865 
866 	attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS;
867 	if (!IS_CONNECTED(gbuf)) {
868 		attrp->la_status = DLADM_WLAN_LINKSTATUS_DISCONNECTED;
869 	} else {
870 		attrp->la_status = DLADM_WLAN_LINKSTATUS_CONNECTED;
871 	}
872 
873 	if (do_get_essid(fd, gbuf) < 0)
874 		goto done;
875 
876 	(void) strlcpy(wl_attrp->wa_essid.we_bytes,
877 	    ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
878 	    DLADM_WLAN_MAX_ESSID_LEN);
879 
880 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
881 
882 	if (do_get_bssid(fd, gbuf) < 0)
883 		goto done;
884 
885 	(void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf,
886 	    DLADM_WLAN_BSSID_LEN);
887 
888 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
889 
890 	if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) {
891 		attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
892 		status = DLADM_STATUS_OK;
893 		goto done;
894 	}
895 
896 	if (do_get_encryption(fd, gbuf) < 0)
897 		goto done;
898 
899 	encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
900 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
901 
902 	switch (encryption) {
903 	case WL_NOENCRYPTION:
904 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
905 		break;
906 	case WL_ENC_WEP:
907 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
908 		break;
909 	case WL_ENC_WPA:
910 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
911 		break;
912 	default:
913 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE;
914 		break;
915 	}
916 
917 	if (do_get_signal(fd, gbuf) < 0)
918 		goto done;
919 
920 	signal = *(wl_rssi_t *)(gbuf->wldp_buf);
921 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
922 	wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
923 
924 	if (do_get_rate(fd, gbuf) < 0)
925 		goto done;
926 
927 	ratesp = (wl_rates_t *)(gbuf->wldp_buf);
928 	if (ratesp->wl_rates_num > 0) {
929 		uint_t	i, r = 0;
930 
931 		for (i = 0; i < ratesp->wl_rates_num; i++) {
932 			if (ratesp->wl_rates_rates[i] > r)
933 				r = ratesp->wl_rates_rates[i];
934 		}
935 		wl_attrp->wa_speed = r;
936 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
937 	}
938 
939 	if (do_get_authmode(fd, gbuf) < 0)
940 		goto done;
941 
942 	authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
943 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
944 
945 	switch (authmode) {
946 	case WL_OPENSYSTEM:
947 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
948 		break;
949 	case WL_SHAREDKEY:
950 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
951 		break;
952 	default:
953 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
954 		break;
955 	}
956 
957 	if (do_get_bsstype(fd, gbuf) < 0)
958 		goto done;
959 
960 	bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
961 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
962 
963 	switch (bsstype) {
964 	case WL_BSS_BSS:
965 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
966 		break;
967 	case WL_BSS_IBSS:
968 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
969 		break;
970 	case WL_BSS_ANY:
971 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
972 		break;
973 	default:
974 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
975 		break;
976 	}
977 
978 	if (do_get_mode(fd, gbuf) < 0)
979 		goto done;
980 
981 	wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf));
982 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
983 	if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
984 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
985 
986 	attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
987 	status = DLADM_STATUS_OK;
988 
989 done:
990 	free(gbuf);
991 	(void) close(fd);
992 	return (status);
993 }
994 
995 boolean_t
996 dladm_wlan_is_valid(const char *link)
997 {
998 	int fd = open_link(link);
999 
1000 	if (fd < 0)
1001 		return (B_FALSE);
1002 
1003 	(void) close(fd);
1004 	return (B_TRUE);
1005 }
1006 
1007 /* ARGSUSED */
1008 static dladm_status_t
1009 do_check_prop(int fd, wldp_t *guf, prop_desc_t *pdp, char **prop_val,
1010     uint_t val_cnt, val_desc_t **vdpp)
1011 {
1012 	int		i;
1013 	val_desc_t	*vdp;
1014 
1015 	if (pdp->pd_nmodval == 0)
1016 		return (DLADM_STATUS_PROPRDONLY);
1017 
1018 	if (val_cnt != 1)
1019 		return (DLADM_STATUS_BADVALCNT);
1020 
1021 	for (i = 0; i < pdp->pd_nmodval; i++)
1022 		if (strcasecmp(*prop_val, pdp->pd_modval[i].vd_name) == 0)
1023 			break;
1024 
1025 	if (i == pdp->pd_nmodval)
1026 		return (DLADM_STATUS_BADVAL);
1027 
1028 	vdp = malloc(sizeof (val_desc_t));
1029 	if (vdp == NULL)
1030 		return (DLADM_STATUS_NOMEM);
1031 
1032 	(void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t));
1033 	*vdpp = vdp;
1034 	return (DLADM_STATUS_OK);
1035 }
1036 
1037 static dladm_status_t
1038 do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp,
1039     char **prop_val, uint_t val_cnt)
1040 {
1041 	dladm_status_t	status;
1042 	val_desc_t	*vdp = NULL;
1043 	uint_t		cnt;
1044 
1045 	if (pdp->pd_set == NULL)
1046 		return (DLADM_STATUS_PROPRDONLY);
1047 
1048 	if (prop_val != NULL) {
1049 		status = pdp->pd_check(fd, gbuf, pdp, prop_val,
1050 		    val_cnt, &vdp);
1051 
1052 		if (status != DLADM_STATUS_OK)
1053 			return (status);
1054 
1055 		cnt = val_cnt;
1056 	} else {
1057 		if (pdp->pd_defval.vd_name == NULL)
1058 			return (DLADM_STATUS_NOTSUP);
1059 
1060 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
1061 			return (DLADM_STATUS_NOMEM);
1062 
1063 		*vdp = pdp->pd_defval;
1064 		cnt = 1;
1065 	}
1066 	status = pdp->pd_set(fd, gbuf, vdp, cnt);
1067 	if (status == DLADM_STATUS_OK) {
1068 		/*
1069 		 * Some ioctls return 0 but store error code in
1070 		 * wldp_result. Need to fix them.
1071 		 */
1072 		if (gbuf->wldp_result != WL_SUCCESS)
1073 			status = dladm_wlan_wlresult2status(gbuf);
1074 	}
1075 	free(vdp);
1076 	return (status);
1077 }
1078 
1079 dladm_status_t
1080 dladm_wlan_set_prop(const char *link, const char *prop_name,
1081     char **prop_val, uint_t val_cnt, char **errprop)
1082 {
1083 	int		fd, i;
1084 	wldp_t		*gbuf = NULL;
1085 	boolean_t	found = B_FALSE;
1086 	dladm_status_t	status = DLADM_STATUS_OK;
1087 
1088 	if ((prop_name == NULL && prop_val != NULL) ||
1089 	    (prop_val != NULL && val_cnt == 0))
1090 		return (DLADM_STATUS_BADARG);
1091 
1092 	if ((fd = open_link(link)) < 0)
1093 		return (DLADM_STATUS_LINKINVAL);
1094 
1095 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
1096 		status = DLADM_STATUS_NOMEM;
1097 		goto done;
1098 	}
1099 
1100 	for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) {
1101 		prop_desc_t	*pdp = &prop_table[i];
1102 		dladm_status_t	s;
1103 
1104 		if (prop_name != NULL &&
1105 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
1106 			continue;
1107 
1108 		found = B_TRUE;
1109 		s = do_set_prop(fd, gbuf, pdp, prop_val, val_cnt);
1110 
1111 		if (prop_name != NULL) {
1112 			status = s;
1113 			break;
1114 		} else {
1115 			if (s != DLADM_STATUS_OK &&
1116 			    s != DLADM_STATUS_NOTSUP) {
1117 				if (errprop != NULL)
1118 					*errprop = pdp->pd_name;
1119 				status = s;
1120 				break;
1121 			}
1122 		}
1123 	}
1124 	if (!found)
1125 		status = DLADM_STATUS_NOTFOUND;
1126 done:
1127 	free(gbuf);
1128 	(void) close(fd);
1129 	return (status);
1130 }
1131 
1132 /* ARGSUSED */
1133 dladm_status_t
1134 dladm_wlan_walk_prop(const char *link, void *arg,
1135     boolean_t (*func)(void *, const char *))
1136 {
1137 	int	i;
1138 
1139 	for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) {
1140 		if (!func(arg, prop_table[i].pd_name))
1141 			break;
1142 	}
1143 	return (DLADM_STATUS_OK);
1144 }
1145 
1146 dladm_status_t
1147 dladm_wlan_get_prop(const char *link, dladm_prop_type_t type,
1148     const char *prop_name, char **prop_val, uint_t *val_cnt)
1149 {
1150 	int		fd;
1151 	int		i;
1152 	wldp_t		*gbuf;
1153 	dladm_status_t	status;
1154 	uint_t		cnt;
1155 	prop_desc_t	*pdp;
1156 
1157 	if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0)
1158 		return (DLADM_STATUS_BADARG);
1159 
1160 	for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++)
1161 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1162 			break;
1163 
1164 	if (i == DLADM_WLAN_MAX_PROPS)
1165 		return (DLADM_STATUS_NOTFOUND);
1166 
1167 	if ((fd = open_link(link)) < 0)
1168 		return (DLADM_STATUS_LINKINVAL);
1169 
1170 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
1171 		status = DLADM_STATUS_NOMEM;
1172 		goto done;
1173 	}
1174 	pdp = &prop_table[i];
1175 	status = DLADM_STATUS_OK;
1176 
1177 	switch (type) {
1178 	case DLADM_PROP_VAL_CURRENT:
1179 		status = pdp->pd_get(fd, gbuf, prop_val, val_cnt);
1180 		break;
1181 
1182 	case DLADM_PROP_VAL_DEFAULT:
1183 		if (pdp->pd_defval.vd_name == NULL) {
1184 			status = DLADM_STATUS_NOTSUP;
1185 			break;
1186 		}
1187 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1188 		*val_cnt = 1;
1189 		break;
1190 
1191 	case DLADM_PROP_VAL_MODIFIABLE:
1192 		if (pdp->pd_getmod != NULL) {
1193 			status = pdp->pd_getmod(fd, gbuf, prop_val, val_cnt);
1194 			break;
1195 		}
1196 		cnt = pdp->pd_nmodval;
1197 		if (cnt == 0) {
1198 			status = DLADM_STATUS_NOTSUP;
1199 		} else if (cnt > *val_cnt) {
1200 			status = DLADM_STATUS_TOOSMALL;
1201 		} else {
1202 			for (i = 0; i < cnt; i++) {
1203 				(void) strcpy(prop_val[i],
1204 				    pdp->pd_modval[i].vd_name);
1205 			}
1206 			*val_cnt = cnt;
1207 		}
1208 		break;
1209 	default:
1210 		status = DLADM_STATUS_BADARG;
1211 		break;
1212 	}
1213 done:
1214 	free(gbuf);
1215 	(void) close(fd);
1216 	return (status);
1217 }
1218 
1219 static boolean_t
1220 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
1221 {
1222 	int	i;
1223 
1224 	for (i = 0; i < cnt; i++) {
1225 		if (strcasecmp(str, vdp[i].vd_name) == 0) {
1226 			*valp = vdp[i].vd_val;
1227 			return (B_TRUE);
1228 		}
1229 	}
1230 	return (B_FALSE);
1231 }
1232 
1233 static boolean_t
1234 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
1235 {
1236 	int	i;
1237 
1238 	for (i = 0; i < cnt; i++) {
1239 		if (val == vdp[i].vd_val) {
1240 			*strp = vdp[i].vd_name;
1241 			return (B_TRUE);
1242 		}
1243 	}
1244 	return (B_FALSE);
1245 }
1246 
1247 const char *
1248 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
1249 {
1250 	(void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
1251 	return (buf);
1252 }
1253 
1254 const char *
1255 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
1256 {
1257 	return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
1258 	    IFT_OTHER));
1259 }
1260 
1261 static const char *
1262 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
1263 {
1264 	char	*s;
1265 
1266 	if (!find_name_by_val(val, vdp, cnt, &s))
1267 		s = "";
1268 
1269 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
1270 	return (buf);
1271 }
1272 
1273 const char *
1274 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
1275 {
1276 	return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
1277 	    VALCNT(secmode_vals), buf));
1278 }
1279 
1280 const char *
1281 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
1282 {
1283 	return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
1284 	    VALCNT(strength_vals), buf));
1285 }
1286 
1287 const char *
1288 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
1289 {
1290 	return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
1291 	    VALCNT(mode_vals), buf));
1292 }
1293 
1294 const char *
1295 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
1296 {
1297 	(void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
1298 	    (float)(*speed) / 2);
1299 	return (buf);
1300 }
1301 
1302 const char *
1303 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
1304 {
1305 	return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
1306 	    VALCNT(auth_vals), buf));
1307 }
1308 
1309 const char *
1310 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
1311 {
1312 	return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
1313 	    VALCNT(bsstype_vals), buf));
1314 }
1315 
1316 const char *
1317 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
1318 {
1319 	return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
1320 	    VALCNT(linkstatus_vals), buf));
1321 }
1322 
1323 dladm_status_t
1324 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
1325 {
1326 	if (str[0] == '\0')
1327 		return (DLADM_STATUS_BADARG);
1328 
1329 	(void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
1330 	return (DLADM_STATUS_OK);
1331 }
1332 
1333 dladm_status_t
1334 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
1335 {
1336 	int	len;
1337 	uchar_t	*buf;
1338 
1339 	buf = _link_aton(str, &len);
1340 	if (buf == NULL)
1341 		return (DLADM_STATUS_BADARG);
1342 
1343 	if (len != DLADM_WLAN_BSSID_LEN) {
1344 		free(buf);
1345 		return (DLADM_STATUS_BADARG);
1346 	}
1347 
1348 	(void) memcpy(bssid->wb_bytes, buf, len);
1349 	free(buf);
1350 	return (DLADM_STATUS_OK);
1351 }
1352 
1353 dladm_status_t
1354 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
1355 {
1356 	uint_t	val;
1357 
1358 	if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
1359 		return (DLADM_STATUS_BADARG);
1360 
1361 	*secmode = (dladm_wlan_secmode_t)val;
1362 	return (DLADM_STATUS_OK);
1363 }
1364 
1365 dladm_status_t
1366 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
1367 {
1368 	uint_t	val;
1369 
1370 	if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
1371 		return (DLADM_STATUS_BADARG);
1372 
1373 	*strength = (dladm_wlan_strength_t)val;
1374 	return (DLADM_STATUS_OK);
1375 }
1376 
1377 dladm_status_t
1378 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
1379 {
1380 	uint_t	val;
1381 
1382 	if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
1383 		return (DLADM_STATUS_BADARG);
1384 
1385 	*mode = (dladm_wlan_mode_t)val;
1386 	return (DLADM_STATUS_OK);
1387 }
1388 
1389 dladm_status_t
1390 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
1391 {
1392 	*speed = (dladm_wlan_speed_t)(atof(str) * 2);
1393 	return (DLADM_STATUS_OK);
1394 }
1395 
1396 dladm_status_t
1397 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
1398 {
1399 	uint_t	val;
1400 
1401 	if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
1402 		return (DLADM_STATUS_BADARG);
1403 
1404 	*auth = (dladm_wlan_auth_t)val;
1405 	return (DLADM_STATUS_OK);
1406 }
1407 
1408 dladm_status_t
1409 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
1410 {
1411 	uint_t	val;
1412 
1413 	if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
1414 		return (DLADM_STATUS_BADARG);
1415 
1416 	*bsstype = (dladm_wlan_bsstype_t)val;
1417 	return (DLADM_STATUS_OK);
1418 }
1419 
1420 dladm_status_t
1421 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
1422 {
1423 	uint_t	val;
1424 
1425 	if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals),
1426 	    &val))
1427 		return (DLADM_STATUS_BADARG);
1428 
1429 	*linkstatus = (dladm_wlan_linkstatus_t)val;
1430 	return (DLADM_STATUS_OK);
1431 }
1432 
1433 static int
1434 do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen)
1435 {
1436 	int			rc;
1437 	struct	strioctl	stri;
1438 
1439 	gbuf->wldp_type = NET_802_11;
1440 	gbuf->wldp_id	= id;
1441 	gbuf->wldp_length = len;
1442 
1443 	stri.ic_timout	= 0;
1444 	stri.ic_dp	= (char *)gbuf;
1445 	stri.ic_cmd	= cmd;
1446 	stri.ic_len	= cmdlen;
1447 
1448 	if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
1449 		if (rc > 0)
1450 			errno = rc;
1451 		return (-1);
1452 	}
1453 	return (0);
1454 }
1455 
1456 static int
1457 do_get_ioctl(int fd, wldp_t *gbuf, uint_t id)
1458 {
1459 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1460 	return (do_ioctl(fd, gbuf, id, MAX_BUF_LEN, WLAN_GET_PARAM,
1461 	    MAX_BUF_LEN));
1462 }
1463 
1464 static int
1465 do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen)
1466 {
1467 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1468 	(void) memcpy(gbuf->wldp_buf, buf, buflen);
1469 	buflen += WIFI_BUF_OFFSET;
1470 	return (do_ioctl(fd, gbuf, id, buflen, WLAN_SET_PARAM, buflen));
1471 }
1472 
1473 static int
1474 do_cmd_ioctl(int fd, wldp_t *gbuf, uint_t cmd)
1475 {
1476 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1477 	return (do_ioctl(fd, gbuf, cmd, sizeof (wldp_t), WLAN_COMMAND,
1478 	    sizeof (wldp_t)));
1479 }
1480 
1481 static int
1482 do_scan(int fd, wldp_t *gbuf)
1483 {
1484 	return (do_cmd_ioctl(fd, gbuf, WL_SCAN));
1485 }
1486 
1487 static int
1488 do_disconnect(const char *link, int fd, wldp_t *gbuf)
1489 {
1490 	if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf->
1491 	    wldp_buf))->wpa_flag > 0)
1492 		(void) wpa_instance_delete(link);
1493 
1494 	return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE));
1495 }
1496 
1497 static int
1498 do_get_esslist(int fd, wldp_t *gbuf)
1499 {
1500 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1501 	return (do_ioctl(fd, gbuf, WL_ESS_LIST, MAX_BUF_LEN,
1502 	    WLAN_GET_PARAM, sizeof (wldp_t)));
1503 }
1504 
1505 static int
1506 do_get_bssid(int fd, wldp_t *gbuf)
1507 {
1508 	return (do_get_ioctl(fd, gbuf, WL_BSSID));
1509 }
1510 
1511 static int
1512 do_get_essid(int fd, wldp_t *gbuf)
1513 {
1514 	return (do_get_ioctl(fd, gbuf, WL_ESSID));
1515 }
1516 
1517 static int
1518 do_get_bsstype(int fd, wldp_t *gbuf)
1519 {
1520 	return (do_get_ioctl(fd, gbuf, WL_BSS_TYPE));
1521 }
1522 
1523 static int
1524 do_get_linkstatus(int fd, wldp_t *gbuf)
1525 {
1526 	return (do_get_ioctl(fd, gbuf, WL_LINKSTATUS));
1527 }
1528 
1529 static int
1530 do_get_rate(int fd, wldp_t *gbuf)
1531 {
1532 	return (do_get_ioctl(fd, gbuf, WL_DESIRED_RATES));
1533 }
1534 
1535 static int
1536 do_get_phyconf(int fd, wldp_t *gbuf)
1537 {
1538 	return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG));
1539 }
1540 
1541 static int
1542 do_get_powermode(int fd, wldp_t *gbuf)
1543 {
1544 	return (do_get_ioctl(fd, gbuf, WL_POWER_MODE));
1545 }
1546 
1547 static int
1548 do_get_radio(int fd, wldp_t *gbuf)
1549 {
1550 	return (do_get_ioctl(fd, gbuf, WL_RADIO));
1551 }
1552 
1553 static int
1554 do_get_authmode(int fd, wldp_t *gbuf)
1555 {
1556 	return (do_get_ioctl(fd, gbuf, WL_AUTH_MODE));
1557 }
1558 
1559 static int
1560 do_get_encryption(int fd, wldp_t *gbuf)
1561 {
1562 	return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION));
1563 }
1564 
1565 static int
1566 do_get_signal(int fd, wldp_t *gbuf)
1567 {
1568 	return (do_get_ioctl(fd, gbuf, WL_RSSI));
1569 }
1570 
1571 static int
1572 do_get_mode(int fd, wldp_t *gbuf)
1573 {
1574 	return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG));
1575 }
1576 
1577 static dladm_status_t
1578 do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
1579 {
1580 	wl_rates_t	*wrp = (wl_rates_t *)gbuf->wldp_buf;
1581 	uint_t		cnt = wrp->wl_rates_num;
1582 	uint_t		i;
1583 
1584 	if (cnt > *val_cnt)
1585 		return (DLADM_STATUS_TOOSMALL);
1586 	if (wrp->wl_rates_rates[0] == 0) {
1587 		prop_val[0][0] = '\0';
1588 		*val_cnt = 1;
1589 		return (DLADM_STATUS_OK);
1590 	}
1591 
1592 	for (i = 0; i < cnt; i++) {
1593 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
1594 		    wrp->wl_rates_rates[i] % 2,
1595 		    (float)wrp->wl_rates_rates[i] / 2);
1596 	}
1597 	*val_cnt = cnt;
1598 	return (DLADM_STATUS_OK);
1599 }
1600 
1601 static dladm_status_t
1602 do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
1603 {
1604 	if (do_get_rate(fd, gbuf) < 0)
1605 		return (dladm_wlan_wlresult2status(gbuf));
1606 
1607 	return (do_get_rate_common(gbuf, prop_val, val_cnt));
1608 }
1609 
1610 static dladm_status_t
1611 do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
1612 {
1613 	if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0)
1614 		return (DLADM_STATUS_FAILED);
1615 
1616 	return (do_get_rate_common(gbuf, prop_val, val_cnt));
1617 }
1618 
1619 static dladm_status_t
1620 do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
1621 {
1622 	uint32_t	channel;
1623 
1624 	if (do_get_phyconf(fd, gbuf) < 0)
1625 		return (dladm_wlan_wlresult2status(gbuf));
1626 
1627 	if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel))
1628 		return (DLADM_STATUS_NOTFOUND);
1629 
1630 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1631 	*val_cnt = 1;
1632 
1633 	return (DLADM_STATUS_OK);
1634 }
1635 
1636 static dladm_status_t
1637 do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
1638 {
1639 	wl_ps_mode_t	*mode;
1640 	const char	*s;
1641 
1642 	if (do_get_powermode(fd, gbuf) < 0)
1643 		return (dladm_wlan_wlresult2status(gbuf));
1644 
1645 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
1646 	switch (mode->wl_ps_mode) {
1647 	case WL_PM_AM:
1648 		s = "off";
1649 		break;
1650 	case WL_PM_MPS:
1651 		s = "max";
1652 		break;
1653 	case WL_PM_FAST:
1654 		s = "fast";
1655 		break;
1656 	default:
1657 		return (DLADM_STATUS_NOTFOUND);
1658 	}
1659 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1660 	*val_cnt = 1;
1661 
1662 	return (DLADM_STATUS_OK);
1663 }
1664 
1665 static dladm_status_t
1666 do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
1667 {
1668 	wl_radio_t	radio;
1669 	const char	*s;
1670 
1671 	if (do_get_radio(fd, gbuf) < 0)
1672 		return (dladm_wlan_wlresult2status(gbuf));
1673 
1674 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
1675 	switch (radio) {
1676 	case B_TRUE:
1677 		s = "on";
1678 		break;
1679 	case B_FALSE:
1680 		s = "off";
1681 		break;
1682 	default:
1683 		return (DLADM_STATUS_NOTFOUND);
1684 	}
1685 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1686 	*val_cnt = 1;
1687 
1688 	return (DLADM_STATUS_OK);
1689 }
1690 
1691 static int
1692 do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype)
1693 {
1694 	wl_bss_type_t	ibsstype;
1695 
1696 	switch (*bsstype) {
1697 	case DLADM_WLAN_BSSTYPE_BSS:
1698 		ibsstype = WL_BSS_BSS;
1699 		break;
1700 	case DLADM_WLAN_BSSTYPE_IBSS:
1701 		ibsstype = WL_BSS_IBSS;
1702 		break;
1703 	default:
1704 		ibsstype = WL_BSS_ANY;
1705 		break;
1706 	}
1707 	return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype,
1708 	    sizeof (ibsstype)));
1709 }
1710 
1711 static int
1712 do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth)
1713 {
1714 	wl_authmode_t	auth_mode;
1715 
1716 	switch (*auth) {
1717 	case DLADM_WLAN_AUTH_OPEN:
1718 		auth_mode = WL_OPENSYSTEM;
1719 		break;
1720 	case DLADM_WLAN_AUTH_SHARED:
1721 		auth_mode = WL_SHAREDKEY;
1722 		break;
1723 	default:
1724 		return (-1);
1725 	}
1726 	return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode,
1727 	    sizeof (auth_mode)));
1728 }
1729 
1730 static int
1731 do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode)
1732 {
1733 	wl_encryption_t	encryption;
1734 
1735 	switch (*secmode) {
1736 	case DLADM_WLAN_SECMODE_NONE:
1737 		encryption = WL_NOENCRYPTION;
1738 		break;
1739 	case DLADM_WLAN_SECMODE_WEP:
1740 		encryption = WL_ENC_WEP;
1741 		break;
1742 	case DLADM_WLAN_SECMODE_WPA:
1743 		return (0);
1744 	default:
1745 		return (-1);
1746 	}
1747 	return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption,
1748 	    sizeof (encryption)));
1749 }
1750 
1751 static int
1752 do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys,
1753     uint_t key_count)
1754 {
1755 	int			i;
1756 	wl_wep_key_t		*wkp;
1757 	wl_wep_key_tab_t	wepkey_tab;
1758 	dladm_wlan_key_t	*kp;
1759 
1760 	if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
1761 		return (-1);
1762 
1763 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
1764 	for (i = 0; i < MAX_NWEPKEYS; i++)
1765 		wepkey_tab[i].wl_wep_operation = WL_NUL;
1766 
1767 	for (i = 0; i < key_count; i++) {
1768 		kp = &keys[i];
1769 		if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
1770 			return (-1);
1771 		if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
1772 		    kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
1773 			return (-1);
1774 
1775 		wkp = &wepkey_tab[kp->wk_idx - 1];
1776 		wkp->wl_wep_operation = WL_ADD;
1777 		wkp->wl_wep_length = kp->wk_len;
1778 		(void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
1779 	}
1780 
1781 	return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab,
1782 	    sizeof (wepkey_tab)));
1783 }
1784 
1785 static int
1786 do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid)
1787 {
1788 	wl_essid_t	iessid;
1789 
1790 	(void) memset(&iessid, 0, sizeof (essid));
1791 
1792 	if (essid != NULL && essid->we_bytes[0] != '\0') {
1793 		iessid.wl_essid_length = strlen(essid->we_bytes);
1794 		(void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
1795 		    sizeof (iessid.wl_essid_essid));
1796 	} else {
1797 		return (-1);
1798 	}
1799 	return (do_set_ioctl(fd, gbuf, WL_ESSID, &iessid, sizeof (iessid)));
1800 }
1801 
1802 /* ARGSUSED */
1803 static dladm_status_t
1804 do_check_rate(int fd, wldp_t *gbuf, prop_desc_t *pdp, char **prop_val,
1805     uint_t val_cnt, val_desc_t **vdpp)
1806 {
1807 	int		i;
1808 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1809 	char		*buf, **modval;
1810 	dladm_status_t	status;
1811 	val_desc_t	*vdp = NULL;
1812 
1813 	if (val_cnt != 1)
1814 		return (DLADM_STATUS_BADVALCNT);
1815 
1816 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) * MAX_SUPPORT_RATES);
1817 	if (buf == NULL)
1818 		goto done;
1819 
1820 	modval = (char **)(void *)buf;
1821 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1822 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1823 		    i * DLADM_STRSIZE;
1824 	}
1825 
1826 	status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt);
1827 	if (status != DLADM_STATUS_OK)
1828 		goto done;
1829 
1830 	vdp = malloc(sizeof (val_desc_t));
1831 	if (vdp == NULL) {
1832 		status = DLADM_STATUS_NOMEM;
1833 		goto done;
1834 	}
1835 
1836 	for (i = 0; i < modval_cnt; i++) {
1837 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1838 			vdp->vd_val = (uint_t)(atof(*prop_val) * 2);
1839 			status = DLADM_STATUS_OK;
1840 			*vdpp = vdp;
1841 			vdp = NULL;
1842 			break;
1843 		}
1844 	}
1845 	if (i == modval_cnt)
1846 		status = DLADM_STATUS_BADVAL;
1847 done:
1848 	free(buf);
1849 	free(vdp);
1850 	return (status);
1851 }
1852 
1853 static dladm_status_t
1854 do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
1855 {
1856 	dladm_wlan_rates_t	rates;
1857 
1858 	if (val_cnt != 1)
1859 		return (DLADM_STATUS_BADVALCNT);
1860 
1861 	rates.wr_cnt = 1;
1862 	rates.wr_rates[0] = vdp[0].vd_val;
1863 
1864 	if (do_set_rate(fd, gbuf, &rates) < 0)
1865 		return (dladm_wlan_wlresult2status(gbuf));
1866 
1867 	return (DLADM_STATUS_OK);
1868 }
1869 
1870 static int
1871 do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates)
1872 {
1873 	int		i;
1874 	uint_t		len;
1875 	wl_rates_t	*wrp = (wl_rates_t *)gbuf->wldp_buf;
1876 
1877 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1878 
1879 	for (i = 0; i < rates->wr_cnt; i++)
1880 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
1881 	wrp->wl_rates_num = rates->wr_cnt;
1882 
1883 	len = offsetof(wl_rates_t, wl_rates_rates) +
1884 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
1885 	return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len));
1886 }
1887 
1888 /* ARGSUSED */
1889 static dladm_status_t
1890 do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
1891 {
1892 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1893 
1894 	if (do_set_powermode(fd, gbuf, &powermode) < 0)
1895 		return (dladm_wlan_wlresult2status(gbuf));
1896 
1897 	return (DLADM_STATUS_OK);
1898 }
1899 
1900 static int
1901 do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm)
1902 {
1903 	wl_ps_mode_t	ps_mode;
1904 
1905 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1906 
1907 	switch (*pm) {
1908 	case DLADM_WLAN_PM_OFF:
1909 		ps_mode.wl_ps_mode = WL_PM_AM;
1910 		break;
1911 	case DLADM_WLAN_PM_MAX:
1912 		ps_mode.wl_ps_mode = WL_PM_MPS;
1913 		break;
1914 	case DLADM_WLAN_PM_FAST:
1915 		ps_mode.wl_ps_mode = WL_PM_FAST;
1916 		break;
1917 	default:
1918 		return (-1);
1919 	}
1920 	return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode,
1921 	    sizeof (ps_mode)));
1922 }
1923 
1924 /* ARGSUSED */
1925 static dladm_status_t
1926 do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
1927 {
1928 	dladm_wlan_radio_t	radio = (dladm_wlan_radio_t)vdp->vd_val;
1929 
1930 	if (do_set_radio(fd, gbuf, &radio) < 0)
1931 		return (dladm_wlan_wlresult2status(gbuf));
1932 
1933 	return (DLADM_STATUS_OK);
1934 }
1935 
1936 static int
1937 do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio)
1938 {
1939 	wl_radio_t r;
1940 
1941 	switch (*radio) {
1942 	case DLADM_WLAN_RADIO_ON:
1943 		r = B_TRUE;
1944 		break;
1945 	case DLADM_WLAN_RADIO_OFF:
1946 		r = B_FALSE;
1947 		break;
1948 	default:
1949 		return (-1);
1950 	}
1951 	return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r)));
1952 }
1953 
1954 static int
1955 do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel)
1956 {
1957 	wl_phy_conf_t phy_conf;
1958 
1959 	if (*channel > MAX_CHANNEL_NUM)
1960 		return (-1);
1961 
1962 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
1963 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
1964 
1965 	return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf,
1966 	    sizeof (phy_conf)));
1967 }
1968 
1969 static int
1970 do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss)
1971 {
1972 	wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
1973 
1974 	return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr)));
1975 }
1976 
1977 static void
1978 generate_essid(dladm_wlan_essid_t *essid)
1979 {
1980 	srandom(gethrtime());
1981 	(void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
1982 	    random());
1983 }
1984 
1985 static int
1986 do_get_capability(int fd, wldp_t *gbuf)
1987 {
1988 	return (do_get_ioctl(fd, gbuf, WL_CAPABILITY));
1989 }
1990 
1991 static int
1992 do_get_wpamode(int fd, wldp_t *gbuf)
1993 {
1994 	return (do_get_ioctl(fd, gbuf, WL_WPA));
1995 }
1996 
1997 static dladm_status_t
1998 ioctl_get(const char *link, int id, void *gbuf)
1999 {
2000 	int		fd;
2001 
2002 	if ((fd = open_link(link)) < 0)
2003 		return (DLADM_STATUS_LINKINVAL);
2004 	(void) do_get_ioctl(fd, gbuf, id);
2005 
2006 	(void) close(fd);
2007 	return (dladm_wlan_wlresult2status(gbuf));
2008 }
2009 
2010 static dladm_status_t
2011 ioctl_set(const char *link, int id, void *buf, uint_t buflen)
2012 {
2013 	int		fd;
2014 	wldp_t 		*gbuf;
2015 	dladm_status_t	status;
2016 
2017 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2018 		return (DLADM_STATUS_NOMEM);
2019 
2020 	if ((fd = open_link(link)) < 0)
2021 		return (DLADM_STATUS_LINKINVAL);
2022 	(void) do_set_ioctl(fd, gbuf, id, buf, buflen);
2023 
2024 	(void) close(fd);
2025 	status = dladm_wlan_wlresult2status(gbuf);
2026 	free(gbuf);
2027 
2028 	return (status);
2029 }
2030 
2031 dladm_status_t
2032 dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt,
2033     uint_t *estot)
2034 {
2035 	int		i, n;
2036 	wldp_t 		*gbuf;
2037 	wl_wpa_ess_t	*es;
2038 	dladm_status_t	status;
2039 
2040 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2041 		return (DLADM_STATUS_NOMEM);
2042 
2043 	status = ioctl_get(link, WL_SCANRESULTS, gbuf);
2044 
2045 	if (status == DLADM_STATUS_OK) {
2046 		es = (wl_wpa_ess_t *)(gbuf->wldp_buf);
2047 		n = (es->count > escnt) ? escnt : es->count;
2048 		for (i = 0; i < n; i ++) {
2049 			(void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
2050 			    DLADM_WLAN_BSSID_LEN);
2051 			sr[i].we_ssid_len = es->ess[i].ssid_len;
2052 			(void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
2053 			    es->ess[i].ssid_len);
2054 			sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
2055 			(void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
2056 			    es->ess[i].wpa_ie_len);
2057 			sr[i].we_freq = es->ess[i].freq;
2058 		}
2059 		*estot = n;
2060 	}
2061 
2062 	free(gbuf);
2063 	return (status);
2064 }
2065 
2066 dladm_status_t
2067 dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie,
2068     uint_t wpa_ie_len)
2069 {
2070 	wl_wpa_ie_t *ie;
2071 	uint_t len;
2072 	dladm_status_t	status;
2073 
2074 	if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
2075 		return (DLADM_STATUS_BADARG);
2076 	len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
2077 	ie = malloc(len);
2078 	if (ie == NULL)
2079 		return (DLADM_STATUS_NOMEM);
2080 
2081 	(void) memset(ie, 0, len);
2082 	ie->wpa_ie_len = wpa_ie_len;
2083 	(void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
2084 
2085 	status = ioctl_set(link, WL_SETOPTIE, ie, len);
2086 	free(ie);
2087 
2088 	return (status);
2089 }
2090 
2091 dladm_status_t
2092 dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag)
2093 {
2094 	wl_wpa_t wpa;
2095 
2096 	wpa.wpa_flag = flag;
2097 	return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t)));
2098 }
2099 
2100 dladm_status_t
2101 dladm_wlan_wpa_del_key(const char *link, uint_t key_idx,
2102     const dladm_wlan_bssid_t *addr)
2103 {
2104 	wl_del_key_t wk;
2105 
2106 	wk.idk_keyix = key_idx;
2107 	if (addr != NULL)
2108 		(void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
2109 		    DLADM_WLAN_BSSID_LEN);
2110 
2111 	return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t)));
2112 }
2113 
2114 dladm_status_t
2115 dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher,
2116     const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq,
2117     uint_t key_idx, uint8_t *key, uint_t key_len)
2118 {
2119 	wl_key_t wk;
2120 
2121 	(void) memset(&wk, 0, sizeof (wl_key_t));
2122 	switch (cipher) {
2123 	case DLADM_WLAN_CIPHER_WEP:
2124 		wk.ik_type = IEEE80211_CIPHER_WEP;
2125 		break;
2126 	case DLADM_WLAN_CIPHER_TKIP:
2127 		wk.ik_type = IEEE80211_CIPHER_TKIP;
2128 		break;
2129 	case DLADM_WLAN_CIPHER_AES_OCB:
2130 		wk.ik_type = IEEE80211_CIPHER_AES_OCB;
2131 		break;
2132 	case DLADM_WLAN_CIPHER_AES_CCM:
2133 		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
2134 		break;
2135 	case DLADM_WLAN_CIPHER_CKIP:
2136 		wk.ik_type = IEEE80211_CIPHER_CKIP;
2137 		break;
2138 	case DLADM_WLAN_CIPHER_NONE:
2139 		wk.ik_type = IEEE80211_CIPHER_NONE;
2140 		break;
2141 	default:
2142 		return (DLADM_STATUS_BADARG);
2143 	}
2144 	wk.ik_flags = IEEE80211_KEY_RECV;
2145 	if (set_tx) {
2146 		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
2147 		(void) memcpy(wk.ik_macaddr, addr->wb_bytes,
2148 		    DLADM_WLAN_BSSID_LEN);
2149 	} else
2150 		(void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
2151 	wk.ik_keyix = key_idx;
2152 	wk.ik_keylen = key_len;
2153 	(void) memcpy(&wk.ik_keyrsc, &seq, 6);	/* only use 48-bit of seq */
2154 	(void) memcpy(wk.ik_keydata, key, key_len);
2155 
2156 	return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t)));
2157 }
2158 
2159 dladm_status_t
2160 dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op,
2161     dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid)
2162 {
2163 	wl_mlme_t mlme;
2164 
2165 	(void) memset(&mlme, 0, sizeof (wl_mlme_t));
2166 	switch (op) {
2167 	case DLADM_WLAN_MLME_ASSOC:
2168 		mlme.im_op = IEEE80211_MLME_ASSOC;
2169 		break;
2170 	case DLADM_WLAN_MLME_DISASSOC:
2171 		mlme.im_op = IEEE80211_MLME_DISASSOC;
2172 		break;
2173 	default:
2174 		return (DLADM_STATUS_BADARG);
2175 	}
2176 	mlme.im_reason = reason;
2177 	if (bssid != NULL)
2178 		(void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
2179 		    DLADM_WLAN_BSSID_LEN);
2180 
2181 	return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t)));
2182 }
2183 
2184 /*
2185  * routines of create instance
2186  */
2187 static scf_propertygroup_t *
2188 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
2189     const char *pg_name, const char *pg_type)
2190 {
2191 	scf_propertygroup_t *pg;
2192 
2193 	pg = scf_pg_create(handle);
2194 	if (pg == NULL)
2195 		return (NULL);
2196 
2197 	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
2198 		scf_pg_destroy(pg);
2199 		return (NULL);
2200 	}
2201 
2202 	return (pg);
2203 }
2204 
2205 static int
2206 add_new_property(scf_handle_t *handle, const char *prop_name,
2207     scf_type_t type, const char *val, scf_transaction_t *tx)
2208 {
2209 	scf_value_t *value = NULL;
2210 	scf_transaction_entry_t *entry = NULL;
2211 
2212 	entry = scf_entry_create(handle);
2213 	if (entry == NULL)
2214 		goto out;
2215 
2216 	value = scf_value_create(handle);
2217 	if (value == NULL)
2218 		goto out;
2219 
2220 	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
2221 		goto out;
2222 
2223 	if (scf_value_set_from_string(value, type, val) != 0)
2224 		goto out;
2225 
2226 	if (scf_entry_add_value(entry, value) != 0)
2227 		goto out;
2228 
2229 	return (DLADM_WLAN_SVC_SUCCESS);
2230 
2231 out:
2232 	if (value != NULL)
2233 		scf_value_destroy(value);
2234 	if (entry != NULL)
2235 		scf_entry_destroy(entry);
2236 
2237 	return (DLADM_WLAN_SVC_FAILURE);
2238 }
2239 
2240 /*
2241  * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed.
2242  */
2243 static int
2244 add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
2245     const char *pg_name, const char *flags)
2246 {
2247 	int			rv, size;
2248 	int			status = DLADM_WLAN_SVC_FAILURE;
2249 	char			*command = NULL;
2250 	scf_transaction_t	*tran = NULL;
2251 	scf_propertygroup_t	*pg;
2252 
2253 	pg = add_property_group_to_instance(handle, instance,
2254 	    pg_name, SCF_GROUP_METHOD);
2255 	if (pg == NULL)
2256 		goto out;
2257 
2258 	tran = scf_transaction_create(handle);
2259 	if (tran == NULL)
2260 		goto out;
2261 
2262 	size = strlen(SVC_METHOD) + strlen("  ") + strlen(flags) + 1;
2263 	command = malloc(size);
2264 	if (command == NULL) {
2265 		status = DLADM_WLAN_SVC_APP_FAILURE;
2266 		goto out;
2267 	}
2268 	(void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
2269 
2270 	do {
2271 		if (scf_transaction_start(tran, pg) != 0)
2272 			goto out;
2273 
2274 		if (add_new_property(handle, SCF_PROPERTY_EXEC,
2275 		    SCF_TYPE_ASTRING, command, tran) !=
2276 		    DLADM_WLAN_SVC_SUCCESS) {
2277 			goto out;
2278 		}
2279 
2280 		rv = scf_transaction_commit(tran);
2281 		switch (rv) {
2282 		case 1:
2283 			status = DLADM_WLAN_SVC_SUCCESS;
2284 			goto out;
2285 		case 0:
2286 			scf_transaction_destroy_children(tran);
2287 			if (scf_pg_update(pg) == -1) {
2288 				goto out;
2289 			}
2290 			break;
2291 		case -1:
2292 		default:
2293 			goto out;
2294 		}
2295 	} while (rv == 0);
2296 
2297 out:
2298 	if (tran != NULL) {
2299 		scf_transaction_destroy_children(tran);
2300 		scf_transaction_destroy(tran);
2301 	}
2302 
2303 	if (pg != NULL)
2304 		scf_pg_destroy(pg);
2305 
2306 	if (command != NULL)
2307 		free(command);
2308 
2309 	return (status);
2310 }
2311 
2312 static int
2313 do_create_instance(scf_handle_t *handle, scf_service_t *svc,
2314     const char *instance_name, const char *command)
2315 {
2316 	int status = DLADM_WLAN_SVC_FAILURE;
2317 	char *buf;
2318 	ssize_t max_fmri_len;
2319 	scf_instance_t *instance;
2320 
2321 	instance = scf_instance_create(handle);
2322 	if (instance == NULL)
2323 		goto out;
2324 
2325 	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
2326 		if (scf_error() == SCF_ERROR_EXISTS)
2327 			/* Let the caller deal with the duplicate instance */
2328 			status = DLADM_WLAN_SVC_INSTANCE_EXISTS;
2329 		goto out;
2330 	}
2331 
2332 	if (add_pg_method(handle, instance, "start",
2333 	    command) != DLADM_WLAN_SVC_SUCCESS) {
2334 		goto out;
2335 	}
2336 
2337 	/* enabling the instance */
2338 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2339 	if ((buf = malloc(max_fmri_len + 1)) == NULL)
2340 		goto out;
2341 
2342 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
2343 		if ((smf_disable_instance(buf, 0) != 0) ||
2344 		    (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
2345 			goto out;
2346 		}
2347 		status = DLADM_WLAN_SVC_SUCCESS;
2348 	}
2349 
2350 out:
2351 	if (instance != NULL)
2352 		scf_instance_destroy(instance);
2353 	return (status);
2354 }
2355 
2356 static int
2357 create_instance(const char *instance_name, const char *command)
2358 {
2359 	int status = DLADM_WLAN_SVC_FAILURE;
2360 	scf_service_t *svc = NULL;
2361 	scf_handle_t *handle = NULL;
2362 
2363 	handle = scf_handle_create(SCF_VERSION);
2364 	if (handle == NULL)
2365 		goto out;
2366 
2367 	if (scf_handle_bind(handle) == -1)
2368 		goto out;
2369 
2370 	if ((svc = scf_service_create(handle)) == NULL)
2371 		goto out;
2372 
2373 	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
2374 	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
2375 		goto out;
2376 
2377 	status = do_create_instance(handle, svc, instance_name, command);
2378 
2379 out:
2380 	if (svc != NULL)
2381 		scf_service_destroy(svc);
2382 
2383 	if (handle != NULL) {
2384 		(void) scf_handle_unbind(handle);
2385 		scf_handle_destroy(handle);
2386 	}
2387 
2388 	return (status);
2389 }
2390 
2391 /*
2392  * routines of delete instance
2393  */
2394 #define	DEFAULT_TIMEOUT	60000000
2395 #define	INIT_WAIT_USECS	50000
2396 
2397 static void
2398 wait_until_disabled(scf_handle_t *handle, char *fmri)
2399 {
2400 	char		*state;
2401 	useconds_t	max;
2402 	useconds_t	usecs;
2403 	uint64_t	*cp = NULL;
2404 	scf_simple_prop_t *sp = NULL;
2405 
2406 	max = DEFAULT_TIMEOUT;
2407 
2408 	if (((sp = scf_simple_prop_get(handle, fmri, "stop",
2409 	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
2410 	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
2411 		max = (*cp) * 1000000;	/* convert to usecs */
2412 
2413 	if (sp != NULL)
2414 		scf_simple_prop_free(sp);
2415 
2416 	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
2417 		/* incremental wait */
2418 		usecs *= 2;
2419 		usecs = (usecs > max) ? max : usecs;
2420 
2421 		(void) usleep(usecs);
2422 
2423 		/* Check state after the wait */
2424 		if ((state = smf_get_state(fmri)) != NULL) {
2425 			if (strcmp(state, "disabled") == 0)
2426 				return;
2427 		}
2428 	}
2429 }
2430 
2431 static int
2432 delete_instance(const char *instance_name)
2433 {
2434 	int		status = DLADM_WLAN_SVC_FAILURE;
2435 	char		*buf;
2436 	ssize_t		max_fmri_len;
2437 	scf_scope_t	*scope = NULL;
2438 	scf_service_t	*svc = NULL;
2439 	scf_handle_t	*handle = NULL;
2440 	scf_instance_t	*instance;
2441 
2442 	handle = scf_handle_create(SCF_VERSION);
2443 	if (handle == NULL)
2444 		goto out;
2445 
2446 	if (scf_handle_bind(handle) == -1)
2447 		goto out;
2448 
2449 	if ((scope = scf_scope_create(handle)) == NULL)
2450 		goto out;
2451 
2452 	if ((svc = scf_service_create(handle)) == NULL)
2453 		goto out;
2454 
2455 	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
2456 		goto out;
2457 
2458 	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
2459 		goto out;
2460 
2461 	instance = scf_instance_create(handle);
2462 	if (instance == NULL)
2463 		goto out;
2464 
2465 	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
2466 		scf_error_t scf_errnum = scf_error();
2467 
2468 		if (scf_errnum == SCF_ERROR_NOT_FOUND)
2469 			status = DLADM_WLAN_SVC_SUCCESS;
2470 
2471 		scf_instance_destroy(instance);
2472 		goto out;
2473 	}
2474 
2475 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2476 	if ((buf = malloc(max_fmri_len + 1)) == NULL) {
2477 		scf_instance_destroy(instance);
2478 		goto out;
2479 	}
2480 
2481 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
2482 		char *state;
2483 
2484 		state = smf_get_state(buf);
2485 		if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
2486 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
2487 			if (smf_disable_instance(buf, 0) == 0) {
2488 				/*
2489 				 * Wait for some time till timeout to avoid
2490 				 * a race with scf_instance_delete() below.
2491 				 */
2492 				wait_until_disabled(handle, buf);
2493 			}
2494 		}
2495 	}
2496 
2497 	if (scf_instance_delete(instance) != 0) {
2498 		scf_instance_destroy(instance);
2499 		goto out;
2500 	}
2501 
2502 	scf_instance_destroy(instance);
2503 
2504 	status = DLADM_WLAN_SVC_SUCCESS;
2505 
2506 out:
2507 	if (svc != NULL)
2508 		scf_service_destroy(svc);
2509 
2510 	if (scope != NULL)
2511 		scf_scope_destroy(scope);
2512 
2513 	if (handle != NULL) {
2514 		(void) scf_handle_unbind(handle);
2515 		scf_handle_destroy(handle);
2516 	}
2517 
2518 	return (status);
2519 }
2520 
2521 /*
2522  * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed.
2523  */
2524 static int
2525 wpa_instance_create(const char *instance_name, void *key)
2526 {
2527 	int		status = DLADM_WLAN_SVC_FAILURE;
2528 	char		*command = NULL;
2529 	char		*wk_name = ((dladm_wlan_key_t *)key)->wk_name;
2530 	int		size;
2531 
2532 	size = strlen(instance_name) + strlen(" -i  -k ") + strlen(wk_name) + 1;
2533 	command = malloc(size);
2534 	if (command == NULL) {
2535 		status = DLADM_WLAN_SVC_APP_FAILURE;
2536 		goto out;
2537 	}
2538 	(void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
2539 
2540 	status = create_instance(instance_name, command);
2541 	if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) {
2542 		/*
2543 		 * Delete the existing instance and create a new instance
2544 		 * with the supplied arguments.
2545 		 */
2546 		if ((status = delete_instance(instance_name)) ==
2547 		    DLADM_WLAN_SVC_SUCCESS) {
2548 			status = create_instance(instance_name, command);
2549 		}
2550 	}
2551 
2552 out:
2553 	if (command != NULL)
2554 		free(command);
2555 
2556 	return (status);
2557 }
2558 
2559 static int
2560 wpa_instance_delete(const char *instance_name)
2561 {
2562 	int status;
2563 
2564 	status = delete_instance(instance_name);
2565 
2566 	return (status);
2567 }
2568