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