13871Syz147064 /*
23871Syz147064  * CDDL HEADER START
33871Syz147064  *
43871Syz147064  * The contents of this file are subject to the terms of the
53871Syz147064  * Common Development and Distribution License (the "License").
63871Syz147064  * You may not use this file except in compliance with the License.
73871Syz147064  *
83871Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93871Syz147064  * or http://www.opensolaris.org/os/licensing.
103871Syz147064  * See the License for the specific language governing permissions
113871Syz147064  * and limitations under the License.
123871Syz147064  *
133871Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
143871Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153871Syz147064  * If applicable, add the following below this CDDL HEADER, with the
163871Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
173871Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
183871Syz147064  *
193871Syz147064  * CDDL HEADER END
203871Syz147064  */
213871Syz147064 /*
225895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233871Syz147064  * Use is subject to license terms.
243871Syz147064  */
253871Syz147064 
263871Syz147064 #include <libintl.h>
273871Syz147064 #include <stdio.h>
283871Syz147064 #include <stdlib.h>
293871Syz147064 #include <unistd.h>
303871Syz147064 #include <fcntl.h>
315895Syz147064 #include <stddef.h>
323871Syz147064 #include <string.h>
333871Syz147064 #include <stropts.h>
343871Syz147064 #include <libdevinfo.h>
353871Syz147064 #include <net/if.h>
363871Syz147064 #include <net/if_dl.h>
373871Syz147064 #include <net/if_types.h>
385895Syz147064 #include <libdlpi.h>
395895Syz147064 #include <libdllink.h>
404126Szf162725 #include <libscf.h>
413871Syz147064 #include <libdlwlan.h>
425895Syz147064 #include <libdladm_impl.h>
433871Syz147064 #include <libdlwlan_impl.h>
444126Szf162725 #include <net/wpa.h>
453871Syz147064 
465895Syz147064 static dladm_status_t	wpa_instance_create(datalink_id_t, void *);
475895Syz147064 static dladm_status_t	wpa_instance_delete(datalink_id_t);
483871Syz147064 
49*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_bsstype(datalink_id_t, void *, int);
50*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_essid(datalink_id_t, void *, int);
51*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_bssid(datalink_id_t, void *, int);
52*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_signal(datalink_id_t, void *, int);
53*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_encryption(datalink_id_t, void *, int);
54*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_authmode(datalink_id_t, void *, int);
55*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_linkstatus(datalink_id_t, void *, int);
56*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_get_esslist(datalink_id_t, void  *, int);
57*7663SSowmini.Varadhan@Sun.COM static dladm_status_t 	do_get_rate(datalink_id_t, void *, int);
58*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_get_mode(datalink_id_t, void *, int);
59*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_get_capability(datalink_id_t, void *, int);
60*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_get_wpamode(datalink_id_t, void *, int);
614126Szf162725 
625895Syz147064 static dladm_status_t	do_set_bsstype(datalink_id_t, dladm_wlan_bsstype_t *);
635895Syz147064 static dladm_status_t	do_set_authmode(datalink_id_t, dladm_wlan_auth_t *);
645895Syz147064 static dladm_status_t	do_set_encryption(datalink_id_t,
655895Syz147064 			    dladm_wlan_secmode_t *);
665895Syz147064 static dladm_status_t	do_set_essid(datalink_id_t, dladm_wlan_essid_t *);
675895Syz147064 static dladm_status_t	do_set_createibss(datalink_id_t, boolean_t *);
685895Syz147064 static dladm_status_t	do_set_key(datalink_id_t, dladm_wlan_key_t *, uint_t);
695895Syz147064 static dladm_status_t	do_set_channel(datalink_id_t, dladm_wlan_channel_t *);
703871Syz147064 
71*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_scan(datalink_id_t, void *, int);
72*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_connect(datalink_id_t, void *, int,
73*7663SSowmini.Varadhan@Sun.COM 			    dladm_wlan_attr_t *, boolean_t, void *, uint_t,
74*7663SSowmini.Varadhan@Sun.COM 			    int);
75*7663SSowmini.Varadhan@Sun.COM static dladm_status_t	do_disconnect(datalink_id_t, void *, int);
765895Syz147064 static boolean_t	find_val_by_name(const char *, val_desc_t *,
775895Syz147064 			    uint_t, uint_t *);
785895Syz147064 static boolean_t	find_name_by_val(uint_t, val_desc_t *, uint_t, char **);
795895Syz147064 static void		generate_essid(dladm_wlan_essid_t *);
803871Syz147064 
813871Syz147064 static dladm_status_t	dladm_wlan_wlresult2status(wldp_t *);
825895Syz147064 static dladm_status_t	dladm_wlan_validate(datalink_id_t);
833871Syz147064 
843871Syz147064 static val_desc_t	linkstatus_vals[] = {
855903Ssowmini 	{ "disconnected", DLADM_WLAN_LINK_DISCONNECTED	},
865903Ssowmini 	{ "connected",    DLADM_WLAN_LINK_CONNECTED	}
873871Syz147064 };
883871Syz147064 
893871Syz147064 static val_desc_t 	secmode_vals[] = {
905903Ssowmini 	{ "none",	DLADM_WLAN_SECMODE_NONE		},
915903Ssowmini 	{ "wep",	DLADM_WLAN_SECMODE_WEP		},
925903Ssowmini 	{ "wpa",	DLADM_WLAN_SECMODE_WPA		}
933871Syz147064 };
943871Syz147064 
953871Syz147064 static val_desc_t 	strength_vals[] = {
965903Ssowmini 	{ "very weak",	DLADM_WLAN_STRENGTH_VERY_WEAK	},
975895Syz147064 	{ "weak",	DLADM_WLAN_STRENGTH_WEAK	},
985895Syz147064 	{ "good",	DLADM_WLAN_STRENGTH_GOOD	},
995903Ssowmini 	{ "very good",	DLADM_WLAN_STRENGTH_VERY_GOOD	},
1005903Ssowmini 	{ "excellent",	DLADM_WLAN_STRENGTH_EXCELLENT	}
1013871Syz147064 };
1023871Syz147064 
1033871Syz147064 static val_desc_t	mode_vals[] = {
1045903Ssowmini 	{ "a",		DLADM_WLAN_MODE_80211A		},
1055903Ssowmini 	{ "b",		DLADM_WLAN_MODE_80211B		},
1065903Ssowmini 	{ "g",		DLADM_WLAN_MODE_80211G		},
1073871Syz147064 };
1083871Syz147064 
1093871Syz147064 static val_desc_t	auth_vals[] = {
1105895Syz147064 	{ "open",	DLADM_WLAN_AUTH_OPEN		},
1115903Ssowmini 	{ "shared",	DLADM_WLAN_AUTH_SHARED		}
1123871Syz147064 };
1133871Syz147064 
1143871Syz147064 static val_desc_t	bsstype_vals[] = {
1155903Ssowmini 	{ "bss",	DLADM_WLAN_BSSTYPE_BSS		},
1165903Ssowmini 	{ "ibss",	DLADM_WLAN_BSSTYPE_IBSS		},
1175903Ssowmini 	{ "any",	DLADM_WLAN_BSSTYPE_ANY		}
1183871Syz147064 };
1193871Syz147064 
120*7663SSowmini.Varadhan@Sun.COM #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
1213871Syz147064 
1223871Syz147064 static dladm_status_t
1233871Syz147064 dladm_wlan_wlresult2status(wldp_t *gbuf)
1243871Syz147064 {
1253871Syz147064 	switch (gbuf->wldp_result) {
1263871Syz147064 	case WL_SUCCESS:
1273871Syz147064 		return (DLADM_STATUS_OK);
1283871Syz147064 
1293871Syz147064 	case WL_NOTSUPPORTED:
1303871Syz147064 	case WL_LACK_FEATURE:
1313871Syz147064 		return (DLADM_STATUS_NOTSUP);
1323871Syz147064 
1333871Syz147064 	case WL_READONLY:
1343871Syz147064 		return (DLADM_STATUS_PROPRDONLY);
1353871Syz147064 
1363871Syz147064 	default:
1373871Syz147064 		break;
1383871Syz147064 	}
1393871Syz147064 
1403871Syz147064 	return (DLADM_STATUS_FAILED);
1413871Syz147064 }
1423871Syz147064 
1433871Syz147064 static dladm_wlan_mode_t
1443871Syz147064 do_convert_mode(wl_phy_conf_t *phyp)
1453871Syz147064 {
1463871Syz147064 	switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) {
1473871Syz147064 	case WL_ERP:
1483871Syz147064 		return (DLADM_WLAN_MODE_80211G);
1493871Syz147064 	case WL_OFDM:
1503871Syz147064 		return (DLADM_WLAN_MODE_80211A);
1513871Syz147064 	case WL_DSSS:
1523871Syz147064 	case WL_FHSS:
1533871Syz147064 		return (DLADM_WLAN_MODE_80211B);
1543871Syz147064 	default:
1553871Syz147064 		break;
1563871Syz147064 	}
1573871Syz147064 
1583871Syz147064 	return (DLADM_WLAN_MODE_NONE);
1593871Syz147064 }
1603871Syz147064 
1615895Syz147064 boolean_t
1625895Syz147064 i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp)
1633871Syz147064 {
1643871Syz147064 	wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf;
1653871Syz147064 	wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
1663871Syz147064 
1673871Syz147064 	switch (wlfp->wl_fhss_subtype) {
1683871Syz147064 	case WL_FHSS:
1693871Syz147064 	case WL_DSSS:
1703871Syz147064 	case WL_IRBASE:
1713871Syz147064 	case WL_HRDS:
1723871Syz147064 	case WL_ERP:
1733871Syz147064 		*channelp = wlfp->wl_fhss_channel;
1743871Syz147064 		break;
1753871Syz147064 	case WL_OFDM:
1763871Syz147064 		*channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency);
1773871Syz147064 		break;
1783871Syz147064 	default:
1793871Syz147064 		return (B_FALSE);
1803871Syz147064 	}
1813871Syz147064 	return (B_TRUE);
1823871Syz147064 }
1833871Syz147064 
1843871Syz147064 #define	IEEE80211_RATE	0x7f
1853871Syz147064 static void
1863871Syz147064 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp)
1873871Syz147064 {
1883871Syz147064 	int		i;
1893871Syz147064 
1903871Syz147064 	(void) memset(attrp, 0, sizeof (*attrp));
1913871Syz147064 
1923871Syz147064 	(void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN,
1933871Syz147064 	    "%s", wlp->wl_ess_conf_essid.wl_essid_essid);
1943871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
1953871Syz147064 
1963871Syz147064 	(void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid,
1973871Syz147064 	    DLADM_WLAN_BSSID_LEN);
1983871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
1993871Syz147064 
2003871Syz147064 	attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled ==
2013871Syz147064 	    WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE);
2024126Szf162725 	if (wlp->wl_ess_conf_reserved[0] > 0)
2034126Szf162725 		attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
2043871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2053871Syz147064 
2063871Syz147064 	attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ?
2073871Syz147064 	    DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS);
2083871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
2093871Syz147064 
2103871Syz147064 	attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ?
2113871Syz147064 	    DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED);
2123871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
2133871Syz147064 
2143871Syz147064 	attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
2153871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
2163871Syz147064 
2173871Syz147064 	attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
2183871Syz147064 	attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
2193871Syz147064 
2203871Syz147064 	for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
2213871Syz147064 		wlp->wl_supported_rates[i] &= IEEE80211_RATE;
2223871Syz147064 		if (wlp->wl_supported_rates[i] > attrp->wa_speed)
2233871Syz147064 			attrp->wa_speed = wlp->wl_supported_rates[i];
2243871Syz147064 	}
2253871Syz147064 	if (attrp->wa_speed > 0)
2263871Syz147064 		attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
2273871Syz147064 
2285895Syz147064 	if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf,
2293871Syz147064 	    &attrp->wa_channel))
2303871Syz147064 		attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL;
2313871Syz147064 }
2323871Syz147064 
2333871Syz147064 dladm_status_t
2345895Syz147064 dladm_wlan_scan(datalink_id_t linkid, void *arg,
2353871Syz147064     boolean_t (*func)(void *, dladm_wlan_attr_t *))
2363871Syz147064 {
2375895Syz147064 	int			i;
2383871Syz147064 	uint32_t		count;
2393871Syz147064 	wl_ess_conf_t		*wlp;
240*7663SSowmini.Varadhan@Sun.COM 	wl_ess_list_t		*wls = NULL;
241*7663SSowmini.Varadhan@Sun.COM 	char 			buf[WLDP_BUFSIZE];
242*7663SSowmini.Varadhan@Sun.COM 	wl_linkstatus_t		wl_status;
2433871Syz147064 	dladm_wlan_attr_t	wlattr;
2443871Syz147064 	dladm_status_t		status;
2453871Syz147064 
2465895Syz147064 	if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK)
2475895Syz147064 		goto done;
2483871Syz147064 
249*7663SSowmini.Varadhan@Sun.COM 	status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status));
250*7663SSowmini.Varadhan@Sun.COM 	if (status != DLADM_STATUS_OK)
2513871Syz147064 		goto done;
2523871Syz147064 
253*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_scan(linkid, buf, sizeof (buf))) != DLADM_STATUS_OK)
2543871Syz147064 		goto done;
2553871Syz147064 
2564126Szf162725 	if (func == NULL) {
2574126Szf162725 		status = DLADM_STATUS_OK;
2584126Szf162725 		goto done;
2594126Szf162725 	}
2604126Szf162725 
261*7663SSowmini.Varadhan@Sun.COM 	wls = malloc(WLDP_BUFSIZE);
262*7663SSowmini.Varadhan@Sun.COM 	if (wls == NULL) {
263*7663SSowmini.Varadhan@Sun.COM 		status = DLADM_STATUS_NOMEM;
264*7663SSowmini.Varadhan@Sun.COM 		goto done;
265*7663SSowmini.Varadhan@Sun.COM 	}
266*7663SSowmini.Varadhan@Sun.COM 
267*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_esslist(linkid, wls, WLDP_BUFSIZE))
268*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
2693871Syz147064 		goto done;
2703871Syz147064 
271*7663SSowmini.Varadhan@Sun.COM 	wlp = wls->wl_ess_list_ess;
272*7663SSowmini.Varadhan@Sun.COM 	count = wls->wl_ess_list_num;
2733871Syz147064 
2743871Syz147064 	for (i = 0; i < count; i++, wlp++) {
2753871Syz147064 		fill_wlan_attr(wlp, &wlattr);
2763871Syz147064 		if (!func(arg, &wlattr))
2773871Syz147064 			break;
2783871Syz147064 	}
2793871Syz147064 
280*7663SSowmini.Varadhan@Sun.COM 	if (wl_status != WL_CONNECTED) {
281*7663SSowmini.Varadhan@Sun.COM 		status = do_get_linkstatus(linkid, &wl_status,
282*7663SSowmini.Varadhan@Sun.COM 		    sizeof (&wl_status));
2835895Syz147064 		if (status != DLADM_STATUS_OK)
2843871Syz147064 			goto done;
285*7663SSowmini.Varadhan@Sun.COM 		if (wl_status == WL_CONNECTED)
286*7663SSowmini.Varadhan@Sun.COM 			(void) do_disconnect(linkid, buf, sizeof (buf));
2873871Syz147064 	}
2883871Syz147064 
2893871Syz147064 	status = DLADM_STATUS_OK;
2903871Syz147064 done:
291*7663SSowmini.Varadhan@Sun.COM 	free(wls);
2923871Syz147064 	return (status);
2933871Syz147064 }
2943871Syz147064 
2953871Syz147064 /*
2963871Syz147064  * Structures used in building the list of eligible WLANs to connect to.
2973871Syz147064  * Specifically, `connect_state' has the WLAN attributes that must be matched
2983871Syz147064  * (in `cs_attr') and a growing list of WLANs that matched those attributes
2993871Syz147064  * chained through `cs_list'.  Each element in the list is of type `attr_node'
3003871Syz147064  * and has the matching WLAN's attributes and a pointer to the next element.
3013871Syz147064  * For convenience, `cs_count' tracks the number of elements in the list.
3023871Syz147064  */
3033871Syz147064 typedef struct attr_node {
3043871Syz147064 	dladm_wlan_attr_t	an_attr;
3053871Syz147064 	struct attr_node	*an_next;
3063871Syz147064 } attr_node_t;
3073871Syz147064 
3083871Syz147064 typedef struct connect_state {
3093871Syz147064 	dladm_wlan_attr_t	*cs_attr;
3103871Syz147064 	uint_t			cs_count;
3113871Syz147064 	attr_node_t		*cs_list;
3123871Syz147064 } connect_state_t;
3133871Syz147064 
3143871Syz147064 /*
3153871Syz147064  * Compare two sets of WLAN attributes.  For now, we only consider strength
3163871Syz147064  * and speed (in that order), which matches the documented default policy for
3173871Syz147064  * dladm_wlan_connect().
3183871Syz147064  */
3193871Syz147064 static int
3203871Syz147064 attr_compare(const void *p1, const void *p2)
3213871Syz147064 {
3223871Syz147064 	dladm_wlan_attr_t *attrp1, *attrp2;
3233871Syz147064 
3243871Syz147064 	attrp1 = (*(dladm_wlan_attr_t **)p1);
3253871Syz147064 	attrp2 = (*(dladm_wlan_attr_t **)p2);
3263871Syz147064 
3273871Syz147064 	if (attrp1->wa_strength < attrp2->wa_strength)
3283871Syz147064 		return (1);
3293871Syz147064 
3303871Syz147064 	if (attrp1->wa_strength > attrp2->wa_strength)
3313871Syz147064 		return (-1);
3323871Syz147064 
3333871Syz147064 	return (attrp2->wa_speed - attrp1->wa_speed);
3343871Syz147064 }
3353871Syz147064 
3363871Syz147064 /*
3373871Syz147064  * Callback function used by dladm_wlan_connect() to filter out unwanted
3383871Syz147064  * WLANs when scanning for available WLANs.  Always returns B_TRUE to
3393871Syz147064  * continue the scan.
3403871Syz147064  */
3413871Syz147064 static boolean_t
3423871Syz147064 connect_cb(void *arg, dladm_wlan_attr_t *attrp)
3433871Syz147064 {
3443871Syz147064 	attr_node_t		*nodep;
3453871Syz147064 	dladm_wlan_attr_t	*fattrp;
3463871Syz147064 	connect_state_t		*statep = (connect_state_t *)arg;
3473871Syz147064 
3483871Syz147064 	fattrp = statep->cs_attr;
3493871Syz147064 	if (fattrp == NULL)
3503871Syz147064 		goto append;
3513871Syz147064 
3523871Syz147064 	if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
3533871Syz147064 		return (B_TRUE);
3543871Syz147064 
3553871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 &&
3563871Syz147064 	    strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes,
3573871Syz147064 	    DLADM_WLAN_MAX_ESSID_LEN) != 0)
3583871Syz147064 		return (B_TRUE);
3593871Syz147064 
3603871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
3613871Syz147064 	    fattrp->wa_secmode != attrp->wa_secmode)
3623871Syz147064 		return (B_TRUE);
3633871Syz147064 
3643871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 &&
3653871Syz147064 	    fattrp->wa_mode != attrp->wa_mode)
3663871Syz147064 		return (B_TRUE);
3673871Syz147064 
3683871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 &&
3693871Syz147064 	    fattrp->wa_strength != attrp->wa_strength)
3703871Syz147064 		return (B_TRUE);
3713871Syz147064 
3723871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 &&
3733871Syz147064 	    fattrp->wa_speed != attrp->wa_speed)
3743871Syz147064 		return (B_TRUE);
3753871Syz147064 
3763871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) {
3773871Syz147064 		attrp->wa_auth = fattrp->wa_auth;
3783871Syz147064 		attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
3793871Syz147064 	}
3803871Syz147064 
3813871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
3823871Syz147064 	    fattrp->wa_bsstype != attrp->wa_bsstype)
3833871Syz147064 		return (B_TRUE);
3843871Syz147064 
3853871Syz147064 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 &&
3863871Syz147064 	    memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes,
3873871Syz147064 	    DLADM_WLAN_BSSID_LEN) != 0)
3883871Syz147064 		return (B_TRUE);
3893871Syz147064 append:
3903871Syz147064 	nodep = malloc(sizeof (attr_node_t));
3913871Syz147064 	if (nodep == NULL)
3923871Syz147064 		return (B_TRUE);
3933871Syz147064 
3943871Syz147064 	(void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t));
3953871Syz147064 	nodep->an_next = statep->cs_list;
3963871Syz147064 	statep->cs_list = nodep;
3973871Syz147064 	statep->cs_count++;
3983871Syz147064 
3993871Syz147064 	return (B_TRUE);
4003871Syz147064 }
4013871Syz147064 
4024126Szf162725 #define	IEEE80211_C_WPA		0x01800000
4034126Szf162725 
4043871Syz147064 static dladm_status_t
405*7663SSowmini.Varadhan@Sun.COM do_connect(datalink_id_t linkid, void *buf, int bufsize,
406*7663SSowmini.Varadhan@Sun.COM     dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys,
407*7663SSowmini.Varadhan@Sun.COM     uint_t key_count, int timeout)
4083871Syz147064 {
4095895Syz147064 	dladm_wlan_secmode_t	secmode;
4105895Syz147064 	dladm_wlan_auth_t	authmode;
4115895Syz147064 	dladm_wlan_bsstype_t	bsstype;
4125895Syz147064 	dladm_wlan_essid_t	essid;
4135895Syz147064 	boolean_t		essid_valid = B_FALSE;
4145895Syz147064 	dladm_status_t		status;
4155895Syz147064 	dladm_wlan_channel_t	channel;
4165895Syz147064 	hrtime_t		start;
4175895Syz147064 	wl_capability_t		*caps;
418*7663SSowmini.Varadhan@Sun.COM 	wl_linkstatus_t		wl_status;
4193871Syz147064 
4203871Syz147064 	if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) {
4213871Syz147064 		channel = attrp->wa_channel;
4225895Syz147064 		status = do_set_channel(linkid, &channel);
4235895Syz147064 		if (status != DLADM_STATUS_OK)
4243871Syz147064 			goto fail;
4253871Syz147064 	}
4263871Syz147064 
4273871Syz147064 	secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ?
4283871Syz147064 	    attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE;
4293871Syz147064 
4305895Syz147064 	if ((status = do_set_encryption(linkid, &secmode)) != DLADM_STATUS_OK)
4313871Syz147064 		goto fail;
4323871Syz147064 
4333871Syz147064 	authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ?
4343871Syz147064 	    attrp->wa_auth : DLADM_WLAN_AUTH_OPEN;
4353871Syz147064 
4365895Syz147064 	if ((status = do_set_authmode(linkid, &authmode)) != DLADM_STATUS_OK)
4373871Syz147064 		goto fail;
4383871Syz147064 
4393871Syz147064 	bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ?
4403871Syz147064 	    attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS;
4413871Syz147064 
4425895Syz147064 	if ((status = do_set_bsstype(linkid, &bsstype)) != DLADM_STATUS_OK)
4433871Syz147064 		goto fail;
4443871Syz147064 
4453871Syz147064 	if (secmode == DLADM_WLAN_SECMODE_WEP) {
4465895Syz147064 		if (keys == NULL || key_count == 0 ||
4475895Syz147064 		    key_count > MAX_NWEPKEYS) {
4485895Syz147064 			status = DLADM_STATUS_BADARG;
4495895Syz147064 			goto fail;
4505895Syz147064 		}
4515895Syz147064 		status = do_set_key(linkid, keys, key_count);
4525895Syz147064 		if (status != DLADM_STATUS_OK)
4533871Syz147064 			goto fail;
4544126Szf162725 	} else if (secmode == DLADM_WLAN_SECMODE_WPA) {
4555895Syz147064 		if (keys == NULL || key_count == 0 ||
4565895Syz147064 		    key_count > MAX_NWEPKEYS) {
4575895Syz147064 			status = DLADM_STATUS_BADARG;
4585895Syz147064 			goto fail;
4595895Syz147064 		}
460*7663SSowmini.Varadhan@Sun.COM 		status = do_get_capability(linkid, buf, bufsize);
4615895Syz147064 		if (status != DLADM_STATUS_OK)
4624126Szf162725 			goto fail;
463*7663SSowmini.Varadhan@Sun.COM 		caps = (wl_capability_t *)buf;
4644126Szf162725 		if ((caps->caps & IEEE80211_C_WPA) == 0)
4654126Szf162725 			return (DLADM_STATUS_NOTSUP);
4663871Syz147064 	}
4673871Syz147064 
4683871Syz147064 	if (create_ibss) {
4695895Syz147064 		status = do_set_channel(linkid, &channel);
4705895Syz147064 		if (status != DLADM_STATUS_OK)
4713871Syz147064 			goto fail;
4723871Syz147064 
4735895Syz147064 		status = do_set_createibss(linkid, &create_ibss);
4745895Syz147064 		if (status != DLADM_STATUS_OK)
4753871Syz147064 			goto fail;
4763871Syz147064 
4773871Syz147064 		if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) {
4783871Syz147064 			generate_essid(&essid);
4793871Syz147064 			essid_valid = B_TRUE;
4803871Syz147064 		}
4813871Syz147064 	}
4823871Syz147064 
4833871Syz147064 	if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) {
4843871Syz147064 		essid = attrp->wa_essid;
4853871Syz147064 		essid_valid = B_TRUE;
4863871Syz147064 	}
4873871Syz147064 
4885895Syz147064 	if (!essid_valid) {
4895895Syz147064 		status = DLADM_STATUS_FAILED;
4905895Syz147064 		goto fail;
4915895Syz147064 	}
4925895Syz147064 
4935895Syz147064 	if ((status = do_set_essid(linkid, &essid)) != DLADM_STATUS_OK)
4943871Syz147064 		goto fail;
4953871Syz147064 
4964126Szf162725 	/*
4974126Szf162725 	 * Because wpa daemon needs getting essid from driver,
4984126Szf162725 	 * we need call do_set_essid() first, then call wpa_instance_create().
4994126Szf162725 	 */
5004126Szf162725 	if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL)
5015895Syz147064 		(void) wpa_instance_create(linkid, keys);
5024126Szf162725 
5033871Syz147064 	start = gethrtime();
5043871Syz147064 	for (;;) {
505*7663SSowmini.Varadhan@Sun.COM 		status = do_get_linkstatus(linkid, &wl_status,
506*7663SSowmini.Varadhan@Sun.COM 		    sizeof (wl_status));
5075895Syz147064 		if (status != DLADM_STATUS_OK)
5083871Syz147064 			goto fail;
5093871Syz147064 
510*7663SSowmini.Varadhan@Sun.COM 		if (wl_status == WL_CONNECTED)
5113871Syz147064 			break;
5123871Syz147064 
5133871Syz147064 		(void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE);
5143871Syz147064 		if ((timeout >= 0) && (gethrtime() - start) /
5155895Syz147064 		    NANOSEC >= timeout) {
5165895Syz147064 			status = DLADM_STATUS_TIMEDOUT;
5175895Syz147064 			goto fail;
5185895Syz147064 		}
5193871Syz147064 	}
5205895Syz147064 	status = DLADM_STATUS_OK;
5213871Syz147064 fail:
5225895Syz147064 	return (status);
5233871Syz147064 }
5243871Syz147064 
5253871Syz147064 dladm_status_t
5265895Syz147064 dladm_wlan_connect(datalink_id_t linkid, dladm_wlan_attr_t *attrp,
5273871Syz147064     int timeout, void *keys, uint_t key_count, uint_t flags)
5283871Syz147064 {
5295895Syz147064 	int			i;
530*7663SSowmini.Varadhan@Sun.COM 	char 			buf[WLDP_BUFSIZE];
5313871Syz147064 	connect_state_t		state = {0, NULL, NULL};
5323871Syz147064 	attr_node_t		*nodep = NULL;
5333871Syz147064 	boolean_t		create_ibss, set_authmode;
5343871Syz147064 	dladm_wlan_attr_t	**wl_list = NULL;
5355895Syz147064 	dladm_status_t		status;
536*7663SSowmini.Varadhan@Sun.COM 	wl_linkstatus_t		wl_status;
5373871Syz147064 
5385895Syz147064 	if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK)
5396233Syz147064 		return (status);
5403871Syz147064 
541*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status)))
542*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
5433871Syz147064 		goto done;
5443871Syz147064 
545*7663SSowmini.Varadhan@Sun.COM 	if (wl_status == WL_CONNECTED) {
5463871Syz147064 		status = DLADM_STATUS_ISCONN;
5473871Syz147064 		goto done;
5483871Syz147064 	}
5493871Syz147064 
5503871Syz147064 	set_authmode = ((attrp != NULL) &&
5513871Syz147064 	    (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0);
5523871Syz147064 	create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 &&
5533871Syz147064 	    attrp != NULL &&
5543871Syz147064 	    (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
5553871Syz147064 	    attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS);
5563871Syz147064 
5573871Syz147064 	if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 ||
5583871Syz147064 	    (create_ibss && attrp != NULL &&
5593871Syz147064 	    (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) {
560*7663SSowmini.Varadhan@Sun.COM 		status = do_connect(linkid, buf, sizeof (buf), attrp,
561*7663SSowmini.Varadhan@Sun.COM 		    create_ibss, keys, key_count, timeout);
5623871Syz147064 		goto done;
5633871Syz147064 	}
5643871Syz147064 
5653871Syz147064 	state.cs_attr = attrp;
5663871Syz147064 	state.cs_list = NULL;
5673871Syz147064 	state.cs_count = 0;
5683871Syz147064 
5695895Syz147064 	status = dladm_wlan_scan(linkid, &state, connect_cb);
5703871Syz147064 	if (status != DLADM_STATUS_OK)
5713871Syz147064 		goto done;
5723871Syz147064 
5733871Syz147064 	if (state.cs_count == 0) {
5743871Syz147064 		if (!create_ibss) {
5753871Syz147064 			status = DLADM_STATUS_NOTFOUND;
5763871Syz147064 			goto done;
5773871Syz147064 		}
578*7663SSowmini.Varadhan@Sun.COM 		status = do_connect(linkid, buf, sizeof (buf),
579*7663SSowmini.Varadhan@Sun.COM 		    attrp, create_ibss, keys, key_count, timeout);
5803871Syz147064 		goto done;
5813871Syz147064 	}
5823871Syz147064 
5833871Syz147064 	wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *));
5843871Syz147064 	if (wl_list == NULL) {
5853871Syz147064 		status = DLADM_STATUS_NOMEM;
5863871Syz147064 		goto done;
5873871Syz147064 	}
5883871Syz147064 
5893871Syz147064 	nodep = state.cs_list;
5903871Syz147064 	for (i = 0; i < state.cs_count; i++) {
5913871Syz147064 		wl_list[i] = &nodep->an_attr;
5923871Syz147064 		nodep = nodep->an_next;
5933871Syz147064 	}
5943871Syz147064 	qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
5953871Syz147064 	    attr_compare);
5963871Syz147064 
5973871Syz147064 	for (i = 0; i < state.cs_count; i++) {
5983871Syz147064 		dladm_wlan_attr_t	*ap = wl_list[i];
5993871Syz147064 
600*7663SSowmini.Varadhan@Sun.COM 		status = do_connect(linkid, buf, sizeof (buf),
601*7663SSowmini.Varadhan@Sun.COM 		    ap, create_ibss, keys, key_count, timeout);
6023871Syz147064 		if (status == DLADM_STATUS_OK)
6033871Syz147064 			break;
6043871Syz147064 
6053871Syz147064 		if (!set_authmode) {
6063871Syz147064 			ap->wa_auth = DLADM_WLAN_AUTH_SHARED;
6073871Syz147064 			ap->wa_valid |= DLADM_WLAN_ATTR_AUTH;
608*7663SSowmini.Varadhan@Sun.COM 			status = do_connect(linkid, buf, sizeof (buf),
609*7663SSowmini.Varadhan@Sun.COM 			    ap, create_ibss, keys, key_count, timeout);
6103871Syz147064 			if (status == DLADM_STATUS_OK)
6113871Syz147064 				break;
6123871Syz147064 		}
6133871Syz147064 	}
6143871Syz147064 done:
6153871Syz147064 	if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
616*7663SSowmini.Varadhan@Sun.COM 		(void) do_disconnect(linkid, buf, sizeof (buf));
6173871Syz147064 
6183871Syz147064 	while (state.cs_list != NULL) {
6193871Syz147064 		nodep = state.cs_list;
6203871Syz147064 		state.cs_list = nodep->an_next;
6213871Syz147064 		free(nodep);
6223871Syz147064 	}
6233871Syz147064 	free(wl_list);
6243871Syz147064 	return (status);
6253871Syz147064 }
6263871Syz147064 
6273871Syz147064 dladm_status_t
6285895Syz147064 dladm_wlan_disconnect(datalink_id_t linkid)
6293871Syz147064 {
630*7663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
6313871Syz147064 	dladm_status_t	status;
632*7663SSowmini.Varadhan@Sun.COM 	wl_linkstatus_t	wl_status;
6333871Syz147064 
6345895Syz147064 	if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK)
6355895Syz147064 		return (status);
6363871Syz147064 
637*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status)))
638*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
6393871Syz147064 		goto done;
6403871Syz147064 
641*7663SSowmini.Varadhan@Sun.COM 	if (wl_status != WL_CONNECTED) {
6423871Syz147064 		status = DLADM_STATUS_NOTCONN;
6433871Syz147064 		goto done;
6443871Syz147064 	}
6453871Syz147064 
646*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_disconnect(linkid, buf, sizeof (buf)))
647*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
6483871Syz147064 		goto done;
6493871Syz147064 
650*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status)))
651*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
6523871Syz147064 		goto done;
6533871Syz147064 
654*7663SSowmini.Varadhan@Sun.COM 	if (wl_status == WL_CONNECTED) {
6553871Syz147064 		status = DLADM_STATUS_FAILED;
6563871Syz147064 		goto done;
6573871Syz147064 	}
6583871Syz147064 
6593871Syz147064 	status = DLADM_STATUS_OK;
6603871Syz147064 done:
6613871Syz147064 	return (status);
6623871Syz147064 }
6633871Syz147064 
6645895Syz147064 dladm_status_t
6655895Syz147064 dladm_wlan_get_linkattr(datalink_id_t linkid, dladm_wlan_linkattr_t *attrp)
6663871Syz147064 {
6673871Syz147064 	wl_rssi_t		signal;
6683871Syz147064 	wl_bss_type_t		bsstype;
6693871Syz147064 	wl_authmode_t		authmode;
6703871Syz147064 	wl_encryption_t		encryption;
671*7663SSowmini.Varadhan@Sun.COM 	wl_rates_t		*ratesp = NULL;
6723871Syz147064 	dladm_wlan_attr_t	*wl_attrp;
6735895Syz147064 	dladm_status_t		status;
674*7663SSowmini.Varadhan@Sun.COM 	char			buf[WLDP_BUFSIZE];
675*7663SSowmini.Varadhan@Sun.COM 	wl_essid_t		wls;
676*7663SSowmini.Varadhan@Sun.COM 	wl_phy_conf_t		wl_phy_conf;
677*7663SSowmini.Varadhan@Sun.COM 	wl_linkstatus_t		wl_status;
6783871Syz147064 
6793871Syz147064 	if (attrp == NULL)
6803871Syz147064 		return (DLADM_STATUS_BADARG);
6813871Syz147064 
6825895Syz147064 	if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK)
6835895Syz147064 		goto done;
6843871Syz147064 
6853871Syz147064 	(void) memset(attrp, 0, sizeof (*attrp));
6863871Syz147064 	wl_attrp = &attrp->la_wlan_attr;
6873871Syz147064 
688*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_linkstatus(linkid, &wl_status, sizeof (wl_status)))
689*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
6903871Syz147064 		goto done;
6913871Syz147064 
6923871Syz147064 	attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS;
693*7663SSowmini.Varadhan@Sun.COM 	if (wl_status != WL_CONNECTED)
6945895Syz147064 		attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED;
6955895Syz147064 	else
6965895Syz147064 		attrp->la_status = DLADM_WLAN_LINK_CONNECTED;
6973871Syz147064 
698*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_essid(linkid, &wls, sizeof (wls)))
699*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
7003871Syz147064 		goto done;
7013871Syz147064 
702*7663SSowmini.Varadhan@Sun.COM 	(void) strlcpy(wl_attrp->wa_essid.we_bytes, wls.wl_essid_essid,
7033871Syz147064 	    DLADM_WLAN_MAX_ESSID_LEN);
7043871Syz147064 
7053871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
7063871Syz147064 
707*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_bssid(linkid, buf, sizeof (buf)))
708*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
7093871Syz147064 		goto done;
7103871Syz147064 
711*7663SSowmini.Varadhan@Sun.COM 	(void) memcpy(wl_attrp->wa_bssid.wb_bytes, buf, DLADM_WLAN_BSSID_LEN);
7123871Syz147064 
7133871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
7143871Syz147064 
7155895Syz147064 	if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) {
7164126Szf162725 		attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
7174126Szf162725 		status = DLADM_STATUS_OK;
7184126Szf162725 		goto done;
7194126Szf162725 	}
7204126Szf162725 
721*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_encryption(linkid, &encryption,
722*7663SSowmini.Varadhan@Sun.COM 	    sizeof (encryption))) != DLADM_STATUS_OK)
7233871Syz147064 		goto done;
7243871Syz147064 
7253871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
7263871Syz147064 
7273871Syz147064 	switch (encryption) {
7283871Syz147064 	case WL_NOENCRYPTION:
7293871Syz147064 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
7303871Syz147064 		break;
7313871Syz147064 	case WL_ENC_WEP:
7323871Syz147064 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
7333871Syz147064 		break;
7344126Szf162725 	case WL_ENC_WPA:
7354126Szf162725 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
7364126Szf162725 		break;
7373871Syz147064 	default:
7383871Syz147064 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE;
7393871Syz147064 		break;
7403871Syz147064 	}
7413871Syz147064 
742*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_signal(linkid, &signal, sizeof (signal)))
743*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
7443871Syz147064 		goto done;
7453871Syz147064 
7463871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
7473871Syz147064 	wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
7483871Syz147064 
749*7663SSowmini.Varadhan@Sun.COM 	ratesp = malloc(WLDP_BUFSIZE);
750*7663SSowmini.Varadhan@Sun.COM 	if (ratesp == NULL) {
751*7663SSowmini.Varadhan@Sun.COM 		status = DLADM_STATUS_NOMEM;
752*7663SSowmini.Varadhan@Sun.COM 		goto done;
753*7663SSowmini.Varadhan@Sun.COM 	}
754*7663SSowmini.Varadhan@Sun.COM 
755*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_rate(linkid, ratesp, WLDP_BUFSIZE))
756*7663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
7573871Syz147064 		goto done;
7583871Syz147064 
7593871Syz147064 	if (ratesp->wl_rates_num > 0) {
7603871Syz147064 		uint_t	i, r = 0;
7613871Syz147064 
7623871Syz147064 		for (i = 0; i < ratesp->wl_rates_num; i++) {
7633871Syz147064 			if (ratesp->wl_rates_rates[i] > r)
7643871Syz147064 				r = ratesp->wl_rates_rates[i];
7653871Syz147064 		}
7663871Syz147064 		wl_attrp->wa_speed = r;
7673871Syz147064 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
7683871Syz147064 	}
7693871Syz147064 
770*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_authmode(linkid, &authmode,
771*7663SSowmini.Varadhan@Sun.COM 	    sizeof (authmode))) != DLADM_STATUS_OK)
7723871Syz147064 		goto done;
7733871Syz147064 
7743871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
7753871Syz147064 
7763871Syz147064 	switch (authmode) {
7773871Syz147064 	case WL_OPENSYSTEM:
7783871Syz147064 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
7793871Syz147064 		break;
7803871Syz147064 	case WL_SHAREDKEY:
7813871Syz147064 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
7823871Syz147064 		break;
7833871Syz147064 	default:
7843871Syz147064 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
7853871Syz147064 		break;
7863871Syz147064 	}
7873871Syz147064 
788*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_bsstype(linkid, &bsstype,
789*7663SSowmini.Varadhan@Sun.COM 	    sizeof (bsstype))) != DLADM_STATUS_OK)
7903871Syz147064 		goto done;
7913871Syz147064 
7923871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
7933871Syz147064 
7943871Syz147064 	switch (bsstype) {
7953871Syz147064 	case WL_BSS_BSS:
7963871Syz147064 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
7973871Syz147064 		break;
7983871Syz147064 	case WL_BSS_IBSS:
7993871Syz147064 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
8003871Syz147064 		break;
8013871Syz147064 	case WL_BSS_ANY:
8023871Syz147064 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
8033871Syz147064 		break;
8043871Syz147064 	default:
8053871Syz147064 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
8063871Syz147064 		break;
8073871Syz147064 	}
8083871Syz147064 
809*7663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_mode(linkid, &wl_phy_conf,
810*7663SSowmini.Varadhan@Sun.COM 	    sizeof (wl_phy_conf))) != DLADM_STATUS_OK)
8113871Syz147064 		goto done;
8123871Syz147064 
813*7663SSowmini.Varadhan@Sun.COM 	wl_attrp->wa_mode = do_convert_mode(&wl_phy_conf);
8143871Syz147064 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
8153871Syz147064 	if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
8163871Syz147064 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
8173871Syz147064 
8183871Syz147064 	attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
8193871Syz147064 	status = DLADM_STATUS_OK;
8203871Syz147064 
8213871Syz147064 done:
822*7663SSowmini.Varadhan@Sun.COM 	free(ratesp);
8233871Syz147064 	return (status);
8243871Syz147064 }
8253871Syz147064 
8267408SSebastien.Roy@Sun.COM /*
8277408SSebastien.Roy@Sun.COM  * Check to see if the link is wireless.
8287408SSebastien.Roy@Sun.COM  */
8293871Syz147064 static dladm_status_t
8305895Syz147064 dladm_wlan_validate(datalink_id_t linkid)
8313871Syz147064 {
8327408SSebastien.Roy@Sun.COM 	uint32_t	media;
8333871Syz147064 	dladm_status_t	status;
8343871Syz147064 
8357408SSebastien.Roy@Sun.COM 	status = dladm_datalink_id2info(linkid, NULL, NULL, &media, NULL, 0);
8367408SSebastien.Roy@Sun.COM 	if (status == DLADM_STATUS_OK) {
8377408SSebastien.Roy@Sun.COM 		if (media != DL_WIFI)
8387408SSebastien.Roy@Sun.COM 			status = DLADM_STATUS_LINKINVAL;
8393871Syz147064 	}
8403871Syz147064 	return (status);
8413871Syz147064 }
8423871Syz147064 
8433871Syz147064 static boolean_t
8443871Syz147064 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
8453871Syz147064 {
8463871Syz147064 	int	i;
8473871Syz147064 
8483871Syz147064 	for (i = 0; i < cnt; i++) {
8493871Syz147064 		if (strcasecmp(str, vdp[i].vd_name) == 0) {
8503871Syz147064 			*valp = vdp[i].vd_val;
8513871Syz147064 			return (B_TRUE);
8523871Syz147064 		}
8533871Syz147064 	}
8543871Syz147064 	return (B_FALSE);
8553871Syz147064 }
8563871Syz147064 
8573871Syz147064 static boolean_t
8583871Syz147064 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
8593871Syz147064 {
8603871Syz147064 	int	i;
8613871Syz147064 
8623871Syz147064 	for (i = 0; i < cnt; i++) {
8633871Syz147064 		if (val == vdp[i].vd_val) {
8643871Syz147064 			*strp = vdp[i].vd_name;
8653871Syz147064 			return (B_TRUE);
8663871Syz147064 		}
8673871Syz147064 	}
8683871Syz147064 	return (B_FALSE);
8693871Syz147064 }
8703871Syz147064 
8713871Syz147064 const char *
8723871Syz147064 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
8733871Syz147064 {
8743871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
8753871Syz147064 	return (buf);
8763871Syz147064 }
8773871Syz147064 
8783871Syz147064 const char *
8793871Syz147064 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
8803871Syz147064 {
8813871Syz147064 	return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
8823871Syz147064 	    IFT_OTHER));
8833871Syz147064 }
8843871Syz147064 
8853871Syz147064 static const char *
8863871Syz147064 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
8873871Syz147064 {
8883871Syz147064 	char	*s;
8893871Syz147064 
8903871Syz147064 	if (!find_name_by_val(val, vdp, cnt, &s))
8913871Syz147064 		s = "";
8923871Syz147064 
8933871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
8943871Syz147064 	return (buf);
8953871Syz147064 }
8963871Syz147064 
8973871Syz147064 const char *
8983871Syz147064 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
8993871Syz147064 {
9003871Syz147064 	return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
9013871Syz147064 	    VALCNT(secmode_vals), buf));
9023871Syz147064 }
9033871Syz147064 
9043871Syz147064 const char *
9053871Syz147064 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
9063871Syz147064 {
9073871Syz147064 	return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
9083871Syz147064 	    VALCNT(strength_vals), buf));
9093871Syz147064 }
9103871Syz147064 
9113871Syz147064 const char *
9123871Syz147064 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
9133871Syz147064 {
9143871Syz147064 	return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
9153871Syz147064 	    VALCNT(mode_vals), buf));
9163871Syz147064 }
9173871Syz147064 
9183871Syz147064 const char *
9193871Syz147064 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
9203871Syz147064 {
9213871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
9223871Syz147064 	    (float)(*speed) / 2);
9233871Syz147064 	return (buf);
9243871Syz147064 }
9253871Syz147064 
9263871Syz147064 const char *
9273871Syz147064 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
9283871Syz147064 {
9293871Syz147064 	return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
9303871Syz147064 	    VALCNT(auth_vals), buf));
9313871Syz147064 }
9323871Syz147064 
9333871Syz147064 const char *
9343871Syz147064 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
9353871Syz147064 {
9363871Syz147064 	return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
9373871Syz147064 	    VALCNT(bsstype_vals), buf));
9383871Syz147064 }
9393871Syz147064 
9403871Syz147064 const char *
9413871Syz147064 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
9423871Syz147064 {
9433871Syz147064 	return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
9443871Syz147064 	    VALCNT(linkstatus_vals), buf));
9453871Syz147064 }
9463871Syz147064 
9473871Syz147064 dladm_status_t
9483871Syz147064 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
9493871Syz147064 {
9506834Sff224033 	if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1)
9513871Syz147064 		return (DLADM_STATUS_BADARG);
9523871Syz147064 
9533871Syz147064 	(void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
9543871Syz147064 	return (DLADM_STATUS_OK);
9553871Syz147064 }
9563871Syz147064 
9573871Syz147064 dladm_status_t
9583871Syz147064 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
9593871Syz147064 {
9603871Syz147064 	int	len;
9613871Syz147064 	uchar_t	*buf;
9623871Syz147064 
9633871Syz147064 	buf = _link_aton(str, &len);
9643871Syz147064 	if (buf == NULL)
9653871Syz147064 		return (DLADM_STATUS_BADARG);
9663871Syz147064 
9673871Syz147064 	if (len != DLADM_WLAN_BSSID_LEN) {
9683871Syz147064 		free(buf);
9693871Syz147064 		return (DLADM_STATUS_BADARG);
9703871Syz147064 	}
9713871Syz147064 
9723871Syz147064 	(void) memcpy(bssid->wb_bytes, buf, len);
9733871Syz147064 	free(buf);
9743871Syz147064 	return (DLADM_STATUS_OK);
9753871Syz147064 }
9763871Syz147064 
9773871Syz147064 dladm_status_t
9783871Syz147064 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
9793871Syz147064 {
9803871Syz147064 	uint_t	val;
9813871Syz147064 
9823871Syz147064 	if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
9833871Syz147064 		return (DLADM_STATUS_BADARG);
9843871Syz147064 
9853871Syz147064 	*secmode = (dladm_wlan_secmode_t)val;
9863871Syz147064 	return (DLADM_STATUS_OK);
9873871Syz147064 }
9883871Syz147064 
9893871Syz147064 dladm_status_t
9903871Syz147064 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
9913871Syz147064 {
9923871Syz147064 	uint_t	val;
9933871Syz147064 
9943871Syz147064 	if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
9953871Syz147064 		return (DLADM_STATUS_BADARG);
9963871Syz147064 
9973871Syz147064 	*strength = (dladm_wlan_strength_t)val;
9983871Syz147064 	return (DLADM_STATUS_OK);
9993871Syz147064 }
10003871Syz147064 
10013871Syz147064 dladm_status_t
10023871Syz147064 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
10033871Syz147064 {
10043871Syz147064 	uint_t	val;
10053871Syz147064 
10063871Syz147064 	if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
10073871Syz147064 		return (DLADM_STATUS_BADARG);
10083871Syz147064 
10093871Syz147064 	*mode = (dladm_wlan_mode_t)val;
10103871Syz147064 	return (DLADM_STATUS_OK);
10113871Syz147064 }
10123871Syz147064 
10133871Syz147064 dladm_status_t
10143871Syz147064 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
10153871Syz147064 {
10163871Syz147064 	*speed = (dladm_wlan_speed_t)(atof(str) * 2);
10173871Syz147064 	return (DLADM_STATUS_OK);
10183871Syz147064 }
10193871Syz147064 
10203871Syz147064 dladm_status_t
10213871Syz147064 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
10223871Syz147064 {
10233871Syz147064 	uint_t	val;
10243871Syz147064 
10253871Syz147064 	if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
10263871Syz147064 		return (DLADM_STATUS_BADARG);
10273871Syz147064 
10283871Syz147064 	*auth = (dladm_wlan_auth_t)val;
10293871Syz147064 	return (DLADM_STATUS_OK);
10303871Syz147064 }
10313871Syz147064 
10323871Syz147064 dladm_status_t
10333871Syz147064 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
10343871Syz147064 {
10353871Syz147064 	uint_t	val;
10363871Syz147064 
10373871Syz147064 	if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
10383871Syz147064 		return (DLADM_STATUS_BADARG);
10393871Syz147064 
10403871Syz147064 	*bsstype = (dladm_wlan_bsstype_t)val;
10413871Syz147064 	return (DLADM_STATUS_OK);
10423871Syz147064 }
10433871Syz147064 
10443871Syz147064 dladm_status_t
10453871Syz147064 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
10463871Syz147064 {
10473871Syz147064 	uint_t	val;
10483871Syz147064 
10495895Syz147064 	if (!find_val_by_name(str, linkstatus_vals,
10505895Syz147064 	    VALCNT(linkstatus_vals), &val)) {
10513871Syz147064 		return (DLADM_STATUS_BADARG);
10525895Syz147064 	}
10533871Syz147064 
10543871Syz147064 	*linkstatus = (dladm_wlan_linkstatus_t)val;
10553871Syz147064 	return (DLADM_STATUS_OK);
10563871Syz147064 }
10573871Syz147064 
10585895Syz147064 dladm_status_t
1059*7663SSowmini.Varadhan@Sun.COM i_dladm_wlan_legacy_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id,
1060*7663SSowmini.Varadhan@Sun.COM     size_t len, uint_t cmd, size_t cmdlen)
10613871Syz147064 {
10625895Syz147064 	char			linkname[MAXPATHLEN];
10635895Syz147064 	int			fd, rc;
10643871Syz147064 	struct	strioctl	stri;
10655895Syz147064 	uint32_t		flags;
10665895Syz147064 	dladm_status_t		status;
10675895Syz147064 	uint32_t		media;
10685895Syz147064 	char			link[MAXLINKNAMELEN];
10695895Syz147064 
10705895Syz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media,
10715895Syz147064 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
10725895Syz147064 		return (status);
10735895Syz147064 	}
10745895Syz147064 
10755895Syz147064 	if (media != DL_WIFI)
10765895Syz147064 		return (DLADM_STATUS_BADARG);
10775895Syz147064 
10785895Syz147064 	if (!(flags & DLADM_OPT_ACTIVE))
10795895Syz147064 		return (DLADM_STATUS_TEMPONLY);
10805895Syz147064 
10815895Syz147064 	/*
10825895Syz147064 	 * dlpi_open() is not used here because libdlpi depends on libdladm,
10835895Syz147064 	 * and we do not want to introduce recursive dependencies.
10845895Syz147064 	 */
10855895Syz147064 	(void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
10865895Syz147064 	if ((fd = open(linkname, O_RDWR)) < 0)
10877408SSebastien.Roy@Sun.COM 		return (dladm_errno2status(errno));
10883871Syz147064 
10893871Syz147064 	gbuf->wldp_type = NET_802_11;
10903871Syz147064 	gbuf->wldp_id	= id;
10913871Syz147064 	gbuf->wldp_length = len;
10923871Syz147064 
10933871Syz147064 	stri.ic_timout	= 0;
10943871Syz147064 	stri.ic_dp	= (char *)gbuf;
10953871Syz147064 	stri.ic_cmd	= cmd;
10963871Syz147064 	stri.ic_len	= cmdlen;
10973871Syz147064 
10983871Syz147064 	if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
10995895Syz147064 		if (rc > 0) {
11005895Syz147064 			/*
11015895Syz147064 			 * Non-negative return value indicates the specific
11025895Syz147064 			 * operation failed and the reason for the failure
11035895Syz147064 			 * was stored in gbuf->wldp_result.
11045895Syz147064 			 */
11055895Syz147064 			status = dladm_wlan_wlresult2status(gbuf);
11065895Syz147064 		} else {
11075895Syz147064 			/*
11085895Syz147064 			 * Negative return value indicates the ioctl failed.
11095895Syz147064 			 */
11105895Syz147064 			status = dladm_errno2status(errno);
11115895Syz147064 		}
11123871Syz147064 	}
11135895Syz147064 	(void) close(fd);
11145895Syz147064 	return (status);
11153871Syz147064 }
11163871Syz147064 
1117*7663SSowmini.Varadhan@Sun.COM static dladm_status_t
1118*7663SSowmini.Varadhan@Sun.COM do_cmd_ioctl(datalink_id_t linkid, void *buf, int buflen, uint_t cmd)
11193871Syz147064 {
11205895Syz147064 	wldp_t *gbuf;
11215895Syz147064 	dladm_status_t status = DLADM_STATUS_OK;
11225895Syz147064 
11235895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
11245895Syz147064 		return (DLADM_STATUS_NOMEM);
11255895Syz147064 
11263871Syz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1127*7663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, cmd, WLDP_BUFSIZE,
1128*7663SSowmini.Varadhan@Sun.COM 	    WLAN_COMMAND, sizeof (wldp_t));
1129*7663SSowmini.Varadhan@Sun.COM 	(void) memcpy(buf, gbuf->wldp_buf, buflen);
11305895Syz147064 	free(gbuf);
11315895Syz147064 	return (status);
11323871Syz147064 }
11333871Syz147064 
11345895Syz147064 static dladm_status_t
1135*7663SSowmini.Varadhan@Sun.COM do_scan(datalink_id_t linkid, void *buf, int buflen)
11363871Syz147064 {
1137*7663SSowmini.Varadhan@Sun.COM 	return (do_cmd_ioctl(linkid, buf, buflen, WL_SCAN));
11383871Syz147064 }
11393871Syz147064 
11405895Syz147064 static dladm_status_t
1141*7663SSowmini.Varadhan@Sun.COM do_disconnect(datalink_id_t linkid, void *buf, int buflen)
11423871Syz147064 {
1143*7663SSowmini.Varadhan@Sun.COM 	if (do_get_wpamode(linkid, buf, buflen) == 0 &&
1144*7663SSowmini.Varadhan@Sun.COM 	    ((wl_wpa_t *)(buf))->wpa_flag > 0)
1145*7663SSowmini.Varadhan@Sun.COM 		(void) wpa_instance_delete(linkid);
1146*7663SSowmini.Varadhan@Sun.COM 
1147*7663SSowmini.Varadhan@Sun.COM 	return (do_cmd_ioctl(linkid, buf, buflen, WL_DISASSOCIATE));
11483871Syz147064 }
11493871Syz147064 
11505895Syz147064 static dladm_status_t
1151*7663SSowmini.Varadhan@Sun.COM do_get_esslist(datalink_id_t linkid, void *buf, int buflen)
11523871Syz147064 {
1153*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_ESS_LIST, buflen,
1154*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
11553871Syz147064 }
11563871Syz147064 
11575895Syz147064 static dladm_status_t
1158*7663SSowmini.Varadhan@Sun.COM do_get_bssid(datalink_id_t linkid, void *buf, int buflen)
11593871Syz147064 {
1160*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_BSSID, buflen,
1161*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
11623871Syz147064 }
11633871Syz147064 
11645895Syz147064 static dladm_status_t
1165*7663SSowmini.Varadhan@Sun.COM do_get_essid(datalink_id_t linkid, void *buf, int buflen)
11663871Syz147064 {
1167*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_ESSID, buflen,
1168*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
11693871Syz147064 }
11703871Syz147064 
11715895Syz147064 static dladm_status_t
1172*7663SSowmini.Varadhan@Sun.COM do_get_bsstype(datalink_id_t linkid, void *buf, int buflen)
11733871Syz147064 {
1174*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_BSSTYPE, buflen,
1175*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
11763871Syz147064 }
11773871Syz147064 
11785895Syz147064 static dladm_status_t
1179*7663SSowmini.Varadhan@Sun.COM do_get_linkstatus(datalink_id_t linkid, void *buf, int buflen)
11803871Syz147064 {
1181*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_LINKSTATUS, buflen,
1182*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
11833871Syz147064 }
11843871Syz147064 
11855895Syz147064 static dladm_status_t
1186*7663SSowmini.Varadhan@Sun.COM do_get_rate(datalink_id_t linkid, void *buf, int buflen)
11873871Syz147064 {
1188*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_DESIRED_RATES,
1189*7663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
11903871Syz147064 }
11913871Syz147064 
11923871Syz147064 static dladm_status_t
1193*7663SSowmini.Varadhan@Sun.COM do_get_authmode(datalink_id_t linkid, void *buf, int buflen)
11943871Syz147064 {
1195*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_AUTH_MODE, buflen,
1196*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
11973871Syz147064 }
11983871Syz147064 
11993871Syz147064 static dladm_status_t
1200*7663SSowmini.Varadhan@Sun.COM do_get_encryption(datalink_id_t linkid, void *buf, int buflen)
12013871Syz147064 {
1202*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_ENCRYPTION, buflen,
1203*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
12043871Syz147064 }
12053871Syz147064 
12063871Syz147064 static dladm_status_t
1207*7663SSowmini.Varadhan@Sun.COM do_get_signal(datalink_id_t linkid, void *buf, int buflen)
12083871Syz147064 {
1209*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_RSSI, buflen,
1210*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
12113871Syz147064 }
12123871Syz147064 
12133871Syz147064 static dladm_status_t
1214*7663SSowmini.Varadhan@Sun.COM do_get_mode(datalink_id_t linkid, void *buf, int buflen)
12153871Syz147064 {
1216*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_PHY_CONFIG,
1217*7663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
12183871Syz147064 }
12193871Syz147064 
12205895Syz147064 static dladm_status_t
12215895Syz147064 do_set_bsstype(datalink_id_t linkid, dladm_wlan_bsstype_t *bsstype)
12223871Syz147064 {
12233871Syz147064 	wl_bss_type_t	ibsstype;
12243871Syz147064 
12253871Syz147064 	switch (*bsstype) {
12263871Syz147064 	case DLADM_WLAN_BSSTYPE_BSS:
12273871Syz147064 		ibsstype = WL_BSS_BSS;
12283871Syz147064 		break;
12293871Syz147064 	case DLADM_WLAN_BSSTYPE_IBSS:
12303871Syz147064 		ibsstype = WL_BSS_IBSS;
12313871Syz147064 		break;
12323871Syz147064 	default:
12333871Syz147064 		ibsstype = WL_BSS_ANY;
12343871Syz147064 		break;
12353871Syz147064 	}
1236*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &ibsstype, MAC_PROP_WL_BSSTYPE,
1237*7663SSowmini.Varadhan@Sun.COM 	    sizeof (ibsstype), B_TRUE));
12383871Syz147064 }
12393871Syz147064 
12405895Syz147064 static dladm_status_t
12415895Syz147064 do_set_authmode(datalink_id_t linkid, dladm_wlan_auth_t *auth)
12423871Syz147064 {
12433871Syz147064 	wl_authmode_t	auth_mode;
12443871Syz147064 
12453871Syz147064 	switch (*auth) {
12463871Syz147064 	case DLADM_WLAN_AUTH_OPEN:
12473871Syz147064 		auth_mode = WL_OPENSYSTEM;
12483871Syz147064 		break;
12493871Syz147064 	case DLADM_WLAN_AUTH_SHARED:
12503871Syz147064 		auth_mode = WL_SHAREDKEY;
12513871Syz147064 		break;
12523871Syz147064 	default:
12535895Syz147064 		return (DLADM_STATUS_NOTSUP);
12543871Syz147064 	}
1255*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &auth_mode, MAC_PROP_WL_AUTH_MODE,
1256*7663SSowmini.Varadhan@Sun.COM 	    sizeof (auth_mode), B_TRUE));
12573871Syz147064 }
12583871Syz147064 
12595895Syz147064 static dladm_status_t
12605895Syz147064 do_set_encryption(datalink_id_t linkid, dladm_wlan_secmode_t *secmode)
12613871Syz147064 {
12623871Syz147064 	wl_encryption_t	encryption;
12633871Syz147064 
12643871Syz147064 	switch (*secmode) {
12653871Syz147064 	case DLADM_WLAN_SECMODE_NONE:
12663871Syz147064 		encryption = WL_NOENCRYPTION;
12673871Syz147064 		break;
12683871Syz147064 	case DLADM_WLAN_SECMODE_WEP:
12693871Syz147064 		encryption = WL_ENC_WEP;
12703871Syz147064 		break;
12714126Szf162725 	case DLADM_WLAN_SECMODE_WPA:
12724126Szf162725 		return (0);
12733871Syz147064 	default:
12745895Syz147064 		return (DLADM_STATUS_NOTSUP);
12753871Syz147064 	}
1276*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &encryption, MAC_PROP_WL_ENCRYPTION,
1277*7663SSowmini.Varadhan@Sun.COM 	    sizeof (encryption), B_TRUE));
12783871Syz147064 }
12793871Syz147064 
12805895Syz147064 static dladm_status_t
12815895Syz147064 do_set_key(datalink_id_t linkid, dladm_wlan_key_t *keys,
12823871Syz147064     uint_t key_count)
12833871Syz147064 {
12843871Syz147064 	int			i;
12853871Syz147064 	wl_wep_key_t		*wkp;
12863871Syz147064 	wl_wep_key_tab_t	wepkey_tab;
12874126Szf162725 	dladm_wlan_key_t	*kp;
12883871Syz147064 
12893871Syz147064 	if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
12905895Syz147064 		return (DLADM_STATUS_BADARG);
12913871Syz147064 
12923871Syz147064 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
12933871Syz147064 	for (i = 0; i < MAX_NWEPKEYS; i++)
12943871Syz147064 		wepkey_tab[i].wl_wep_operation = WL_NUL;
12953871Syz147064 
12963871Syz147064 	for (i = 0; i < key_count; i++) {
12973871Syz147064 		kp = &keys[i];
12983871Syz147064 		if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
12995895Syz147064 			return (DLADM_STATUS_BADARG);
13003871Syz147064 		if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
13013871Syz147064 		    kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
13025895Syz147064 			return (DLADM_STATUS_BADARG);
13033871Syz147064 
13043871Syz147064 		wkp = &wepkey_tab[kp->wk_idx - 1];
13053871Syz147064 		wkp->wl_wep_operation = WL_ADD;
13063871Syz147064 		wkp->wl_wep_length = kp->wk_len;
13073871Syz147064 		(void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
13083871Syz147064 	}
13093871Syz147064 
1310*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &wepkey_tab, MAC_PROP_WL_KEY_TAB,
1311*7663SSowmini.Varadhan@Sun.COM 	    sizeof (wepkey_tab), B_TRUE));
13123871Syz147064 }
13133871Syz147064 
13145895Syz147064 static dladm_status_t
13155895Syz147064 do_set_essid(datalink_id_t linkid, dladm_wlan_essid_t *essid)
13163871Syz147064 {
13173871Syz147064 	wl_essid_t	iessid;
13183871Syz147064 
13193871Syz147064 	(void) memset(&iessid, 0, sizeof (essid));
13203871Syz147064 
13213871Syz147064 	if (essid != NULL && essid->we_bytes[0] != '\0') {
13223871Syz147064 		iessid.wl_essid_length = strlen(essid->we_bytes);
13233871Syz147064 		(void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
13243871Syz147064 		    sizeof (iessid.wl_essid_essid));
13253871Syz147064 	} else {
13265895Syz147064 		return (DLADM_STATUS_BADARG);
13275102Syz147064 	}
1328*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &iessid, MAC_PROP_WL_ESSID,
1329*7663SSowmini.Varadhan@Sun.COM 	    sizeof (iessid), B_TRUE));
13303871Syz147064 }
13313871Syz147064 
13323871Syz147064 static dladm_status_t
13335895Syz147064 do_set_channel(datalink_id_t linkid, dladm_wlan_channel_t *channel)
13343871Syz147064 {
13353871Syz147064 	wl_phy_conf_t phy_conf;
13363871Syz147064 
13373871Syz147064 	if (*channel > MAX_CHANNEL_NUM)
13385895Syz147064 		return (DLADM_STATUS_BADVAL);
13393871Syz147064 
13403871Syz147064 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
13413871Syz147064 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
13423871Syz147064 
1343*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &phy_conf, MAC_PROP_WL_PHY_CONFIG,
1344*7663SSowmini.Varadhan@Sun.COM 	    sizeof (phy_conf), B_TRUE));
13453871Syz147064 }
13463871Syz147064 
13475895Syz147064 static dladm_status_t
13485895Syz147064 do_set_createibss(datalink_id_t linkid, boolean_t *create_ibss)
13493871Syz147064 {
13503871Syz147064 	wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
13513871Syz147064 
1352*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &cr, MAC_PROP_WL_CREATE_IBSS,
1353*7663SSowmini.Varadhan@Sun.COM 	    sizeof (cr), B_TRUE));
13543871Syz147064 }
13553871Syz147064 
13563871Syz147064 static void
13573871Syz147064 generate_essid(dladm_wlan_essid_t *essid)
13583871Syz147064 {
13593871Syz147064 	srandom(gethrtime());
13603871Syz147064 	(void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
13613871Syz147064 	    random());
13623871Syz147064 }
13634126Szf162725 
13645895Syz147064 static dladm_status_t
1365*7663SSowmini.Varadhan@Sun.COM do_get_capability(datalink_id_t linkid, void *buf, int buflen)
13664126Szf162725 {
1367*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_CAPABILITY,
1368*7663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
13694126Szf162725 }
13704126Szf162725 
13714126Szf162725 static dladm_status_t
1372*7663SSowmini.Varadhan@Sun.COM do_get_wpamode(datalink_id_t linkid, void *buf, int buflen)
13734126Szf162725 {
1374*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_WPA, buflen,
1375*7663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
13764126Szf162725 }
13774126Szf162725 
13784126Szf162725 dladm_status_t
13795895Syz147064 dladm_wlan_wpa_get_sr(datalink_id_t linkid, dladm_wlan_ess_t *sr,
13805895Syz147064     uint_t escnt, uint_t *estot)
13814126Szf162725 {
13824126Szf162725 	int		i, n;
13834126Szf162725 	wl_wpa_ess_t	*es;
13844126Szf162725 	dladm_status_t	status;
13854126Szf162725 
1386*7663SSowmini.Varadhan@Sun.COM 	es = malloc(WLDP_BUFSIZE);
1387*7663SSowmini.Varadhan@Sun.COM 	if (es == NULL)
13884126Szf162725 		return (DLADM_STATUS_NOMEM);
13894126Szf162725 
1390*7663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_param(linkid, es, MAC_PROP_WL_SCANRESULTS,
1391*7663SSowmini.Varadhan@Sun.COM 	    WLDP_BUFSIZE, B_FALSE);
13924126Szf162725 
13934126Szf162725 	if (status == DLADM_STATUS_OK) {
13944126Szf162725 		n = (es->count > escnt) ? escnt : es->count;
13954126Szf162725 		for (i = 0; i < n; i ++) {
13964126Szf162725 			(void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
13974126Szf162725 			    DLADM_WLAN_BSSID_LEN);
13984126Szf162725 			sr[i].we_ssid_len = es->ess[i].ssid_len;
13994126Szf162725 			(void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
14004126Szf162725 			    es->ess[i].ssid_len);
14014126Szf162725 			sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
14024126Szf162725 			(void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
14034126Szf162725 			    es->ess[i].wpa_ie_len);
14044126Szf162725 			sr[i].we_freq = es->ess[i].freq;
14054126Szf162725 		}
14064126Szf162725 		*estot = n;
14074126Szf162725 	}
14084126Szf162725 
1409*7663SSowmini.Varadhan@Sun.COM 	free(es);
14104126Szf162725 	return (status);
14114126Szf162725 }
14124126Szf162725 
14134126Szf162725 dladm_status_t
14145895Syz147064 dladm_wlan_wpa_set_ie(datalink_id_t linkid, uint8_t *wpa_ie, uint_t wpa_ie_len)
14154126Szf162725 {
14164126Szf162725 	wl_wpa_ie_t *ie;
14174126Szf162725 	uint_t len;
14184126Szf162725 	dladm_status_t	status;
14194126Szf162725 
14204126Szf162725 	if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
14214126Szf162725 		return (DLADM_STATUS_BADARG);
14224126Szf162725 	len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
14234126Szf162725 	ie = malloc(len);
14244126Szf162725 	if (ie == NULL)
14254126Szf162725 		return (DLADM_STATUS_NOMEM);
14264126Szf162725 
14274126Szf162725 	(void) memset(ie, 0, len);
14284126Szf162725 	ie->wpa_ie_len = wpa_ie_len;
14294126Szf162725 	(void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
14304126Szf162725 
1431*7663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_param(linkid, ie, MAC_PROP_WL_SETOPTIE, len,
1432*7663SSowmini.Varadhan@Sun.COM 	    B_TRUE);
14334126Szf162725 	free(ie);
14344126Szf162725 
14354126Szf162725 	return (status);
14364126Szf162725 }
14374126Szf162725 
14384126Szf162725 dladm_status_t
14395895Syz147064 dladm_wlan_wpa_set_wpa(datalink_id_t linkid, boolean_t flag)
14404126Szf162725 {
14415895Syz147064 	wl_wpa_t	wpa;
14424126Szf162725 
14434126Szf162725 	wpa.wpa_flag = flag;
1444*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &wpa, MAC_PROP_WL_WPA,
1445*7663SSowmini.Varadhan@Sun.COM 	    sizeof (wpa), B_TRUE));
14464126Szf162725 }
14474126Szf162725 
14484126Szf162725 dladm_status_t
14495895Syz147064 dladm_wlan_wpa_del_key(datalink_id_t linkid, uint_t key_idx,
14504126Szf162725     const dladm_wlan_bssid_t *addr)
14514126Szf162725 {
14525895Syz147064 	wl_del_key_t	wk;
14534126Szf162725 
14544126Szf162725 	wk.idk_keyix = key_idx;
14554126Szf162725 	if (addr != NULL)
14564126Szf162725 		(void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
14574126Szf162725 		    DLADM_WLAN_BSSID_LEN);
14584126Szf162725 
1459*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &wk, MAC_PROP_WL_DELKEY,
1460*7663SSowmini.Varadhan@Sun.COM 	    sizeof (wk), B_TRUE));
14614126Szf162725 }
14624126Szf162725 
14634126Szf162725 dladm_status_t
14645895Syz147064 dladm_wlan_wpa_set_key(datalink_id_t linkid, dladm_wlan_cipher_t cipher,
14654126Szf162725     const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq,
14664126Szf162725     uint_t key_idx, uint8_t *key, uint_t key_len)
14674126Szf162725 {
14685895Syz147064 	wl_key_t	wk;
14694126Szf162725 
14704126Szf162725 	(void) memset(&wk, 0, sizeof (wl_key_t));
14714126Szf162725 	switch (cipher) {
14724126Szf162725 	case DLADM_WLAN_CIPHER_WEP:
14734126Szf162725 		wk.ik_type = IEEE80211_CIPHER_WEP;
14744126Szf162725 		break;
14754126Szf162725 	case DLADM_WLAN_CIPHER_TKIP:
14764126Szf162725 		wk.ik_type = IEEE80211_CIPHER_TKIP;
14774126Szf162725 		break;
14784126Szf162725 	case DLADM_WLAN_CIPHER_AES_OCB:
14794126Szf162725 		wk.ik_type = IEEE80211_CIPHER_AES_OCB;
14804126Szf162725 		break;
14814126Szf162725 	case DLADM_WLAN_CIPHER_AES_CCM:
14824126Szf162725 		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
14834126Szf162725 		break;
14844126Szf162725 	case DLADM_WLAN_CIPHER_CKIP:
14854126Szf162725 		wk.ik_type = IEEE80211_CIPHER_CKIP;
14864126Szf162725 		break;
14874126Szf162725 	case DLADM_WLAN_CIPHER_NONE:
14884126Szf162725 		wk.ik_type = IEEE80211_CIPHER_NONE;
14894126Szf162725 		break;
14904126Szf162725 	default:
14914126Szf162725 		return (DLADM_STATUS_BADARG);
14924126Szf162725 	}
14934126Szf162725 	wk.ik_flags = IEEE80211_KEY_RECV;
14944126Szf162725 	if (set_tx) {
14954126Szf162725 		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
14964126Szf162725 		(void) memcpy(wk.ik_macaddr, addr->wb_bytes,
14974126Szf162725 		    DLADM_WLAN_BSSID_LEN);
14984126Szf162725 	} else
14994126Szf162725 		(void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
15004126Szf162725 	wk.ik_keyix = key_idx;
15014126Szf162725 	wk.ik_keylen = key_len;
15024126Szf162725 	(void) memcpy(&wk.ik_keyrsc, &seq, 6);	/* only use 48-bit of seq */
15034126Szf162725 	(void) memcpy(wk.ik_keydata, key, key_len);
15044126Szf162725 
1505*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &wk, MAC_PROP_WL_KEY,
1506*7663SSowmini.Varadhan@Sun.COM 	    sizeof (wk), B_TRUE));
15074126Szf162725 }
15084126Szf162725 
15094126Szf162725 dladm_status_t
15105895Syz147064 dladm_wlan_wpa_set_mlme(datalink_id_t linkid, dladm_wlan_mlme_op_t op,
15114126Szf162725     dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid)
15124126Szf162725 {
15134126Szf162725 	wl_mlme_t mlme;
15144126Szf162725 
15154126Szf162725 	(void) memset(&mlme, 0, sizeof (wl_mlme_t));
15164126Szf162725 	switch (op) {
15174126Szf162725 	case DLADM_WLAN_MLME_ASSOC:
15184126Szf162725 		mlme.im_op = IEEE80211_MLME_ASSOC;
15194126Szf162725 		break;
15204126Szf162725 	case DLADM_WLAN_MLME_DISASSOC:
15214126Szf162725 		mlme.im_op = IEEE80211_MLME_DISASSOC;
15224126Szf162725 		break;
15234126Szf162725 	default:
15244126Szf162725 		return (DLADM_STATUS_BADARG);
15254126Szf162725 	}
15264126Szf162725 	mlme.im_reason = reason;
15274126Szf162725 	if (bssid != NULL)
15284126Szf162725 		(void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
15294126Szf162725 		    DLADM_WLAN_BSSID_LEN);
15304126Szf162725 
1531*7663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &mlme, MAC_PROP_WL_MLME,
1532*7663SSowmini.Varadhan@Sun.COM 	    sizeof (mlme), B_TRUE));
15334126Szf162725 }
15344126Szf162725 
15354126Szf162725 /*
15364126Szf162725  * routines of create instance
15374126Szf162725  */
15384126Szf162725 static scf_propertygroup_t *
15394126Szf162725 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
15404126Szf162725     const char *pg_name, const char *pg_type)
15414126Szf162725 {
15424126Szf162725 	scf_propertygroup_t *pg;
15434126Szf162725 
15444126Szf162725 	pg = scf_pg_create(handle);
15454126Szf162725 	if (pg == NULL)
15464126Szf162725 		return (NULL);
15474126Szf162725 
15484126Szf162725 	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
15494126Szf162725 		scf_pg_destroy(pg);
15504126Szf162725 		return (NULL);
15514126Szf162725 	}
15524126Szf162725 
15534126Szf162725 	return (pg);
15544126Szf162725 }
15554126Szf162725 
15565895Syz147064 static dladm_status_t
15574126Szf162725 add_new_property(scf_handle_t *handle, const char *prop_name,
15584126Szf162725     scf_type_t type, const char *val, scf_transaction_t *tx)
15594126Szf162725 {
15604126Szf162725 	scf_value_t *value = NULL;
15614126Szf162725 	scf_transaction_entry_t *entry = NULL;
15624126Szf162725 
15634126Szf162725 	entry = scf_entry_create(handle);
15644126Szf162725 	if (entry == NULL)
15654126Szf162725 		goto out;
15664126Szf162725 
15674126Szf162725 	value = scf_value_create(handle);
15684126Szf162725 	if (value == NULL)
15694126Szf162725 		goto out;
15704126Szf162725 
15714126Szf162725 	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
15724126Szf162725 		goto out;
15734126Szf162725 
15744126Szf162725 	if (scf_value_set_from_string(value, type, val) != 0)
15754126Szf162725 		goto out;
15764126Szf162725 
15774126Szf162725 	if (scf_entry_add_value(entry, value) != 0)
15784126Szf162725 		goto out;
15794126Szf162725 
15805895Syz147064 	return (DLADM_STATUS_OK);
15814126Szf162725 
15824126Szf162725 out:
15834126Szf162725 	if (value != NULL)
15844126Szf162725 		scf_value_destroy(value);
15854126Szf162725 	if (entry != NULL)
15864126Szf162725 		scf_entry_destroy(entry);
15874126Szf162725 
15885895Syz147064 	return (DLADM_STATUS_FAILED);
15894126Szf162725 }
15904126Szf162725 
15915895Syz147064 static dladm_status_t
15924126Szf162725 add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
15934126Szf162725     const char *pg_name, const char *flags)
15944126Szf162725 {
15954126Szf162725 	int			rv, size;
15965895Syz147064 	dladm_status_t		status = DLADM_STATUS_FAILED;
15974126Szf162725 	char			*command = NULL;
15984126Szf162725 	scf_transaction_t	*tran = NULL;
15994126Szf162725 	scf_propertygroup_t	*pg;
16004126Szf162725 
16014126Szf162725 	pg = add_property_group_to_instance(handle, instance,
16024126Szf162725 	    pg_name, SCF_GROUP_METHOD);
16034126Szf162725 	if (pg == NULL)
16044126Szf162725 		goto out;
16054126Szf162725 
16064126Szf162725 	tran = scf_transaction_create(handle);
16074126Szf162725 	if (tran == NULL)
16084126Szf162725 		goto out;
16094126Szf162725 
16104126Szf162725 	size = strlen(SVC_METHOD) + strlen("  ") + strlen(flags) + 1;
16114126Szf162725 	command = malloc(size);
16124126Szf162725 	if (command == NULL) {
16135895Syz147064 		status = DLADM_STATUS_NOMEM;
16144126Szf162725 		goto out;
16154126Szf162725 	}
16164126Szf162725 	(void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
16174126Szf162725 
16184126Szf162725 	do {
16194126Szf162725 		if (scf_transaction_start(tran, pg) != 0)
16204126Szf162725 			goto out;
16214126Szf162725 
16224126Szf162725 		if (add_new_property(handle, SCF_PROPERTY_EXEC,
16235895Syz147064 		    SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
16244126Szf162725 			goto out;
16254126Szf162725 		}
16264126Szf162725 
16274126Szf162725 		rv = scf_transaction_commit(tran);
16284126Szf162725 		switch (rv) {
16294126Szf162725 		case 1:
16305895Syz147064 			status = DLADM_STATUS_OK;
16314126Szf162725 			goto out;
16324126Szf162725 		case 0:
16334126Szf162725 			scf_transaction_destroy_children(tran);
16344126Szf162725 			if (scf_pg_update(pg) == -1) {
16354126Szf162725 				goto out;
16364126Szf162725 			}
16374126Szf162725 			break;
16384126Szf162725 		case -1:
16394126Szf162725 		default:
16404126Szf162725 			goto out;
16414126Szf162725 		}
16424126Szf162725 	} while (rv == 0);
16434126Szf162725 
16444126Szf162725 out:
16454126Szf162725 	if (tran != NULL) {
16464126Szf162725 		scf_transaction_destroy_children(tran);
16474126Szf162725 		scf_transaction_destroy(tran);
16484126Szf162725 	}
16494126Szf162725 
16504126Szf162725 	if (pg != NULL)
16514126Szf162725 		scf_pg_destroy(pg);
16524126Szf162725 
16534126Szf162725 	if (command != NULL)
16544126Szf162725 		free(command);
16554126Szf162725 
16564126Szf162725 	return (status);
16574126Szf162725 }
16584126Szf162725 
16595895Syz147064 static dladm_status_t
16604126Szf162725 do_create_instance(scf_handle_t *handle, scf_service_t *svc,
16614126Szf162725     const char *instance_name, const char *command)
16624126Szf162725 {
16635895Syz147064 	dladm_status_t status = DLADM_STATUS_FAILED;
16644126Szf162725 	char *buf;
16654126Szf162725 	ssize_t max_fmri_len;
16664126Szf162725 	scf_instance_t *instance;
16674126Szf162725 
16684126Szf162725 	instance = scf_instance_create(handle);
16694126Szf162725 	if (instance == NULL)
16704126Szf162725 		goto out;
16714126Szf162725 
16724126Szf162725 	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
16734126Szf162725 		if (scf_error() == SCF_ERROR_EXISTS)
16744126Szf162725 			/* Let the caller deal with the duplicate instance */
16755895Syz147064 			status = DLADM_STATUS_EXIST;
16764126Szf162725 		goto out;
16774126Szf162725 	}
16784126Szf162725 
16794126Szf162725 	if (add_pg_method(handle, instance, "start",
16805895Syz147064 	    command) != DLADM_STATUS_OK) {
16814126Szf162725 		goto out;
16824126Szf162725 	}
16834126Szf162725 
16844126Szf162725 	/* enabling the instance */
16854126Szf162725 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
16864126Szf162725 	if ((buf = malloc(max_fmri_len + 1)) == NULL)
16874126Szf162725 		goto out;
16884126Szf162725 
16894126Szf162725 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
16904126Szf162725 		if ((smf_disable_instance(buf, 0) != 0) ||
16914126Szf162725 		    (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
16924126Szf162725 			goto out;
16934126Szf162725 		}
16945895Syz147064 		status = DLADM_STATUS_OK;
16954126Szf162725 	}
16964126Szf162725 
16974126Szf162725 out:
16984126Szf162725 	if (instance != NULL)
16994126Szf162725 		scf_instance_destroy(instance);
17004126Szf162725 	return (status);
17014126Szf162725 }
17024126Szf162725 
17035895Syz147064 static dladm_status_t
17044126Szf162725 create_instance(const char *instance_name, const char *command)
17054126Szf162725 {
17065895Syz147064 	dladm_status_t status = DLADM_STATUS_FAILED;
17074126Szf162725 	scf_service_t *svc = NULL;
17084126Szf162725 	scf_handle_t *handle = NULL;
17094126Szf162725 
17104126Szf162725 	handle = scf_handle_create(SCF_VERSION);
17114126Szf162725 	if (handle == NULL)
17124126Szf162725 		goto out;
17134126Szf162725 
17144126Szf162725 	if (scf_handle_bind(handle) == -1)
17154126Szf162725 		goto out;
17164126Szf162725 
17174126Szf162725 	if ((svc = scf_service_create(handle)) == NULL)
17184126Szf162725 		goto out;
17194126Szf162725 
17204126Szf162725 	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
17214126Szf162725 	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
17224126Szf162725 		goto out;
17234126Szf162725 
17244126Szf162725 	status = do_create_instance(handle, svc, instance_name, command);
17254126Szf162725 
17264126Szf162725 out:
17274126Szf162725 	if (svc != NULL)
17284126Szf162725 		scf_service_destroy(svc);
17294126Szf162725 
17304126Szf162725 	if (handle != NULL) {
17314126Szf162725 		(void) scf_handle_unbind(handle);
17324126Szf162725 		scf_handle_destroy(handle);
17334126Szf162725 	}
17344126Szf162725 
17354126Szf162725 	return (status);
17364126Szf162725 }
17374126Szf162725 
17384126Szf162725 /*
17394126Szf162725  * routines of delete instance
17404126Szf162725  */
17414126Szf162725 #define	DEFAULT_TIMEOUT	60000000
17424126Szf162725 #define	INIT_WAIT_USECS	50000
17434126Szf162725 
17444126Szf162725 static void
17454126Szf162725 wait_until_disabled(scf_handle_t *handle, char *fmri)
17464126Szf162725 {
17474126Szf162725 	char		*state;
17484126Szf162725 	useconds_t	max;
17494126Szf162725 	useconds_t	usecs;
17504126Szf162725 	uint64_t	*cp = NULL;
17514126Szf162725 	scf_simple_prop_t *sp = NULL;
17524126Szf162725 
17534126Szf162725 	max = DEFAULT_TIMEOUT;
17544126Szf162725 
17554126Szf162725 	if (((sp = scf_simple_prop_get(handle, fmri, "stop",
17564126Szf162725 	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
17574126Szf162725 	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
17584126Szf162725 		max = (*cp) * 1000000;	/* convert to usecs */
17594126Szf162725 
17604126Szf162725 	if (sp != NULL)
17614126Szf162725 		scf_simple_prop_free(sp);
17624126Szf162725 
17634126Szf162725 	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
17644126Szf162725 		/* incremental wait */
17654126Szf162725 		usecs *= 2;
17664126Szf162725 		usecs = (usecs > max) ? max : usecs;
17674126Szf162725 
17684126Szf162725 		(void) usleep(usecs);
17694126Szf162725 
17704126Szf162725 		/* Check state after the wait */
17714126Szf162725 		if ((state = smf_get_state(fmri)) != NULL) {
17724126Szf162725 			if (strcmp(state, "disabled") == 0)
17734126Szf162725 				return;
17744126Szf162725 		}
17754126Szf162725 	}
17764126Szf162725 }
17774126Szf162725 
17785895Syz147064 static dladm_status_t
17794126Szf162725 delete_instance(const char *instance_name)
17804126Szf162725 {
17815895Syz147064 	dladm_status_t	status = DLADM_STATUS_FAILED;
17824126Szf162725 	char		*buf;
17834126Szf162725 	ssize_t		max_fmri_len;
17844126Szf162725 	scf_scope_t	*scope = NULL;
17854126Szf162725 	scf_service_t	*svc = NULL;
17864126Szf162725 	scf_handle_t	*handle = NULL;
17874126Szf162725 	scf_instance_t	*instance;
17884126Szf162725 
17894126Szf162725 	handle = scf_handle_create(SCF_VERSION);
17904126Szf162725 	if (handle == NULL)
17914126Szf162725 		goto out;
17924126Szf162725 
17934126Szf162725 	if (scf_handle_bind(handle) == -1)
17944126Szf162725 		goto out;
17954126Szf162725 
17964126Szf162725 	if ((scope = scf_scope_create(handle)) == NULL)
17974126Szf162725 		goto out;
17984126Szf162725 
17994126Szf162725 	if ((svc = scf_service_create(handle)) == NULL)
18004126Szf162725 		goto out;
18014126Szf162725 
18024126Szf162725 	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
18034126Szf162725 		goto out;
18044126Szf162725 
18054126Szf162725 	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
18064126Szf162725 		goto out;
18074126Szf162725 
18084126Szf162725 	instance = scf_instance_create(handle);
18094126Szf162725 	if (instance == NULL)
18104126Szf162725 		goto out;
18114126Szf162725 
18124126Szf162725 	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
18134126Szf162725 		scf_error_t scf_errnum = scf_error();
18144126Szf162725 
18154126Szf162725 		if (scf_errnum == SCF_ERROR_NOT_FOUND)
18165895Syz147064 			status = DLADM_STATUS_OK;
18174126Szf162725 
18184126Szf162725 		scf_instance_destroy(instance);
18194126Szf162725 		goto out;
18204126Szf162725 	}
18214126Szf162725 
18224126Szf162725 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
18234126Szf162725 	if ((buf = malloc(max_fmri_len + 1)) == NULL) {
18244126Szf162725 		scf_instance_destroy(instance);
18254126Szf162725 		goto out;
18264126Szf162725 	}
18274126Szf162725 
18284126Szf162725 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
18294126Szf162725 		char *state;
18304126Szf162725 
18314126Szf162725 		state = smf_get_state(buf);
18324126Szf162725 		if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
18334126Szf162725 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
18344126Szf162725 			if (smf_disable_instance(buf, 0) == 0) {
18354126Szf162725 				/*
18364126Szf162725 				 * Wait for some time till timeout to avoid
18374126Szf162725 				 * a race with scf_instance_delete() below.
18384126Szf162725 				 */
18394126Szf162725 				wait_until_disabled(handle, buf);
18404126Szf162725 			}
18414126Szf162725 		}
18424126Szf162725 	}
18434126Szf162725 
18444126Szf162725 	if (scf_instance_delete(instance) != 0) {
18454126Szf162725 		scf_instance_destroy(instance);
18464126Szf162725 		goto out;
18474126Szf162725 	}
18484126Szf162725 
18494126Szf162725 	scf_instance_destroy(instance);
18504126Szf162725 
18515895Syz147064 	status = DLADM_STATUS_OK;
18524126Szf162725 
18534126Szf162725 out:
18544126Szf162725 	if (svc != NULL)
18554126Szf162725 		scf_service_destroy(svc);
18564126Szf162725 
18574126Szf162725 	if (scope != NULL)
18584126Szf162725 		scf_scope_destroy(scope);
18594126Szf162725 
18604126Szf162725 	if (handle != NULL) {
18614126Szf162725 		(void) scf_handle_unbind(handle);
18624126Szf162725 		scf_handle_destroy(handle);
18634126Szf162725 	}
18644126Szf162725 
18654126Szf162725 	return (status);
18664126Szf162725 }
18674126Szf162725 
18685895Syz147064 static dladm_status_t
18695895Syz147064 wpa_instance_create(datalink_id_t linkid, void *key)
18704126Szf162725 {
18715895Syz147064 	dladm_status_t	status = DLADM_STATUS_FAILED;
18724126Szf162725 	char		*command = NULL;
18734126Szf162725 	char		*wk_name = ((dladm_wlan_key_t *)key)->wk_name;
18744126Szf162725 	int		size;
18755895Syz147064 	char		instance_name[MAXLINKNAMELEN];
18765895Syz147064 
18775895Syz147064 	/*
18785895Syz147064 	 * Use the link name as the instance name of the network/wpad service.
18795895Syz147064 	 */
18805895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name,
18815895Syz147064 	    sizeof (instance_name));
18825895Syz147064 	if (status != DLADM_STATUS_OK)
18835895Syz147064 		goto out;
18844126Szf162725 
18854126Szf162725 	size = strlen(instance_name) + strlen(" -i  -k ") + strlen(wk_name) + 1;
18864126Szf162725 	command = malloc(size);
18874126Szf162725 	if (command == NULL) {
18885895Syz147064 		status = DLADM_STATUS_NOMEM;
18894126Szf162725 		goto out;
18904126Szf162725 	}
18914126Szf162725 	(void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
18924126Szf162725 
18934126Szf162725 	status = create_instance(instance_name, command);
18945895Syz147064 	if (status == DLADM_STATUS_EXIST) {
18954126Szf162725 		/*
18964126Szf162725 		 * Delete the existing instance and create a new instance
18974126Szf162725 		 * with the supplied arguments.
18984126Szf162725 		 */
18994126Szf162725 		if ((status = delete_instance(instance_name)) ==
19005895Syz147064 		    DLADM_STATUS_OK) {
19014126Szf162725 			status = create_instance(instance_name, command);
19024126Szf162725 		}
19034126Szf162725 	}
19044126Szf162725 
19054126Szf162725 out:
19064126Szf162725 	if (command != NULL)
19074126Szf162725 		free(command);
19084126Szf162725 
19094126Szf162725 	return (status);
19104126Szf162725 }
19114126Szf162725 
19125895Syz147064 static dladm_status_t
19135895Syz147064 wpa_instance_delete(datalink_id_t linkid)
19144126Szf162725 {
19155895Syz147064 	char	instance_name[MAXLINKNAMELEN];
19164126Szf162725 
19175895Syz147064 	/*
19185895Syz147064 	 * Get the instance name of the network/wpad service (the same as
19195895Syz147064 	 * the link name).
19205895Syz147064 	 */
19215895Syz147064 	if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name,
19225895Syz147064 	    sizeof (instance_name)) != DLADM_STATUS_OK)
19235895Syz147064 		return (DLADM_STATUS_FAILED);
19244126Szf162725 
19255895Syz147064 	return (delete_instance(instance_name));
19264126Szf162725 }
1927