xref: /titanic_50/usr/src/lib/libdladm/common/libdlwlan.c (revision 1d03c31e0733adea0edef54f0d5d2ea9639ecd2a)
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 		status = DLADM_STATUS_NOMEM;
1819 		goto done;
1820 	}
1821 
1822 	modval = (char **)(void *)buf;
1823 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1824 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1825 		    i * DLADM_STRSIZE;
1826 	}
1827 
1828 	status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt);
1829 	if (status != DLADM_STATUS_OK)
1830 		goto done;
1831 
1832 	vdp = malloc(sizeof (val_desc_t));
1833 	if (vdp == NULL) {
1834 		status = DLADM_STATUS_NOMEM;
1835 		goto done;
1836 	}
1837 
1838 	for (i = 0; i < modval_cnt; i++) {
1839 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1840 			vdp->vd_val = (uint_t)(atof(*prop_val) * 2);
1841 			status = DLADM_STATUS_OK;
1842 			*vdpp = vdp;
1843 			vdp = NULL;
1844 			break;
1845 		}
1846 	}
1847 	if (i == modval_cnt)
1848 		status = DLADM_STATUS_BADVAL;
1849 done:
1850 	free(buf);
1851 	free(vdp);
1852 	return (status);
1853 }
1854 
1855 static dladm_status_t
1856 do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
1857 {
1858 	dladm_wlan_rates_t	rates;
1859 
1860 	if (val_cnt != 1)
1861 		return (DLADM_STATUS_BADVALCNT);
1862 
1863 	rates.wr_cnt = 1;
1864 	rates.wr_rates[0] = vdp[0].vd_val;
1865 
1866 	if (do_set_rate(fd, gbuf, &rates) < 0)
1867 		return (dladm_wlan_wlresult2status(gbuf));
1868 
1869 	return (DLADM_STATUS_OK);
1870 }
1871 
1872 static int
1873 do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates)
1874 {
1875 	int		i;
1876 	uint_t		len;
1877 	wl_rates_t	*wrp = (wl_rates_t *)gbuf->wldp_buf;
1878 
1879 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1880 
1881 	for (i = 0; i < rates->wr_cnt; i++)
1882 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
1883 	wrp->wl_rates_num = rates->wr_cnt;
1884 
1885 	len = offsetof(wl_rates_t, wl_rates_rates) +
1886 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
1887 	return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len));
1888 }
1889 
1890 /* ARGSUSED */
1891 static dladm_status_t
1892 do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
1893 {
1894 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1895 
1896 	if (do_set_powermode(fd, gbuf, &powermode) < 0)
1897 		return (dladm_wlan_wlresult2status(gbuf));
1898 
1899 	return (DLADM_STATUS_OK);
1900 }
1901 
1902 static int
1903 do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm)
1904 {
1905 	wl_ps_mode_t	ps_mode;
1906 
1907 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1908 
1909 	switch (*pm) {
1910 	case DLADM_WLAN_PM_OFF:
1911 		ps_mode.wl_ps_mode = WL_PM_AM;
1912 		break;
1913 	case DLADM_WLAN_PM_MAX:
1914 		ps_mode.wl_ps_mode = WL_PM_MPS;
1915 		break;
1916 	case DLADM_WLAN_PM_FAST:
1917 		ps_mode.wl_ps_mode = WL_PM_FAST;
1918 		break;
1919 	default:
1920 		return (-1);
1921 	}
1922 	return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode,
1923 	    sizeof (ps_mode)));
1924 }
1925 
1926 /* ARGSUSED */
1927 static dladm_status_t
1928 do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
1929 {
1930 	dladm_wlan_radio_t	radio = (dladm_wlan_radio_t)vdp->vd_val;
1931 
1932 	if (do_set_radio(fd, gbuf, &radio) < 0)
1933 		return (dladm_wlan_wlresult2status(gbuf));
1934 
1935 	return (DLADM_STATUS_OK);
1936 }
1937 
1938 static int
1939 do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio)
1940 {
1941 	wl_radio_t r;
1942 
1943 	switch (*radio) {
1944 	case DLADM_WLAN_RADIO_ON:
1945 		r = B_TRUE;
1946 		break;
1947 	case DLADM_WLAN_RADIO_OFF:
1948 		r = B_FALSE;
1949 		break;
1950 	default:
1951 		return (-1);
1952 	}
1953 	return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r)));
1954 }
1955 
1956 static int
1957 do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel)
1958 {
1959 	wl_phy_conf_t phy_conf;
1960 
1961 	if (*channel > MAX_CHANNEL_NUM)
1962 		return (-1);
1963 
1964 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
1965 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
1966 
1967 	return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf,
1968 	    sizeof (phy_conf)));
1969 }
1970 
1971 static int
1972 do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss)
1973 {
1974 	wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
1975 
1976 	return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr)));
1977 }
1978 
1979 static void
1980 generate_essid(dladm_wlan_essid_t *essid)
1981 {
1982 	srandom(gethrtime());
1983 	(void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
1984 	    random());
1985 }
1986 
1987 static int
1988 do_get_capability(int fd, wldp_t *gbuf)
1989 {
1990 	return (do_get_ioctl(fd, gbuf, WL_CAPABILITY));
1991 }
1992 
1993 static int
1994 do_get_wpamode(int fd, wldp_t *gbuf)
1995 {
1996 	return (do_get_ioctl(fd, gbuf, WL_WPA));
1997 }
1998 
1999 static dladm_status_t
2000 ioctl_get(const char *link, int id, void *gbuf)
2001 {
2002 	int		fd;
2003 
2004 	if ((fd = open_link(link)) < 0)
2005 		return (DLADM_STATUS_LINKINVAL);
2006 	(void) do_get_ioctl(fd, gbuf, id);
2007 
2008 	(void) close(fd);
2009 	return (dladm_wlan_wlresult2status(gbuf));
2010 }
2011 
2012 static dladm_status_t
2013 ioctl_set(const char *link, int id, void *buf, uint_t buflen)
2014 {
2015 	int		fd;
2016 	wldp_t 		*gbuf;
2017 	dladm_status_t	status;
2018 
2019 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2020 		return (DLADM_STATUS_NOMEM);
2021 
2022 	if ((fd = open_link(link)) < 0)
2023 		return (DLADM_STATUS_LINKINVAL);
2024 	(void) do_set_ioctl(fd, gbuf, id, buf, buflen);
2025 
2026 	(void) close(fd);
2027 	status = dladm_wlan_wlresult2status(gbuf);
2028 	free(gbuf);
2029 
2030 	return (status);
2031 }
2032 
2033 dladm_status_t
2034 dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt,
2035     uint_t *estot)
2036 {
2037 	int		i, n;
2038 	wldp_t 		*gbuf;
2039 	wl_wpa_ess_t	*es;
2040 	dladm_status_t	status;
2041 
2042 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2043 		return (DLADM_STATUS_NOMEM);
2044 
2045 	status = ioctl_get(link, WL_SCANRESULTS, gbuf);
2046 
2047 	if (status == DLADM_STATUS_OK) {
2048 		es = (wl_wpa_ess_t *)(gbuf->wldp_buf);
2049 		n = (es->count > escnt) ? escnt : es->count;
2050 		for (i = 0; i < n; i ++) {
2051 			(void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
2052 			    DLADM_WLAN_BSSID_LEN);
2053 			sr[i].we_ssid_len = es->ess[i].ssid_len;
2054 			(void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
2055 			    es->ess[i].ssid_len);
2056 			sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
2057 			(void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
2058 			    es->ess[i].wpa_ie_len);
2059 			sr[i].we_freq = es->ess[i].freq;
2060 		}
2061 		*estot = n;
2062 	}
2063 
2064 	free(gbuf);
2065 	return (status);
2066 }
2067 
2068 dladm_status_t
2069 dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie,
2070     uint_t wpa_ie_len)
2071 {
2072 	wl_wpa_ie_t *ie;
2073 	uint_t len;
2074 	dladm_status_t	status;
2075 
2076 	if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
2077 		return (DLADM_STATUS_BADARG);
2078 	len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
2079 	ie = malloc(len);
2080 	if (ie == NULL)
2081 		return (DLADM_STATUS_NOMEM);
2082 
2083 	(void) memset(ie, 0, len);
2084 	ie->wpa_ie_len = wpa_ie_len;
2085 	(void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
2086 
2087 	status = ioctl_set(link, WL_SETOPTIE, ie, len);
2088 	free(ie);
2089 
2090 	return (status);
2091 }
2092 
2093 dladm_status_t
2094 dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag)
2095 {
2096 	wl_wpa_t wpa;
2097 
2098 	wpa.wpa_flag = flag;
2099 	return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t)));
2100 }
2101 
2102 dladm_status_t
2103 dladm_wlan_wpa_del_key(const char *link, uint_t key_idx,
2104     const dladm_wlan_bssid_t *addr)
2105 {
2106 	wl_del_key_t wk;
2107 
2108 	wk.idk_keyix = key_idx;
2109 	if (addr != NULL)
2110 		(void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
2111 		    DLADM_WLAN_BSSID_LEN);
2112 
2113 	return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t)));
2114 }
2115 
2116 dladm_status_t
2117 dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher,
2118     const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq,
2119     uint_t key_idx, uint8_t *key, uint_t key_len)
2120 {
2121 	wl_key_t wk;
2122 
2123 	(void) memset(&wk, 0, sizeof (wl_key_t));
2124 	switch (cipher) {
2125 	case DLADM_WLAN_CIPHER_WEP:
2126 		wk.ik_type = IEEE80211_CIPHER_WEP;
2127 		break;
2128 	case DLADM_WLAN_CIPHER_TKIP:
2129 		wk.ik_type = IEEE80211_CIPHER_TKIP;
2130 		break;
2131 	case DLADM_WLAN_CIPHER_AES_OCB:
2132 		wk.ik_type = IEEE80211_CIPHER_AES_OCB;
2133 		break;
2134 	case DLADM_WLAN_CIPHER_AES_CCM:
2135 		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
2136 		break;
2137 	case DLADM_WLAN_CIPHER_CKIP:
2138 		wk.ik_type = IEEE80211_CIPHER_CKIP;
2139 		break;
2140 	case DLADM_WLAN_CIPHER_NONE:
2141 		wk.ik_type = IEEE80211_CIPHER_NONE;
2142 		break;
2143 	default:
2144 		return (DLADM_STATUS_BADARG);
2145 	}
2146 	wk.ik_flags = IEEE80211_KEY_RECV;
2147 	if (set_tx) {
2148 		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
2149 		(void) memcpy(wk.ik_macaddr, addr->wb_bytes,
2150 		    DLADM_WLAN_BSSID_LEN);
2151 	} else
2152 		(void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
2153 	wk.ik_keyix = key_idx;
2154 	wk.ik_keylen = key_len;
2155 	(void) memcpy(&wk.ik_keyrsc, &seq, 6);	/* only use 48-bit of seq */
2156 	(void) memcpy(wk.ik_keydata, key, key_len);
2157 
2158 	return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t)));
2159 }
2160 
2161 dladm_status_t
2162 dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op,
2163     dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid)
2164 {
2165 	wl_mlme_t mlme;
2166 
2167 	(void) memset(&mlme, 0, sizeof (wl_mlme_t));
2168 	switch (op) {
2169 	case DLADM_WLAN_MLME_ASSOC:
2170 		mlme.im_op = IEEE80211_MLME_ASSOC;
2171 		break;
2172 	case DLADM_WLAN_MLME_DISASSOC:
2173 		mlme.im_op = IEEE80211_MLME_DISASSOC;
2174 		break;
2175 	default:
2176 		return (DLADM_STATUS_BADARG);
2177 	}
2178 	mlme.im_reason = reason;
2179 	if (bssid != NULL)
2180 		(void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
2181 		    DLADM_WLAN_BSSID_LEN);
2182 
2183 	return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t)));
2184 }
2185 
2186 /*
2187  * routines of create instance
2188  */
2189 static scf_propertygroup_t *
2190 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
2191     const char *pg_name, const char *pg_type)
2192 {
2193 	scf_propertygroup_t *pg;
2194 
2195 	pg = scf_pg_create(handle);
2196 	if (pg == NULL)
2197 		return (NULL);
2198 
2199 	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
2200 		scf_pg_destroy(pg);
2201 		return (NULL);
2202 	}
2203 
2204 	return (pg);
2205 }
2206 
2207 static int
2208 add_new_property(scf_handle_t *handle, const char *prop_name,
2209     scf_type_t type, const char *val, scf_transaction_t *tx)
2210 {
2211 	scf_value_t *value = NULL;
2212 	scf_transaction_entry_t *entry = NULL;
2213 
2214 	entry = scf_entry_create(handle);
2215 	if (entry == NULL)
2216 		goto out;
2217 
2218 	value = scf_value_create(handle);
2219 	if (value == NULL)
2220 		goto out;
2221 
2222 	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
2223 		goto out;
2224 
2225 	if (scf_value_set_from_string(value, type, val) != 0)
2226 		goto out;
2227 
2228 	if (scf_entry_add_value(entry, value) != 0)
2229 		goto out;
2230 
2231 	return (DLADM_WLAN_SVC_SUCCESS);
2232 
2233 out:
2234 	if (value != NULL)
2235 		scf_value_destroy(value);
2236 	if (entry != NULL)
2237 		scf_entry_destroy(entry);
2238 
2239 	return (DLADM_WLAN_SVC_FAILURE);
2240 }
2241 
2242 /*
2243  * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed.
2244  */
2245 static int
2246 add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
2247     const char *pg_name, const char *flags)
2248 {
2249 	int			rv, size;
2250 	int			status = DLADM_WLAN_SVC_FAILURE;
2251 	char			*command = NULL;
2252 	scf_transaction_t	*tran = NULL;
2253 	scf_propertygroup_t	*pg;
2254 
2255 	pg = add_property_group_to_instance(handle, instance,
2256 	    pg_name, SCF_GROUP_METHOD);
2257 	if (pg == NULL)
2258 		goto out;
2259 
2260 	tran = scf_transaction_create(handle);
2261 	if (tran == NULL)
2262 		goto out;
2263 
2264 	size = strlen(SVC_METHOD) + strlen("  ") + strlen(flags) + 1;
2265 	command = malloc(size);
2266 	if (command == NULL) {
2267 		status = DLADM_WLAN_SVC_APP_FAILURE;
2268 		goto out;
2269 	}
2270 	(void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
2271 
2272 	do {
2273 		if (scf_transaction_start(tran, pg) != 0)
2274 			goto out;
2275 
2276 		if (add_new_property(handle, SCF_PROPERTY_EXEC,
2277 		    SCF_TYPE_ASTRING, command, tran) !=
2278 		    DLADM_WLAN_SVC_SUCCESS) {
2279 			goto out;
2280 		}
2281 
2282 		rv = scf_transaction_commit(tran);
2283 		switch (rv) {
2284 		case 1:
2285 			status = DLADM_WLAN_SVC_SUCCESS;
2286 			goto out;
2287 		case 0:
2288 			scf_transaction_destroy_children(tran);
2289 			if (scf_pg_update(pg) == -1) {
2290 				goto out;
2291 			}
2292 			break;
2293 		case -1:
2294 		default:
2295 			goto out;
2296 		}
2297 	} while (rv == 0);
2298 
2299 out:
2300 	if (tran != NULL) {
2301 		scf_transaction_destroy_children(tran);
2302 		scf_transaction_destroy(tran);
2303 	}
2304 
2305 	if (pg != NULL)
2306 		scf_pg_destroy(pg);
2307 
2308 	if (command != NULL)
2309 		free(command);
2310 
2311 	return (status);
2312 }
2313 
2314 static int
2315 do_create_instance(scf_handle_t *handle, scf_service_t *svc,
2316     const char *instance_name, const char *command)
2317 {
2318 	int status = DLADM_WLAN_SVC_FAILURE;
2319 	char *buf;
2320 	ssize_t max_fmri_len;
2321 	scf_instance_t *instance;
2322 
2323 	instance = scf_instance_create(handle);
2324 	if (instance == NULL)
2325 		goto out;
2326 
2327 	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
2328 		if (scf_error() == SCF_ERROR_EXISTS)
2329 			/* Let the caller deal with the duplicate instance */
2330 			status = DLADM_WLAN_SVC_INSTANCE_EXISTS;
2331 		goto out;
2332 	}
2333 
2334 	if (add_pg_method(handle, instance, "start",
2335 	    command) != DLADM_WLAN_SVC_SUCCESS) {
2336 		goto out;
2337 	}
2338 
2339 	/* enabling the instance */
2340 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2341 	if ((buf = malloc(max_fmri_len + 1)) == NULL)
2342 		goto out;
2343 
2344 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
2345 		if ((smf_disable_instance(buf, 0) != 0) ||
2346 		    (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
2347 			goto out;
2348 		}
2349 		status = DLADM_WLAN_SVC_SUCCESS;
2350 	}
2351 
2352 out:
2353 	if (instance != NULL)
2354 		scf_instance_destroy(instance);
2355 	return (status);
2356 }
2357 
2358 static int
2359 create_instance(const char *instance_name, const char *command)
2360 {
2361 	int status = DLADM_WLAN_SVC_FAILURE;
2362 	scf_service_t *svc = NULL;
2363 	scf_handle_t *handle = NULL;
2364 
2365 	handle = scf_handle_create(SCF_VERSION);
2366 	if (handle == NULL)
2367 		goto out;
2368 
2369 	if (scf_handle_bind(handle) == -1)
2370 		goto out;
2371 
2372 	if ((svc = scf_service_create(handle)) == NULL)
2373 		goto out;
2374 
2375 	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
2376 	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
2377 		goto out;
2378 
2379 	status = do_create_instance(handle, svc, instance_name, command);
2380 
2381 out:
2382 	if (svc != NULL)
2383 		scf_service_destroy(svc);
2384 
2385 	if (handle != NULL) {
2386 		(void) scf_handle_unbind(handle);
2387 		scf_handle_destroy(handle);
2388 	}
2389 
2390 	return (status);
2391 }
2392 
2393 /*
2394  * routines of delete instance
2395  */
2396 #define	DEFAULT_TIMEOUT	60000000
2397 #define	INIT_WAIT_USECS	50000
2398 
2399 static void
2400 wait_until_disabled(scf_handle_t *handle, char *fmri)
2401 {
2402 	char		*state;
2403 	useconds_t	max;
2404 	useconds_t	usecs;
2405 	uint64_t	*cp = NULL;
2406 	scf_simple_prop_t *sp = NULL;
2407 
2408 	max = DEFAULT_TIMEOUT;
2409 
2410 	if (((sp = scf_simple_prop_get(handle, fmri, "stop",
2411 	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
2412 	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
2413 		max = (*cp) * 1000000;	/* convert to usecs */
2414 
2415 	if (sp != NULL)
2416 		scf_simple_prop_free(sp);
2417 
2418 	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
2419 		/* incremental wait */
2420 		usecs *= 2;
2421 		usecs = (usecs > max) ? max : usecs;
2422 
2423 		(void) usleep(usecs);
2424 
2425 		/* Check state after the wait */
2426 		if ((state = smf_get_state(fmri)) != NULL) {
2427 			if (strcmp(state, "disabled") == 0)
2428 				return;
2429 		}
2430 	}
2431 }
2432 
2433 static int
2434 delete_instance(const char *instance_name)
2435 {
2436 	int		status = DLADM_WLAN_SVC_FAILURE;
2437 	char		*buf;
2438 	ssize_t		max_fmri_len;
2439 	scf_scope_t	*scope = NULL;
2440 	scf_service_t	*svc = NULL;
2441 	scf_handle_t	*handle = NULL;
2442 	scf_instance_t	*instance;
2443 
2444 	handle = scf_handle_create(SCF_VERSION);
2445 	if (handle == NULL)
2446 		goto out;
2447 
2448 	if (scf_handle_bind(handle) == -1)
2449 		goto out;
2450 
2451 	if ((scope = scf_scope_create(handle)) == NULL)
2452 		goto out;
2453 
2454 	if ((svc = scf_service_create(handle)) == NULL)
2455 		goto out;
2456 
2457 	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
2458 		goto out;
2459 
2460 	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
2461 		goto out;
2462 
2463 	instance = scf_instance_create(handle);
2464 	if (instance == NULL)
2465 		goto out;
2466 
2467 	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
2468 		scf_error_t scf_errnum = scf_error();
2469 
2470 		if (scf_errnum == SCF_ERROR_NOT_FOUND)
2471 			status = DLADM_WLAN_SVC_SUCCESS;
2472 
2473 		scf_instance_destroy(instance);
2474 		goto out;
2475 	}
2476 
2477 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2478 	if ((buf = malloc(max_fmri_len + 1)) == NULL) {
2479 		scf_instance_destroy(instance);
2480 		goto out;
2481 	}
2482 
2483 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
2484 		char *state;
2485 
2486 		state = smf_get_state(buf);
2487 		if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
2488 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
2489 			if (smf_disable_instance(buf, 0) == 0) {
2490 				/*
2491 				 * Wait for some time till timeout to avoid
2492 				 * a race with scf_instance_delete() below.
2493 				 */
2494 				wait_until_disabled(handle, buf);
2495 			}
2496 		}
2497 	}
2498 
2499 	if (scf_instance_delete(instance) != 0) {
2500 		scf_instance_destroy(instance);
2501 		goto out;
2502 	}
2503 
2504 	scf_instance_destroy(instance);
2505 
2506 	status = DLADM_WLAN_SVC_SUCCESS;
2507 
2508 out:
2509 	if (svc != NULL)
2510 		scf_service_destroy(svc);
2511 
2512 	if (scope != NULL)
2513 		scf_scope_destroy(scope);
2514 
2515 	if (handle != NULL) {
2516 		(void) scf_handle_unbind(handle);
2517 		scf_handle_destroy(handle);
2518 	}
2519 
2520 	return (status);
2521 }
2522 
2523 /*
2524  * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed.
2525  */
2526 static int
2527 wpa_instance_create(const char *instance_name, void *key)
2528 {
2529 	int		status = DLADM_WLAN_SVC_FAILURE;
2530 	char		*command = NULL;
2531 	char		*wk_name = ((dladm_wlan_key_t *)key)->wk_name;
2532 	int		size;
2533 
2534 	size = strlen(instance_name) + strlen(" -i  -k ") + strlen(wk_name) + 1;
2535 	command = malloc(size);
2536 	if (command == NULL) {
2537 		status = DLADM_WLAN_SVC_APP_FAILURE;
2538 		goto out;
2539 	}
2540 	(void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
2541 
2542 	status = create_instance(instance_name, command);
2543 	if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) {
2544 		/*
2545 		 * Delete the existing instance and create a new instance
2546 		 * with the supplied arguments.
2547 		 */
2548 		if ((status = delete_instance(instance_name)) ==
2549 		    DLADM_WLAN_SVC_SUCCESS) {
2550 			status = create_instance(instance_name, command);
2551 		}
2552 	}
2553 
2554 out:
2555 	if (command != NULL)
2556 		free(command);
2557 
2558 	return (status);
2559 }
2560 
2561 static int
2562 wpa_instance_delete(const char *instance_name)
2563 {
2564 	int status;
2565 
2566 	status = delete_instance(instance_name);
2567 
2568 	return (status);
2569 }
2570