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