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