10ba2cbe9Sxc /*
20ba2cbe9Sxc  * CDDL HEADER START
30ba2cbe9Sxc  *
40ba2cbe9Sxc  * The contents of this file are subject to the terms of the
50ba2cbe9Sxc  * Common Development and Distribution License (the "License").
60ba2cbe9Sxc  * You may not use this file except in compliance with the License.
70ba2cbe9Sxc  *
80ba2cbe9Sxc  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90ba2cbe9Sxc  * or http://www.opensolaris.org/os/licensing.
100ba2cbe9Sxc  * See the License for the specific language governing permissions
110ba2cbe9Sxc  * and limitations under the License.
120ba2cbe9Sxc  *
130ba2cbe9Sxc  * When distributing Covered Code, include this CDDL HEADER in each
140ba2cbe9Sxc  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150ba2cbe9Sxc  * If applicable, add the following below this CDDL HEADER, with the
160ba2cbe9Sxc  * fields enclosed by brackets "[]" replaced with your own identifying
170ba2cbe9Sxc  * information: Portions Copyright [yyyy] [name of copyright owner]
180ba2cbe9Sxc  *
190ba2cbe9Sxc  * CDDL HEADER END
200ba2cbe9Sxc  */
210ba2cbe9Sxc /*
22e2cf88acSQuaker Fang  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230ba2cbe9Sxc  * Use is subject to license terms.
240ba2cbe9Sxc  */
250ba2cbe9Sxc 
2633343a97Smeem #include <libintl.h>
270ba2cbe9Sxc #include <stdio.h>
280ba2cbe9Sxc #include <stdlib.h>
290ba2cbe9Sxc #include <unistd.h>
300ba2cbe9Sxc #include <fcntl.h>
31d62bc4baSyz #include <stddef.h>
320ba2cbe9Sxc #include <string.h>
330ba2cbe9Sxc #include <stropts.h>
340ba2cbe9Sxc #include <libdevinfo.h>
350ba2cbe9Sxc #include <net/if.h>
360ba2cbe9Sxc #include <net/if_dl.h>
370ba2cbe9Sxc #include <net/if_types.h>
38d62bc4baSyz #include <libdlpi.h>
39d62bc4baSyz #include <libdllink.h>
40a399b765Szf #include <libscf.h>
41f595a68aSyz #include <libdlwlan.h>
42d62bc4baSyz #include <libdladm_impl.h>
43f595a68aSyz #include <libdlwlan_impl.h>
44a399b765Szf #include <net/wpa.h>
450ba2cbe9Sxc 
464ac67f02SAnurag S. Maskey static dladm_status_t	wpa_instance_create(dladm_handle_t, datalink_id_t,
474ac67f02SAnurag S. Maskey 			    void *);
484ac67f02SAnurag S. Maskey static dladm_status_t	wpa_instance_delete(dladm_handle_t, datalink_id_t);
49d62bc4baSyz 
50c0e21d6aSToomas Soome static dladm_status_t	do_get_bsstype(dladm_handle_t, datalink_id_t, void *,
514ac67f02SAnurag S. Maskey 			    int);
52c0e21d6aSToomas Soome static dladm_status_t	do_get_essid(dladm_handle_t, datalink_id_t, void *,
534ac67f02SAnurag S. Maskey 			    int);
54c0e21d6aSToomas Soome static dladm_status_t	do_get_bssid(dladm_handle_t, datalink_id_t, void *,
554ac67f02SAnurag S. Maskey 			    int);
56c0e21d6aSToomas Soome static dladm_status_t	do_get_signal(dladm_handle_t, datalink_id_t, void *,
574ac67f02SAnurag S. Maskey 			    int);
58c0e21d6aSToomas Soome static dladm_status_t	do_get_encryption(dladm_handle_t, datalink_id_t, void *,
594ac67f02SAnurag S. Maskey 			    int);
60c0e21d6aSToomas Soome static dladm_status_t	do_get_authmode(dladm_handle_t, datalink_id_t, void *,
614ac67f02SAnurag S. Maskey 			    int);
62c0e21d6aSToomas Soome static dladm_status_t	do_get_linkstatus(dladm_handle_t, datalink_id_t, void *,
634ac67f02SAnurag S. Maskey 			    int);
644ac67f02SAnurag S. Maskey static dladm_status_t	do_get_esslist(dladm_handle_t, datalink_id_t, void  *,
654ac67f02SAnurag S. Maskey 			    int);
66c0e21d6aSToomas Soome static dladm_status_t	do_get_rate(dladm_handle_t, datalink_id_t, void *, int);
674ac67f02SAnurag S. Maskey static dladm_status_t	do_get_mode(dladm_handle_t, datalink_id_t, void *, int);
684ac67f02SAnurag S. Maskey static dladm_status_t	do_get_capability(dladm_handle_t, datalink_id_t, void *,
694ac67f02SAnurag S. Maskey 			    int);
704ac67f02SAnurag S. Maskey static dladm_status_t	do_get_wpamode(dladm_handle_t, datalink_id_t, void *,
714ac67f02SAnurag S. Maskey 			    int);
724ac67f02SAnurag S. Maskey 
734ac67f02SAnurag S. Maskey static dladm_status_t	do_set_bsstype(dladm_handle_t, datalink_id_t,
744ac67f02SAnurag S. Maskey 			    dladm_wlan_bsstype_t *);
754ac67f02SAnurag S. Maskey static dladm_status_t	do_set_authmode(dladm_handle_t, datalink_id_t,
764ac67f02SAnurag S. Maskey 			    dladm_wlan_auth_t *);
774ac67f02SAnurag S. Maskey static dladm_status_t	do_set_encryption(dladm_handle_t, datalink_id_t,
784ac67f02SAnurag S. Maskey 			    dladm_wlan_secmode_t *);
794ac67f02SAnurag S. Maskey static dladm_status_t	do_set_essid(dladm_handle_t, datalink_id_t,
804ac67f02SAnurag S. Maskey 			    dladm_wlan_essid_t *);
814ac67f02SAnurag S. Maskey static dladm_status_t	do_set_createibss(dladm_handle_t, datalink_id_t,
824ac67f02SAnurag S. Maskey 			    boolean_t *);
834ac67f02SAnurag S. Maskey static dladm_status_t	do_set_key(dladm_handle_t, datalink_id_t,
844ac67f02SAnurag S. Maskey 			    dladm_wlan_key_t *, uint_t);
854ac67f02SAnurag S. Maskey static dladm_status_t	do_set_channel(dladm_handle_t, datalink_id_t,
864ac67f02SAnurag S. Maskey 			    dladm_wlan_channel_t *);
874ac67f02SAnurag S. Maskey 
884ac67f02SAnurag S. Maskey static dladm_status_t	do_scan(dladm_handle_t, datalink_id_t, void *, int);
894ac67f02SAnurag S. Maskey static dladm_status_t	do_connect(dladm_handle_t, datalink_id_t, void *, int,
90bcb5c89dSSowmini Varadhan 			    dladm_wlan_attr_t *, boolean_t, void *, uint_t,
91bcb5c89dSSowmini Varadhan 			    int);
924ac67f02SAnurag S. Maskey static dladm_status_t	do_disconnect(dladm_handle_t, datalink_id_t, void *,
934ac67f02SAnurag S. Maskey 			    int);
94d62bc4baSyz static boolean_t	find_val_by_name(const char *, val_desc_t *,
95d62bc4baSyz 			    uint_t, uint_t *);
96d62bc4baSyz static boolean_t	find_name_by_val(uint_t, val_desc_t *, uint_t, char **);
97d62bc4baSyz static void		generate_essid(dladm_wlan_essid_t *);
980ba2cbe9Sxc 
99f595a68aSyz static dladm_status_t	dladm_wlan_wlresult2status(wldp_t *);
1004ac67f02SAnurag S. Maskey static dladm_status_t	dladm_wlan_validate(dladm_handle_t, datalink_id_t);
1010ba2cbe9Sxc 
1020ba2cbe9Sxc static val_desc_t	linkstatus_vals[] = {
103e7801d59Ssowmini 	{ "disconnected", DLADM_WLAN_LINK_DISCONNECTED	},
104e7801d59Ssowmini 	{ "connected",    DLADM_WLAN_LINK_CONNECTED	}
1050ba2cbe9Sxc };
1060ba2cbe9Sxc 
107c0e21d6aSToomas Soome static val_desc_t	secmode_vals[] = {
108e7801d59Ssowmini 	{ "none",	DLADM_WLAN_SECMODE_NONE		},
109e7801d59Ssowmini 	{ "wep",	DLADM_WLAN_SECMODE_WEP		},
110e7801d59Ssowmini 	{ "wpa",	DLADM_WLAN_SECMODE_WPA		}
1110ba2cbe9Sxc };
1120ba2cbe9Sxc 
113c0e21d6aSToomas Soome static val_desc_t	strength_vals[] = {
114e7801d59Ssowmini 	{ "very weak",	DLADM_WLAN_STRENGTH_VERY_WEAK	},
115d62bc4baSyz 	{ "weak",	DLADM_WLAN_STRENGTH_WEAK	},
116d62bc4baSyz 	{ "good",	DLADM_WLAN_STRENGTH_GOOD	},
117e7801d59Ssowmini 	{ "very good",	DLADM_WLAN_STRENGTH_VERY_GOOD	},
118e7801d59Ssowmini 	{ "excellent",	DLADM_WLAN_STRENGTH_EXCELLENT	}
1190ba2cbe9Sxc };
1200ba2cbe9Sxc 
1210ba2cbe9Sxc static val_desc_t	mode_vals[] = {
122e7801d59Ssowmini 	{ "a",		DLADM_WLAN_MODE_80211A		},
123e7801d59Ssowmini 	{ "b",		DLADM_WLAN_MODE_80211B		},
124e7801d59Ssowmini 	{ "g",		DLADM_WLAN_MODE_80211G		},
125e2cf88acSQuaker Fang 	{ "n",		DLADM_WLAN_MODE_80211GN		},
126e2cf88acSQuaker Fang 	{ "n",		DLADM_WLAN_MODE_80211AN		}
1270ba2cbe9Sxc };
1280ba2cbe9Sxc 
1290ba2cbe9Sxc static val_desc_t	auth_vals[] = {
130d62bc4baSyz 	{ "open",	DLADM_WLAN_AUTH_OPEN		},
131e7801d59Ssowmini 	{ "shared",	DLADM_WLAN_AUTH_SHARED		}
1320ba2cbe9Sxc };
1330ba2cbe9Sxc 
1340ba2cbe9Sxc static val_desc_t	bsstype_vals[] = {
135e7801d59Ssowmini 	{ "bss",	DLADM_WLAN_BSSTYPE_BSS		},
136e7801d59Ssowmini 	{ "ibss",	DLADM_WLAN_BSSTYPE_IBSS		},
137e7801d59Ssowmini 	{ "any",	DLADM_WLAN_BSSTYPE_ANY		}
1380ba2cbe9Sxc };
1390ba2cbe9Sxc 
140bcb5c89dSSowmini Varadhan #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
1410ba2cbe9Sxc 
142f595a68aSyz static dladm_status_t
dladm_wlan_wlresult2status(wldp_t * gbuf)143f595a68aSyz dladm_wlan_wlresult2status(wldp_t *gbuf)
1440ba2cbe9Sxc {
1450ba2cbe9Sxc 	switch (gbuf->wldp_result) {
1460ba2cbe9Sxc 	case WL_SUCCESS:
147f595a68aSyz 		return (DLADM_STATUS_OK);
1480ba2cbe9Sxc 
1490ba2cbe9Sxc 	case WL_NOTSUPPORTED:
1500ba2cbe9Sxc 	case WL_LACK_FEATURE:
151f595a68aSyz 		return (DLADM_STATUS_NOTSUP);
1520ba2cbe9Sxc 
1530ba2cbe9Sxc 	case WL_READONLY:
154f595a68aSyz 		return (DLADM_STATUS_PROPRDONLY);
1550ba2cbe9Sxc 
1560ba2cbe9Sxc 	default:
1570ba2cbe9Sxc 		break;
1580ba2cbe9Sxc 	}
1590ba2cbe9Sxc 
160f595a68aSyz 	return (DLADM_STATUS_FAILED);
1610ba2cbe9Sxc }
1620ba2cbe9Sxc 
163f595a68aSyz static dladm_wlan_mode_t
do_convert_mode(wl_phy_conf_t * phyp)1640ba2cbe9Sxc do_convert_mode(wl_phy_conf_t *phyp)
1650ba2cbe9Sxc {
166e2cf88acSQuaker Fang 	wl_erp_t *wlep = &phyp->wl_phy_erp_conf;
167e2cf88acSQuaker Fang 	wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
168e2cf88acSQuaker Fang 
1690ba2cbe9Sxc 	switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) {
1700ba2cbe9Sxc 	case WL_ERP:
171e2cf88acSQuaker Fang 		return (wlep->wl_erp_ht_enabled ?
172e2cf88acSQuaker Fang 		    DLADM_WLAN_MODE_80211GN : DLADM_WLAN_MODE_80211G);
1730ba2cbe9Sxc 	case WL_OFDM:
174e2cf88acSQuaker Fang 		return (wlop->wl_ofdm_ht_enabled ?
175e2cf88acSQuaker Fang 		    DLADM_WLAN_MODE_80211AN : DLADM_WLAN_MODE_80211A);
1760ba2cbe9Sxc 	case WL_DSSS:
1770ba2cbe9Sxc 	case WL_FHSS:
178f595a68aSyz 		return (DLADM_WLAN_MODE_80211B);
1790ba2cbe9Sxc 	default:
1800ba2cbe9Sxc 		break;
1810ba2cbe9Sxc 	}
1820ba2cbe9Sxc 
183f595a68aSyz 	return (DLADM_WLAN_MODE_NONE);
1840ba2cbe9Sxc }
1850ba2cbe9Sxc 
186d62bc4baSyz boolean_t
i_dladm_wlan_convert_chan(wl_phy_conf_t * phyp,uint32_t * channelp)187d62bc4baSyz i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp)
1880ba2cbe9Sxc {
1890ba2cbe9Sxc 	wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf;
1900ba2cbe9Sxc 	wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
1910ba2cbe9Sxc 
1920ba2cbe9Sxc 	switch (wlfp->wl_fhss_subtype) {
1930ba2cbe9Sxc 	case WL_FHSS:
1940ba2cbe9Sxc 	case WL_DSSS:
1950ba2cbe9Sxc 	case WL_IRBASE:
1960ba2cbe9Sxc 	case WL_HRDS:
1970ba2cbe9Sxc 	case WL_ERP:
1980ba2cbe9Sxc 		*channelp = wlfp->wl_fhss_channel;
1990ba2cbe9Sxc 		break;
2000ba2cbe9Sxc 	case WL_OFDM:
201f595a68aSyz 		*channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency);
2020ba2cbe9Sxc 		break;
2030ba2cbe9Sxc 	default:
2040ba2cbe9Sxc 		return (B_FALSE);
2050ba2cbe9Sxc 	}
2060ba2cbe9Sxc 	return (B_TRUE);
2070ba2cbe9Sxc }
2080ba2cbe9Sxc 
2090ba2cbe9Sxc #define	IEEE80211_RATE	0x7f
2100ba2cbe9Sxc static void
fill_wlan_attr(wl_ess_conf_t * wlp,dladm_wlan_attr_t * attrp)211f595a68aSyz fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp)
2120ba2cbe9Sxc {
2130ba2cbe9Sxc 	int		i;
2140ba2cbe9Sxc 
2150ba2cbe9Sxc 	(void) memset(attrp, 0, sizeof (*attrp));
2160ba2cbe9Sxc 
217f595a68aSyz 	(void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN,
218f595a68aSyz 	    "%s", wlp->wl_ess_conf_essid.wl_essid_essid);
219f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
2200ba2cbe9Sxc 
2210ba2cbe9Sxc 	(void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid,
222f595a68aSyz 	    DLADM_WLAN_BSSID_LEN);
223f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
2240ba2cbe9Sxc 
2250ba2cbe9Sxc 	attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled ==
226f595a68aSyz 	    WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE);
227a399b765Szf 	if (wlp->wl_ess_conf_reserved[0] > 0)
228a399b765Szf 		attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
229f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2300ba2cbe9Sxc 
2310ba2cbe9Sxc 	attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ?
232f595a68aSyz 	    DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS);
233f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
2340ba2cbe9Sxc 
2350ba2cbe9Sxc 	attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ?
236f595a68aSyz 	    DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED);
237f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
2380ba2cbe9Sxc 
239f595a68aSyz 	attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
240f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
2410ba2cbe9Sxc 
2420ba2cbe9Sxc 	attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
243f595a68aSyz 	attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
2440ba2cbe9Sxc 
2450ba2cbe9Sxc 	for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
2460ba2cbe9Sxc 		wlp->wl_supported_rates[i] &= IEEE80211_RATE;
247*4202e8bfSToomas Soome 		if ((uint_t)wlp->wl_supported_rates[i] > attrp->wa_speed)
2480ba2cbe9Sxc 			attrp->wa_speed = wlp->wl_supported_rates[i];
2490ba2cbe9Sxc 	}
2500ba2cbe9Sxc 	if (attrp->wa_speed > 0)
251f595a68aSyz 		attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
2520ba2cbe9Sxc 
253d62bc4baSyz 	if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf,
2540ba2cbe9Sxc 	    &attrp->wa_channel))
255f595a68aSyz 		attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL;
2560ba2cbe9Sxc }
2570ba2cbe9Sxc 
258f595a68aSyz dladm_status_t
dladm_wlan_scan(dladm_handle_t handle,datalink_id_t linkid,void * arg,boolean_t (* func)(void *,dladm_wlan_attr_t *))2594ac67f02SAnurag S. Maskey dladm_wlan_scan(dladm_handle_t handle, datalink_id_t linkid, void *arg,
260f595a68aSyz     boolean_t (*func)(void *, dladm_wlan_attr_t *))
2610ba2cbe9Sxc {
262*4202e8bfSToomas Soome 	uint_t			i;
2630ba2cbe9Sxc 	uint32_t		count;
2640ba2cbe9Sxc 	wl_ess_conf_t		*wlp;
265bcb5c89dSSowmini Varadhan 	wl_ess_list_t		*wls = NULL;
266c0e21d6aSToomas Soome 	char			buf[WLDP_BUFSIZE];
267bcb5c89dSSowmini Varadhan 	wl_linkstatus_t		wl_status;
268f595a68aSyz 	dladm_wlan_attr_t	wlattr;
269f595a68aSyz 	dladm_status_t		status;
2700ba2cbe9Sxc 
2714ac67f02SAnurag S. Maskey 	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
272d62bc4baSyz 		goto done;
2730ba2cbe9Sxc 
2744ac67f02SAnurag S. Maskey 	status = do_get_linkstatus(handle, linkid, &wl_status,
2754ac67f02SAnurag S. Maskey 	    sizeof (wl_status));
276bcb5c89dSSowmini Varadhan 	if (status != DLADM_STATUS_OK)
2770ba2cbe9Sxc 		goto done;
2780ba2cbe9Sxc 
2794ac67f02SAnurag S. Maskey 	if ((status = do_scan(handle, linkid, buf, sizeof (buf))) !=
2804ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
2810ba2cbe9Sxc 		goto done;
2820ba2cbe9Sxc 
283a399b765Szf 	if (func == NULL) {
284a399b765Szf 		status = DLADM_STATUS_OK;
285a399b765Szf 		goto done;
286a399b765Szf 	}
287a399b765Szf 
288bcb5c89dSSowmini Varadhan 	wls = malloc(WLDP_BUFSIZE);
289bcb5c89dSSowmini Varadhan 	if (wls == NULL) {
290bcb5c89dSSowmini Varadhan 		status = DLADM_STATUS_NOMEM;
291bcb5c89dSSowmini Varadhan 		goto done;
292bcb5c89dSSowmini Varadhan 	}
293bcb5c89dSSowmini Varadhan 
2944ac67f02SAnurag S. Maskey 	if ((status = do_get_esslist(handle, linkid, wls, WLDP_BUFSIZE))
295bcb5c89dSSowmini Varadhan 	    != DLADM_STATUS_OK)
2960ba2cbe9Sxc 		goto done;
2970ba2cbe9Sxc 
298bcb5c89dSSowmini Varadhan 	wlp = wls->wl_ess_list_ess;
299bcb5c89dSSowmini Varadhan 	count = wls->wl_ess_list_num;
3000ba2cbe9Sxc 
3010ba2cbe9Sxc 	for (i = 0; i < count; i++, wlp++) {
3020ba2cbe9Sxc 		fill_wlan_attr(wlp, &wlattr);
3030ba2cbe9Sxc 		if (!func(arg, &wlattr))
3040ba2cbe9Sxc 			break;
3050ba2cbe9Sxc 	}
3060ba2cbe9Sxc 
307bcb5c89dSSowmini Varadhan 	if (wl_status != WL_CONNECTED) {
3084ac67f02SAnurag S. Maskey 		status = do_get_linkstatus(handle, linkid, &wl_status,
309bcb5c89dSSowmini Varadhan 		    sizeof (&wl_status));
310d62bc4baSyz 		if (status != DLADM_STATUS_OK)
3110ba2cbe9Sxc 			goto done;
312bcb5c89dSSowmini Varadhan 		if (wl_status == WL_CONNECTED)
3134ac67f02SAnurag S. Maskey 			(void) do_disconnect(handle, linkid, buf, sizeof (buf));
3140ba2cbe9Sxc 	}
3150ba2cbe9Sxc 
316f595a68aSyz 	status = DLADM_STATUS_OK;
3170ba2cbe9Sxc done:
318bcb5c89dSSowmini Varadhan 	free(wls);
3190ba2cbe9Sxc 	return (status);
3200ba2cbe9Sxc }
3210ba2cbe9Sxc 
3220ba2cbe9Sxc /*
3230ba2cbe9Sxc  * Structures used in building the list of eligible WLANs to connect to.
3240ba2cbe9Sxc  * Specifically, `connect_state' has the WLAN attributes that must be matched
3250ba2cbe9Sxc  * (in `cs_attr') and a growing list of WLANs that matched those attributes
3260ba2cbe9Sxc  * chained through `cs_list'.  Each element in the list is of type `attr_node'
3270ba2cbe9Sxc  * and has the matching WLAN's attributes and a pointer to the next element.
3280ba2cbe9Sxc  * For convenience, `cs_count' tracks the number of elements in the list.
3290ba2cbe9Sxc  */
3300ba2cbe9Sxc typedef struct attr_node {
331f595a68aSyz 	dladm_wlan_attr_t	an_attr;
3320ba2cbe9Sxc 	struct attr_node	*an_next;
3330ba2cbe9Sxc } attr_node_t;
3340ba2cbe9Sxc 
3350ba2cbe9Sxc typedef struct connect_state {
336f595a68aSyz 	dladm_wlan_attr_t	*cs_attr;
3370ba2cbe9Sxc 	uint_t			cs_count;
3380ba2cbe9Sxc 	attr_node_t		*cs_list;
3390ba2cbe9Sxc } connect_state_t;
3400ba2cbe9Sxc 
3410ba2cbe9Sxc /*
3420ba2cbe9Sxc  * Compare two sets of WLAN attributes.  For now, we only consider strength
3430ba2cbe9Sxc  * and speed (in that order), which matches the documented default policy for
344f595a68aSyz  * dladm_wlan_connect().
3450ba2cbe9Sxc  */
3460ba2cbe9Sxc static int
attr_compare(const void * p1,const void * p2)3470ba2cbe9Sxc attr_compare(const void *p1, const void *p2)
3480ba2cbe9Sxc {
349f595a68aSyz 	dladm_wlan_attr_t *attrp1, *attrp2;
3500ba2cbe9Sxc 
351f595a68aSyz 	attrp1 = (*(dladm_wlan_attr_t **)p1);
352f595a68aSyz 	attrp2 = (*(dladm_wlan_attr_t **)p2);
3530ba2cbe9Sxc 
3540ba2cbe9Sxc 	if (attrp1->wa_strength < attrp2->wa_strength)
3550ba2cbe9Sxc 		return (1);
3560ba2cbe9Sxc 
3570ba2cbe9Sxc 	if (attrp1->wa_strength > attrp2->wa_strength)
3580ba2cbe9Sxc 		return (-1);
3590ba2cbe9Sxc 
3600ba2cbe9Sxc 	return (attrp2->wa_speed - attrp1->wa_speed);
3610ba2cbe9Sxc }
3620ba2cbe9Sxc 
3630ba2cbe9Sxc /*
364f595a68aSyz  * Callback function used by dladm_wlan_connect() to filter out unwanted
365f595a68aSyz  * WLANs when scanning for available WLANs.  Always returns B_TRUE to
366f595a68aSyz  * continue the scan.
3670ba2cbe9Sxc  */
3680ba2cbe9Sxc static boolean_t
connect_cb(void * arg,dladm_wlan_attr_t * attrp)369f595a68aSyz connect_cb(void *arg, dladm_wlan_attr_t *attrp)
3700ba2cbe9Sxc {
3710ba2cbe9Sxc 	attr_node_t		*nodep;
372f595a68aSyz 	dladm_wlan_attr_t	*fattrp;
3730ba2cbe9Sxc 	connect_state_t		*statep = (connect_state_t *)arg;
3740ba2cbe9Sxc 
3750ba2cbe9Sxc 	fattrp = statep->cs_attr;
3760ba2cbe9Sxc 	if (fattrp == NULL)
3770ba2cbe9Sxc 		goto append;
3780ba2cbe9Sxc 
3790ba2cbe9Sxc 	if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
3800ba2cbe9Sxc 		return (B_TRUE);
3810ba2cbe9Sxc 
382f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 &&
3830ba2cbe9Sxc 	    strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes,
384f595a68aSyz 	    DLADM_WLAN_MAX_ESSID_LEN) != 0)
3850ba2cbe9Sxc 		return (B_TRUE);
3860ba2cbe9Sxc 
387f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
3880ba2cbe9Sxc 	    fattrp->wa_secmode != attrp->wa_secmode)
3890ba2cbe9Sxc 		return (B_TRUE);
3900ba2cbe9Sxc 
391f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 &&
3920ba2cbe9Sxc 	    fattrp->wa_mode != attrp->wa_mode)
3930ba2cbe9Sxc 		return (B_TRUE);
3940ba2cbe9Sxc 
395f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 &&
3960ba2cbe9Sxc 	    fattrp->wa_strength != attrp->wa_strength)
3970ba2cbe9Sxc 		return (B_TRUE);
3980ba2cbe9Sxc 
399f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 &&
4000ba2cbe9Sxc 	    fattrp->wa_speed != attrp->wa_speed)
4010ba2cbe9Sxc 		return (B_TRUE);
4020ba2cbe9Sxc 
403f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) {
4040ba2cbe9Sxc 		attrp->wa_auth = fattrp->wa_auth;
405f595a68aSyz 		attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
4060ba2cbe9Sxc 	}
4070ba2cbe9Sxc 
408f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
4090ba2cbe9Sxc 	    fattrp->wa_bsstype != attrp->wa_bsstype)
4100ba2cbe9Sxc 		return (B_TRUE);
4110ba2cbe9Sxc 
412f595a68aSyz 	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 &&
4130ba2cbe9Sxc 	    memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes,
414f595a68aSyz 	    DLADM_WLAN_BSSID_LEN) != 0)
4150ba2cbe9Sxc 		return (B_TRUE);
4160ba2cbe9Sxc append:
4170ba2cbe9Sxc 	nodep = malloc(sizeof (attr_node_t));
4180ba2cbe9Sxc 	if (nodep == NULL)
4190ba2cbe9Sxc 		return (B_TRUE);
4200ba2cbe9Sxc 
421f595a68aSyz 	(void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t));
4220ba2cbe9Sxc 	nodep->an_next = statep->cs_list;
4230ba2cbe9Sxc 	statep->cs_list = nodep;
4240ba2cbe9Sxc 	statep->cs_count++;
4250ba2cbe9Sxc 
4260ba2cbe9Sxc 	return (B_TRUE);
4270ba2cbe9Sxc }
4280ba2cbe9Sxc 
429a399b765Szf #define	IEEE80211_C_WPA		0x01800000
430a399b765Szf 
431f595a68aSyz static dladm_status_t
do_connect(dladm_handle_t handle,datalink_id_t linkid,void * buf,int bufsize,dladm_wlan_attr_t * attrp,boolean_t create_ibss,void * keys,uint_t key_count,int timeout)4324ac67f02SAnurag S. Maskey do_connect(dladm_handle_t handle, datalink_id_t linkid, void *buf, int bufsize,
433bcb5c89dSSowmini Varadhan     dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys,
434bcb5c89dSSowmini Varadhan     uint_t key_count, int timeout)
4350ba2cbe9Sxc {
436d62bc4baSyz 	dladm_wlan_secmode_t	secmode;
437d62bc4baSyz 	dladm_wlan_auth_t	authmode;
438d62bc4baSyz 	dladm_wlan_bsstype_t	bsstype;
439d62bc4baSyz 	dladm_wlan_essid_t	essid;
440d62bc4baSyz 	boolean_t		essid_valid = B_FALSE;
441d62bc4baSyz 	dladm_status_t		status;
442d62bc4baSyz 	dladm_wlan_channel_t	channel;
443d62bc4baSyz 	hrtime_t		start;
444d62bc4baSyz 	wl_capability_t		*caps;
445bcb5c89dSSowmini Varadhan 	wl_linkstatus_t		wl_status;
4460ba2cbe9Sxc 
447f595a68aSyz 	if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) {
4480ba2cbe9Sxc 		channel = attrp->wa_channel;
4494ac67f02SAnurag S. Maskey 		status = do_set_channel(handle, linkid, &channel);
450d62bc4baSyz 		if (status != DLADM_STATUS_OK)
45113994ee8Sxz 			goto fail;
4520ba2cbe9Sxc 	}
4530ba2cbe9Sxc 
454f595a68aSyz 	secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ?
455f595a68aSyz 	    attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE;
4560ba2cbe9Sxc 
4574ac67f02SAnurag S. Maskey 	if ((status = do_set_encryption(handle, linkid, &secmode)) !=
4584ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
45913994ee8Sxz 		goto fail;
4600ba2cbe9Sxc 
461f595a68aSyz 	authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ?
462f595a68aSyz 	    attrp->wa_auth : DLADM_WLAN_AUTH_OPEN;
4630ba2cbe9Sxc 
4644ac67f02SAnurag S. Maskey 	if ((status = do_set_authmode(handle, linkid, &authmode)) !=
4654ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
46613994ee8Sxz 		goto fail;
4670ba2cbe9Sxc 
468f595a68aSyz 	bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ?
469f595a68aSyz 	    attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS;
4700ba2cbe9Sxc 
4714ac67f02SAnurag S. Maskey 	if ((status = do_set_bsstype(handle, linkid, &bsstype)) !=
4724ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
47313994ee8Sxz 		goto fail;
4740ba2cbe9Sxc 
475f595a68aSyz 	if (secmode == DLADM_WLAN_SECMODE_WEP) {
476d62bc4baSyz 		if (keys == NULL || key_count == 0 ||
477d62bc4baSyz 		    key_count > MAX_NWEPKEYS) {
478d62bc4baSyz 			status = DLADM_STATUS_BADARG;
479d62bc4baSyz 			goto fail;
480d62bc4baSyz 		}
4814ac67f02SAnurag S. Maskey 		status = do_set_key(handle, linkid, keys, key_count);
482d62bc4baSyz 		if (status != DLADM_STATUS_OK)
483a399b765Szf 			goto fail;
484a399b765Szf 	} else if (secmode == DLADM_WLAN_SECMODE_WPA) {
485d62bc4baSyz 		if (keys == NULL || key_count == 0 ||
486d62bc4baSyz 		    key_count > MAX_NWEPKEYS) {
487d62bc4baSyz 			status = DLADM_STATUS_BADARG;
488d62bc4baSyz 			goto fail;
489d62bc4baSyz 		}
4904ac67f02SAnurag S. Maskey 		status = do_get_capability(handle, linkid, buf, bufsize);
491d62bc4baSyz 		if (status != DLADM_STATUS_OK)
49213994ee8Sxz 			goto fail;
493bcb5c89dSSowmini Varadhan 		caps = (wl_capability_t *)buf;
494a399b765Szf 		if ((caps->caps & IEEE80211_C_WPA) == 0)
495a399b765Szf 			return (DLADM_STATUS_NOTSUP);
49613994ee8Sxz 	}
4970ba2cbe9Sxc 
4980ba2cbe9Sxc 	if (create_ibss) {
4994ac67f02SAnurag S. Maskey 		status = do_set_channel(handle, linkid, &channel);
500d62bc4baSyz 		if (status != DLADM_STATUS_OK)
50113994ee8Sxz 			goto fail;
5020ba2cbe9Sxc 
5034ac67f02SAnurag S. Maskey 		status = do_set_createibss(handle, linkid, &create_ibss);
504d62bc4baSyz 		if (status != DLADM_STATUS_OK)
50513994ee8Sxz 			goto fail;
5060ba2cbe9Sxc 
507f595a68aSyz 		if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) {
5080ba2cbe9Sxc 			generate_essid(&essid);
5090ba2cbe9Sxc 			essid_valid = B_TRUE;
5100ba2cbe9Sxc 		}
5110ba2cbe9Sxc 	}
5120ba2cbe9Sxc 
513f595a68aSyz 	if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) {
5140ba2cbe9Sxc 		essid = attrp->wa_essid;
5150ba2cbe9Sxc 		essid_valid = B_TRUE;
5160ba2cbe9Sxc 	}
5170ba2cbe9Sxc 
518d62bc4baSyz 	if (!essid_valid) {
519d62bc4baSyz 		status = DLADM_STATUS_FAILED;
520d62bc4baSyz 		goto fail;
521d62bc4baSyz 	}
522d62bc4baSyz 
5234ac67f02SAnurag S. Maskey 	if ((status = do_set_essid(handle, linkid, &essid)) != DLADM_STATUS_OK)
52413994ee8Sxz 		goto fail;
5250ba2cbe9Sxc 
526a399b765Szf 	/*
527a399b765Szf 	 * Because wpa daemon needs getting essid from driver,
528a399b765Szf 	 * we need call do_set_essid() first, then call wpa_instance_create().
529a399b765Szf 	 */
530a399b765Szf 	if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL)
5314ac67f02SAnurag S. Maskey 		(void) wpa_instance_create(handle, linkid, keys);
532a399b765Szf 
5330ba2cbe9Sxc 	start = gethrtime();
5340ba2cbe9Sxc 	for (;;) {
5354ac67f02SAnurag S. Maskey 		status = do_get_linkstatus(handle, linkid, &wl_status,
536bcb5c89dSSowmini Varadhan 		    sizeof (wl_status));
537d62bc4baSyz 		if (status != DLADM_STATUS_OK)
53813994ee8Sxz 			goto fail;
5390ba2cbe9Sxc 
540bcb5c89dSSowmini Varadhan 		if (wl_status == WL_CONNECTED)
5410ba2cbe9Sxc 			break;
5420ba2cbe9Sxc 
543f595a68aSyz 		(void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE);
5440ba2cbe9Sxc 		if ((timeout >= 0) && (gethrtime() - start) /
545d62bc4baSyz 		    NANOSEC >= timeout) {
546d62bc4baSyz 			status = DLADM_STATUS_TIMEDOUT;
547d62bc4baSyz 			goto fail;
548d62bc4baSyz 		}
5490ba2cbe9Sxc 	}
550d62bc4baSyz 	status = DLADM_STATUS_OK;
55113994ee8Sxz fail:
552d62bc4baSyz 	return (status);
5530ba2cbe9Sxc }
5540ba2cbe9Sxc 
555f595a68aSyz dladm_status_t
dladm_wlan_connect(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_attr_t * attrp,int timeout,void * keys,uint_t key_count,uint_t flags)5564ac67f02SAnurag S. Maskey dladm_wlan_connect(dladm_handle_t handle, datalink_id_t linkid,
5574ac67f02SAnurag S. Maskey     dladm_wlan_attr_t *attrp, int timeout, void *keys, uint_t key_count,
5584ac67f02SAnurag S. Maskey     uint_t flags)
5590ba2cbe9Sxc {
560*4202e8bfSToomas Soome 	uint_t			i;
561c0e21d6aSToomas Soome 	char			buf[WLDP_BUFSIZE];
562c0e21d6aSToomas Soome 	connect_state_t		state = {0, 0, NULL};
5630ba2cbe9Sxc 	attr_node_t		*nodep = NULL;
5640ba2cbe9Sxc 	boolean_t		create_ibss, set_authmode;
565f595a68aSyz 	dladm_wlan_attr_t	**wl_list = NULL;
566d62bc4baSyz 	dladm_status_t		status;
567bcb5c89dSSowmini Varadhan 	wl_linkstatus_t		wl_status;
5680ba2cbe9Sxc 
5694ac67f02SAnurag S. Maskey 	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
570811fc8e1Syz 		return (status);
5710ba2cbe9Sxc 
5724ac67f02SAnurag S. Maskey 	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
5734ac67f02SAnurag S. Maskey 	    sizeof (wl_status))) != DLADM_STATUS_OK)
5740ba2cbe9Sxc 		goto done;
5750ba2cbe9Sxc 
576bcb5c89dSSowmini Varadhan 	if (wl_status == WL_CONNECTED) {
577f595a68aSyz 		status = DLADM_STATUS_ISCONN;
5780ba2cbe9Sxc 		goto done;
5790ba2cbe9Sxc 	}
5800ba2cbe9Sxc 
5810ba2cbe9Sxc 	set_authmode = ((attrp != NULL) &&
582f595a68aSyz 	    (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0);
583f595a68aSyz 	create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 &&
5840ba2cbe9Sxc 	    attrp != NULL &&
585f595a68aSyz 	    (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
586f595a68aSyz 	    attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS);
5870ba2cbe9Sxc 
588f595a68aSyz 	if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 ||
5890ba2cbe9Sxc 	    (create_ibss && attrp != NULL &&
590f595a68aSyz 	    (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) {
5914ac67f02SAnurag S. Maskey 		status = do_connect(handle, linkid, buf, sizeof (buf), attrp,
592bcb5c89dSSowmini Varadhan 		    create_ibss, keys, key_count, timeout);
5930ba2cbe9Sxc 		goto done;
5940ba2cbe9Sxc 	}
5950ba2cbe9Sxc 
5960ba2cbe9Sxc 	state.cs_attr = attrp;
5970ba2cbe9Sxc 	state.cs_list = NULL;
5980ba2cbe9Sxc 	state.cs_count = 0;
5990ba2cbe9Sxc 
6004ac67f02SAnurag S. Maskey 	status = dladm_wlan_scan(handle, linkid, &state, connect_cb);
601f595a68aSyz 	if (status != DLADM_STATUS_OK)
6020ba2cbe9Sxc 		goto done;
6030ba2cbe9Sxc 
6040ba2cbe9Sxc 	if (state.cs_count == 0) {
6050ba2cbe9Sxc 		if (!create_ibss) {
606f595a68aSyz 			status = DLADM_STATUS_NOTFOUND;
6070ba2cbe9Sxc 			goto done;
6080ba2cbe9Sxc 		}
6094ac67f02SAnurag S. Maskey 		status = do_connect(handle, linkid, buf, sizeof (buf),
610bcb5c89dSSowmini Varadhan 		    attrp, create_ibss, keys, key_count, timeout);
6110ba2cbe9Sxc 		goto done;
6120ba2cbe9Sxc 	}
6130ba2cbe9Sxc 
614f595a68aSyz 	wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *));
6150ba2cbe9Sxc 	if (wl_list == NULL) {
616f595a68aSyz 		status = DLADM_STATUS_NOMEM;
6170ba2cbe9Sxc 		goto done;
6180ba2cbe9Sxc 	}
6190ba2cbe9Sxc 
6200ba2cbe9Sxc 	nodep = state.cs_list;
6210ba2cbe9Sxc 	for (i = 0; i < state.cs_count; i++) {
6220ba2cbe9Sxc 		wl_list[i] = &nodep->an_attr;
6230ba2cbe9Sxc 		nodep = nodep->an_next;
6240ba2cbe9Sxc 	}
625f595a68aSyz 	qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
6260ba2cbe9Sxc 	    attr_compare);
6270ba2cbe9Sxc 
6280ba2cbe9Sxc 	for (i = 0; i < state.cs_count; i++) {
629f595a68aSyz 		dladm_wlan_attr_t	*ap = wl_list[i];
6300ba2cbe9Sxc 
6314ac67f02SAnurag S. Maskey 		status = do_connect(handle, linkid, buf, sizeof (buf),
632bcb5c89dSSowmini Varadhan 		    ap, create_ibss, keys, key_count, timeout);
633f595a68aSyz 		if (status == DLADM_STATUS_OK)
6340ba2cbe9Sxc 			break;
6350ba2cbe9Sxc 
6360ba2cbe9Sxc 		if (!set_authmode) {
637f595a68aSyz 			ap->wa_auth = DLADM_WLAN_AUTH_SHARED;
638f595a68aSyz 			ap->wa_valid |= DLADM_WLAN_ATTR_AUTH;
6394ac67f02SAnurag S. Maskey 			status = do_connect(handle, linkid, buf, sizeof (buf),
640bcb5c89dSSowmini Varadhan 			    ap, create_ibss, keys, key_count, timeout);
641f595a68aSyz 			if (status == DLADM_STATUS_OK)
6420ba2cbe9Sxc 				break;
6430ba2cbe9Sxc 		}
6440ba2cbe9Sxc 	}
6450ba2cbe9Sxc done:
646f595a68aSyz 	if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
6474ac67f02SAnurag S. Maskey 		(void) do_disconnect(handle, linkid, buf, sizeof (buf));
6480ba2cbe9Sxc 
6490ba2cbe9Sxc 	while (state.cs_list != NULL) {
6500ba2cbe9Sxc 		nodep = state.cs_list;
6510ba2cbe9Sxc 		state.cs_list = nodep->an_next;
6520ba2cbe9Sxc 		free(nodep);
6530ba2cbe9Sxc 	}
6540ba2cbe9Sxc 	free(wl_list);
6550ba2cbe9Sxc 	return (status);
6560ba2cbe9Sxc }
6570ba2cbe9Sxc 
658f595a68aSyz dladm_status_t
dladm_wlan_disconnect(dladm_handle_t handle,datalink_id_t linkid)6594ac67f02SAnurag S. Maskey dladm_wlan_disconnect(dladm_handle_t handle, datalink_id_t linkid)
6600ba2cbe9Sxc {
661bcb5c89dSSowmini Varadhan 	char		buf[WLDP_BUFSIZE];
662f595a68aSyz 	dladm_status_t	status;
663bcb5c89dSSowmini Varadhan 	wl_linkstatus_t	wl_status;
6640ba2cbe9Sxc 
6654ac67f02SAnurag S. Maskey 	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
666d62bc4baSyz 		return (status);
6670ba2cbe9Sxc 
6684ac67f02SAnurag S. Maskey 	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
6694ac67f02SAnurag S. Maskey 	    sizeof (wl_status))) != DLADM_STATUS_OK)
6700ba2cbe9Sxc 		goto done;
6710ba2cbe9Sxc 
672bcb5c89dSSowmini Varadhan 	if (wl_status != WL_CONNECTED) {
673f595a68aSyz 		status = DLADM_STATUS_NOTCONN;
6740ba2cbe9Sxc 		goto done;
6750ba2cbe9Sxc 	}
6760ba2cbe9Sxc 
6774ac67f02SAnurag S. Maskey 	if ((status = do_disconnect(handle, linkid, buf, sizeof (buf)))
678bcb5c89dSSowmini Varadhan 	    != DLADM_STATUS_OK)
6790ba2cbe9Sxc 		goto done;
6800ba2cbe9Sxc 
6814ac67f02SAnurag S. Maskey 	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
6824ac67f02SAnurag S. Maskey 	    sizeof (wl_status))) != DLADM_STATUS_OK)
6830ba2cbe9Sxc 		goto done;
6840ba2cbe9Sxc 
685bcb5c89dSSowmini Varadhan 	if (wl_status == WL_CONNECTED) {
686f595a68aSyz 		status = DLADM_STATUS_FAILED;
6870ba2cbe9Sxc 		goto done;
6880ba2cbe9Sxc 	}
6890ba2cbe9Sxc 
690f595a68aSyz 	status = DLADM_STATUS_OK;
6910ba2cbe9Sxc done:
6920ba2cbe9Sxc 	return (status);
6930ba2cbe9Sxc }
6940ba2cbe9Sxc 
695f595a68aSyz dladm_status_t
dladm_wlan_get_linkattr(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_linkattr_t * attrp)6964ac67f02SAnurag S. Maskey dladm_wlan_get_linkattr(dladm_handle_t handle, datalink_id_t linkid,
6974ac67f02SAnurag S. Maskey     dladm_wlan_linkattr_t *attrp)
6980ba2cbe9Sxc {
6990ba2cbe9Sxc 	wl_rssi_t		signal;
7000ba2cbe9Sxc 	wl_bss_type_t		bsstype;
7010ba2cbe9Sxc 	wl_authmode_t		authmode;
7020ba2cbe9Sxc 	wl_encryption_t		encryption;
703bcb5c89dSSowmini Varadhan 	wl_rates_t		*ratesp = NULL;
704f595a68aSyz 	dladm_wlan_attr_t	*wl_attrp;
705d62bc4baSyz 	dladm_status_t		status;
706bcb5c89dSSowmini Varadhan 	char			buf[WLDP_BUFSIZE];
707bcb5c89dSSowmini Varadhan 	wl_essid_t		wls;
708bcb5c89dSSowmini Varadhan 	wl_phy_conf_t		wl_phy_conf;
709bcb5c89dSSowmini Varadhan 	wl_linkstatus_t		wl_status;
7100ba2cbe9Sxc 
7110ba2cbe9Sxc 	if (attrp == NULL)
712f595a68aSyz 		return (DLADM_STATUS_BADARG);
7130ba2cbe9Sxc 
7144ac67f02SAnurag S. Maskey 	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
715d62bc4baSyz 		goto done;
7160ba2cbe9Sxc 
7170ba2cbe9Sxc 	(void) memset(attrp, 0, sizeof (*attrp));
7180ba2cbe9Sxc 	wl_attrp = &attrp->la_wlan_attr;
7190ba2cbe9Sxc 
7204ac67f02SAnurag S. Maskey 	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
7214ac67f02SAnurag S. Maskey 	    sizeof (wl_status))) != DLADM_STATUS_OK)
7220ba2cbe9Sxc 		goto done;
7230ba2cbe9Sxc 
724f595a68aSyz 	attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS;
725bcb5c89dSSowmini Varadhan 	if (wl_status != WL_CONNECTED)
726d62bc4baSyz 		attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED;
727d62bc4baSyz 	else
728d62bc4baSyz 		attrp->la_status = DLADM_WLAN_LINK_CONNECTED;
7290ba2cbe9Sxc 
7304ac67f02SAnurag S. Maskey 	if ((status = do_get_essid(handle, linkid, &wls, sizeof (wls)))
731bcb5c89dSSowmini Varadhan 	    != DLADM_STATUS_OK)
7320ba2cbe9Sxc 		goto done;
7330ba2cbe9Sxc 
734bcb5c89dSSowmini Varadhan 	(void) strlcpy(wl_attrp->wa_essid.we_bytes, wls.wl_essid_essid,
735f595a68aSyz 	    DLADM_WLAN_MAX_ESSID_LEN);
7360ba2cbe9Sxc 
737f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
7380ba2cbe9Sxc 
7394ac67f02SAnurag S. Maskey 	if ((status = do_get_bssid(handle, linkid, buf, sizeof (buf)))
740bcb5c89dSSowmini Varadhan 	    != DLADM_STATUS_OK)
7410ba2cbe9Sxc 		goto done;
7420ba2cbe9Sxc 
743bcb5c89dSSowmini Varadhan 	(void) memcpy(wl_attrp->wa_bssid.wb_bytes, buf, DLADM_WLAN_BSSID_LEN);
7440ba2cbe9Sxc 
745f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
7460ba2cbe9Sxc 
747d62bc4baSyz 	if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) {
748a399b765Szf 		attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
749a399b765Szf 		status = DLADM_STATUS_OK;
750a399b765Szf 		goto done;
751a399b765Szf 	}
752a399b765Szf 
7534ac67f02SAnurag S. Maskey 	if ((status = do_get_encryption(handle, linkid, &encryption,
754bcb5c89dSSowmini Varadhan 	    sizeof (encryption))) != DLADM_STATUS_OK)
7550ba2cbe9Sxc 		goto done;
7560ba2cbe9Sxc 
757f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
7580ba2cbe9Sxc 
7590ba2cbe9Sxc 	switch (encryption) {
7600ba2cbe9Sxc 	case WL_NOENCRYPTION:
761f595a68aSyz 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
7620ba2cbe9Sxc 		break;
7630ba2cbe9Sxc 	case WL_ENC_WEP:
764f595a68aSyz 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
7650ba2cbe9Sxc 		break;
766a399b765Szf 	case WL_ENC_WPA:
767a399b765Szf 		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
768a399b765Szf 		break;
7690ba2cbe9Sxc 	default:
770f595a68aSyz 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE;
7710ba2cbe9Sxc 		break;
7720ba2cbe9Sxc 	}
7730ba2cbe9Sxc 
7744ac67f02SAnurag S. Maskey 	if ((status = do_get_signal(handle, linkid, &signal, sizeof (signal)))
775bcb5c89dSSowmini Varadhan 	    != DLADM_STATUS_OK)
7760ba2cbe9Sxc 		goto done;
7770ba2cbe9Sxc 
778f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
779f595a68aSyz 	wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
7800ba2cbe9Sxc 
781bcb5c89dSSowmini Varadhan 	ratesp = malloc(WLDP_BUFSIZE);
782bcb5c89dSSowmini Varadhan 	if (ratesp == NULL) {
783bcb5c89dSSowmini Varadhan 		status = DLADM_STATUS_NOMEM;
784bcb5c89dSSowmini Varadhan 		goto done;
785bcb5c89dSSowmini Varadhan 	}
786bcb5c89dSSowmini Varadhan 
7874ac67f02SAnurag S. Maskey 	if ((status = do_get_rate(handle, linkid, ratesp, WLDP_BUFSIZE))
788bcb5c89dSSowmini Varadhan 	    != DLADM_STATUS_OK)
7890ba2cbe9Sxc 		goto done;
7900ba2cbe9Sxc 
7910ba2cbe9Sxc 	if (ratesp->wl_rates_num > 0) {
792*4202e8bfSToomas Soome 		uint_t	i;
793*4202e8bfSToomas Soome 		int r = 0;
7940ba2cbe9Sxc 
7950ba2cbe9Sxc 		for (i = 0; i < ratesp->wl_rates_num; i++) {
7960ba2cbe9Sxc 			if (ratesp->wl_rates_rates[i] > r)
7970ba2cbe9Sxc 				r = ratesp->wl_rates_rates[i];
7980ba2cbe9Sxc 		}
7990ba2cbe9Sxc 		wl_attrp->wa_speed = r;
800f595a68aSyz 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
8010ba2cbe9Sxc 	}
8020ba2cbe9Sxc 
8034ac67f02SAnurag S. Maskey 	if ((status = do_get_authmode(handle, linkid, &authmode,
804bcb5c89dSSowmini Varadhan 	    sizeof (authmode))) != DLADM_STATUS_OK)
8050ba2cbe9Sxc 		goto done;
8060ba2cbe9Sxc 
807f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
8080ba2cbe9Sxc 
8090ba2cbe9Sxc 	switch (authmode) {
8100ba2cbe9Sxc 	case WL_OPENSYSTEM:
811f595a68aSyz 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
8120ba2cbe9Sxc 		break;
8130ba2cbe9Sxc 	case WL_SHAREDKEY:
814f595a68aSyz 		wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
8150ba2cbe9Sxc 		break;
8160ba2cbe9Sxc 	default:
817f595a68aSyz 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
8180ba2cbe9Sxc 		break;
8190ba2cbe9Sxc 	}
8200ba2cbe9Sxc 
8214ac67f02SAnurag S. Maskey 	if ((status = do_get_bsstype(handle, linkid, &bsstype,
822bcb5c89dSSowmini Varadhan 	    sizeof (bsstype))) != DLADM_STATUS_OK)
8230ba2cbe9Sxc 		goto done;
8240ba2cbe9Sxc 
825f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
8260ba2cbe9Sxc 
8270ba2cbe9Sxc 	switch (bsstype) {
8280ba2cbe9Sxc 	case WL_BSS_BSS:
829f595a68aSyz 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
8300ba2cbe9Sxc 		break;
8310ba2cbe9Sxc 	case WL_BSS_IBSS:
832f595a68aSyz 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
8330ba2cbe9Sxc 		break;
8340ba2cbe9Sxc 	case WL_BSS_ANY:
835f595a68aSyz 		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
8360ba2cbe9Sxc 		break;
8370ba2cbe9Sxc 	default:
838f595a68aSyz 		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
8390ba2cbe9Sxc 		break;
8400ba2cbe9Sxc 	}
8410ba2cbe9Sxc 
8424ac67f02SAnurag S. Maskey 	if ((status = do_get_mode(handle, linkid, &wl_phy_conf,
843bcb5c89dSSowmini Varadhan 	    sizeof (wl_phy_conf))) != DLADM_STATUS_OK)
8440ba2cbe9Sxc 		goto done;
8450ba2cbe9Sxc 
846bcb5c89dSSowmini Varadhan 	wl_attrp->wa_mode = do_convert_mode(&wl_phy_conf);
847f595a68aSyz 	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
848f595a68aSyz 	if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
849f595a68aSyz 		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
8500ba2cbe9Sxc 
851f595a68aSyz 	attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
852f595a68aSyz 	status = DLADM_STATUS_OK;
8530ba2cbe9Sxc 
8540ba2cbe9Sxc done:
855bcb5c89dSSowmini Varadhan 	free(ratesp);
8560ba2cbe9Sxc 	return (status);
8570ba2cbe9Sxc }
8580ba2cbe9Sxc 
859eae72b5bSSebastien Roy /*
860eae72b5bSSebastien Roy  * Check to see if the link is wireless.
861eae72b5bSSebastien Roy  */
862f595a68aSyz static dladm_status_t
dladm_wlan_validate(dladm_handle_t handle,datalink_id_t linkid)8634ac67f02SAnurag S. Maskey dladm_wlan_validate(dladm_handle_t handle, datalink_id_t linkid)
8640ba2cbe9Sxc {
865eae72b5bSSebastien Roy 	uint32_t	media;
866f595a68aSyz 	dladm_status_t	status;
8670ba2cbe9Sxc 
8684ac67f02SAnurag S. Maskey 	status = dladm_datalink_id2info(handle, linkid, NULL, NULL, &media,
8694ac67f02SAnurag S. Maskey 	    NULL, 0);
870eae72b5bSSebastien Roy 	if (status == DLADM_STATUS_OK) {
871eae72b5bSSebastien Roy 		if (media != DL_WIFI)
872eae72b5bSSebastien Roy 			status = DLADM_STATUS_LINKINVAL;
8730ba2cbe9Sxc 	}
8740ba2cbe9Sxc 	return (status);
8750ba2cbe9Sxc }
8760ba2cbe9Sxc 
8770ba2cbe9Sxc static boolean_t
find_val_by_name(const char * str,val_desc_t * vdp,uint_t cnt,uint_t * valp)8780ba2cbe9Sxc find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
8790ba2cbe9Sxc {
880*4202e8bfSToomas Soome 	uint_t	i;
8810ba2cbe9Sxc 
8820ba2cbe9Sxc 	for (i = 0; i < cnt; i++) {
8830ba2cbe9Sxc 		if (strcasecmp(str, vdp[i].vd_name) == 0) {
8840ba2cbe9Sxc 			*valp = vdp[i].vd_val;
8850ba2cbe9Sxc 			return (B_TRUE);
8860ba2cbe9Sxc 		}
8870ba2cbe9Sxc 	}
8880ba2cbe9Sxc 	return (B_FALSE);
8890ba2cbe9Sxc }
8900ba2cbe9Sxc 
8910ba2cbe9Sxc static boolean_t
find_name_by_val(uint_t val,val_desc_t * vdp,uint_t cnt,char ** strp)8920ba2cbe9Sxc find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
8930ba2cbe9Sxc {
894*4202e8bfSToomas Soome 	uint_t	i;
8950ba2cbe9Sxc 
8960ba2cbe9Sxc 	for (i = 0; i < cnt; i++) {
8970ba2cbe9Sxc 		if (val == vdp[i].vd_val) {
8980ba2cbe9Sxc 			*strp = vdp[i].vd_name;
8990ba2cbe9Sxc 			return (B_TRUE);
9000ba2cbe9Sxc 		}
9010ba2cbe9Sxc 	}
9020ba2cbe9Sxc 	return (B_FALSE);
9030ba2cbe9Sxc }
9040ba2cbe9Sxc 
9050ba2cbe9Sxc const char *
dladm_wlan_essid2str(dladm_wlan_essid_t * essid,char * buf)906f595a68aSyz dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
9070ba2cbe9Sxc {
908f595a68aSyz 	(void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
9090ba2cbe9Sxc 	return (buf);
9100ba2cbe9Sxc }
9110ba2cbe9Sxc 
9120ba2cbe9Sxc const char *
dladm_wlan_bssid2str(dladm_wlan_bssid_t * bssid,char * buf)913f595a68aSyz dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
9140ba2cbe9Sxc {
915f595a68aSyz 	return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
916f595a68aSyz 	    IFT_OTHER));
9170ba2cbe9Sxc }
9180ba2cbe9Sxc 
9190ba2cbe9Sxc static const char *
dladm_wlan_val2str(uint_t val,val_desc_t * vdp,uint_t cnt,char * buf)920f595a68aSyz dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
9210ba2cbe9Sxc {
9220ba2cbe9Sxc 	char	*s;
9230ba2cbe9Sxc 
9240ba2cbe9Sxc 	if (!find_name_by_val(val, vdp, cnt, &s))
9250ba2cbe9Sxc 		s = "";
9260ba2cbe9Sxc 
927f595a68aSyz 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
9280ba2cbe9Sxc 	return (buf);
9290ba2cbe9Sxc }
9300ba2cbe9Sxc 
9310ba2cbe9Sxc const char *
dladm_wlan_secmode2str(dladm_wlan_secmode_t * secmode,char * buf)932f595a68aSyz dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
9330ba2cbe9Sxc {
934f595a68aSyz 	return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
9350ba2cbe9Sxc 	    VALCNT(secmode_vals), buf));
9360ba2cbe9Sxc }
9370ba2cbe9Sxc 
9380ba2cbe9Sxc const char *
dladm_wlan_strength2str(dladm_wlan_strength_t * strength,char * buf)939f595a68aSyz dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
9400ba2cbe9Sxc {
941f595a68aSyz 	return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
9420ba2cbe9Sxc 	    VALCNT(strength_vals), buf));
9430ba2cbe9Sxc }
9440ba2cbe9Sxc 
9450ba2cbe9Sxc const char *
dladm_wlan_mode2str(dladm_wlan_mode_t * mode,char * buf)946f595a68aSyz dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
9470ba2cbe9Sxc {
948f595a68aSyz 	return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
9490ba2cbe9Sxc 	    VALCNT(mode_vals), buf));
9500ba2cbe9Sxc }
9510ba2cbe9Sxc 
9520ba2cbe9Sxc const char *
dladm_wlan_speed2str(dladm_wlan_speed_t * speed,char * buf)953f595a68aSyz dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
9540ba2cbe9Sxc {
955f595a68aSyz 	(void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
9560ba2cbe9Sxc 	    (float)(*speed) / 2);
9570ba2cbe9Sxc 	return (buf);
9580ba2cbe9Sxc }
9590ba2cbe9Sxc 
9600ba2cbe9Sxc const char *
dladm_wlan_auth2str(dladm_wlan_auth_t * auth,char * buf)961f595a68aSyz dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
9620ba2cbe9Sxc {
963f595a68aSyz 	return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
9640ba2cbe9Sxc 	    VALCNT(auth_vals), buf));
9650ba2cbe9Sxc }
9660ba2cbe9Sxc 
9670ba2cbe9Sxc const char *
dladm_wlan_bsstype2str(dladm_wlan_bsstype_t * bsstype,char * buf)968f595a68aSyz dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
9690ba2cbe9Sxc {
970f595a68aSyz 	return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
9710ba2cbe9Sxc 	    VALCNT(bsstype_vals), buf));
9720ba2cbe9Sxc }
9730ba2cbe9Sxc 
9740ba2cbe9Sxc const char *
dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t * linkstatus,char * buf)975f595a68aSyz dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
9760ba2cbe9Sxc {
977f595a68aSyz 	return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
9780ba2cbe9Sxc 	    VALCNT(linkstatus_vals), buf));
9790ba2cbe9Sxc }
9800ba2cbe9Sxc 
981f595a68aSyz dladm_status_t
dladm_wlan_str2essid(const char * str,dladm_wlan_essid_t * essid)982f595a68aSyz dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
9830ba2cbe9Sxc {
9840d2f4bc9Sff 	if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1)
985f595a68aSyz 		return (DLADM_STATUS_BADARG);
9860ba2cbe9Sxc 
987f595a68aSyz 	(void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
988f595a68aSyz 	return (DLADM_STATUS_OK);
9890ba2cbe9Sxc }
9900ba2cbe9Sxc 
991f595a68aSyz dladm_status_t
dladm_wlan_str2bssid(const char * str,dladm_wlan_bssid_t * bssid)992f595a68aSyz dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
9930ba2cbe9Sxc {
9940ba2cbe9Sxc 	int	len;
9950ba2cbe9Sxc 	uchar_t	*buf;
9960ba2cbe9Sxc 
9970ba2cbe9Sxc 	buf = _link_aton(str, &len);
9980ba2cbe9Sxc 	if (buf == NULL)
999f595a68aSyz 		return (DLADM_STATUS_BADARG);
10000ba2cbe9Sxc 
1001f595a68aSyz 	if (len != DLADM_WLAN_BSSID_LEN) {
10020ba2cbe9Sxc 		free(buf);
1003f595a68aSyz 		return (DLADM_STATUS_BADARG);
10040ba2cbe9Sxc 	}
10050ba2cbe9Sxc 
10060ba2cbe9Sxc 	(void) memcpy(bssid->wb_bytes, buf, len);
10070ba2cbe9Sxc 	free(buf);
1008f595a68aSyz 	return (DLADM_STATUS_OK);
10090ba2cbe9Sxc }
10100ba2cbe9Sxc 
1011f595a68aSyz dladm_status_t
dladm_wlan_str2secmode(const char * str,dladm_wlan_secmode_t * secmode)1012f595a68aSyz dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
10130ba2cbe9Sxc {
10140ba2cbe9Sxc 	uint_t	val;
10150ba2cbe9Sxc 
10160ba2cbe9Sxc 	if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
1017f595a68aSyz 		return (DLADM_STATUS_BADARG);
10180ba2cbe9Sxc 
1019f595a68aSyz 	*secmode = (dladm_wlan_secmode_t)val;
1020f595a68aSyz 	return (DLADM_STATUS_OK);
10210ba2cbe9Sxc }
10220ba2cbe9Sxc 
1023f595a68aSyz dladm_status_t
dladm_wlan_str2strength(const char * str,dladm_wlan_strength_t * strength)1024f595a68aSyz dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
10250ba2cbe9Sxc {
10260ba2cbe9Sxc 	uint_t	val;
10270ba2cbe9Sxc 
10280ba2cbe9Sxc 	if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
1029f595a68aSyz 		return (DLADM_STATUS_BADARG);
10300ba2cbe9Sxc 
1031f595a68aSyz 	*strength = (dladm_wlan_strength_t)val;
1032f595a68aSyz 	return (DLADM_STATUS_OK);
10330ba2cbe9Sxc }
10340ba2cbe9Sxc 
1035f595a68aSyz dladm_status_t
dladm_wlan_str2mode(const char * str,dladm_wlan_mode_t * mode)1036f595a68aSyz dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
10370ba2cbe9Sxc {
10380ba2cbe9Sxc 	uint_t	val;
10390ba2cbe9Sxc 
10400ba2cbe9Sxc 	if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
1041f595a68aSyz 		return (DLADM_STATUS_BADARG);
10420ba2cbe9Sxc 
1043f595a68aSyz 	*mode = (dladm_wlan_mode_t)val;
1044f595a68aSyz 	return (DLADM_STATUS_OK);
10450ba2cbe9Sxc }
10460ba2cbe9Sxc 
1047f595a68aSyz dladm_status_t
dladm_wlan_str2speed(const char * str,dladm_wlan_speed_t * speed)1048f595a68aSyz dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
10490ba2cbe9Sxc {
1050f595a68aSyz 	*speed = (dladm_wlan_speed_t)(atof(str) * 2);
1051f595a68aSyz 	return (DLADM_STATUS_OK);
10520ba2cbe9Sxc }
10530ba2cbe9Sxc 
1054f595a68aSyz dladm_status_t
dladm_wlan_str2auth(const char * str,dladm_wlan_auth_t * auth)1055f595a68aSyz dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
10560ba2cbe9Sxc {
10570ba2cbe9Sxc 	uint_t	val;
10580ba2cbe9Sxc 
10590ba2cbe9Sxc 	if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
1060f595a68aSyz 		return (DLADM_STATUS_BADARG);
10610ba2cbe9Sxc 
1062f595a68aSyz 	*auth = (dladm_wlan_auth_t)val;
1063f595a68aSyz 	return (DLADM_STATUS_OK);
10640ba2cbe9Sxc }
10650ba2cbe9Sxc 
1066f595a68aSyz dladm_status_t
dladm_wlan_str2bsstype(const char * str,dladm_wlan_bsstype_t * bsstype)1067f595a68aSyz dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
10680ba2cbe9Sxc {
10690ba2cbe9Sxc 	uint_t	val;
10700ba2cbe9Sxc 
10710ba2cbe9Sxc 	if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
1072f595a68aSyz 		return (DLADM_STATUS_BADARG);
10730ba2cbe9Sxc 
1074f595a68aSyz 	*bsstype = (dladm_wlan_bsstype_t)val;
1075f595a68aSyz 	return (DLADM_STATUS_OK);
10760ba2cbe9Sxc }
10770ba2cbe9Sxc 
1078f595a68aSyz dladm_status_t
dladm_wlan_str2linkstatus(const char * str,dladm_wlan_linkstatus_t * linkstatus)1079f595a68aSyz dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
10800ba2cbe9Sxc {
10810ba2cbe9Sxc 	uint_t	val;
10820ba2cbe9Sxc 
1083d62bc4baSyz 	if (!find_val_by_name(str, linkstatus_vals,
1084d62bc4baSyz 	    VALCNT(linkstatus_vals), &val)) {
1085f595a68aSyz 		return (DLADM_STATUS_BADARG);
1086d62bc4baSyz 	}
10870ba2cbe9Sxc 
1088f595a68aSyz 	*linkstatus = (dladm_wlan_linkstatus_t)val;
1089f595a68aSyz 	return (DLADM_STATUS_OK);
10900ba2cbe9Sxc }
10910ba2cbe9Sxc 
1092d62bc4baSyz dladm_status_t
i_dladm_wlan_legacy_ioctl(dladm_handle_t handle,datalink_id_t linkid,wldp_t * gbuf,uint_t id,size_t len,uint_t cmd,size_t cmdlen)10934ac67f02SAnurag S. Maskey i_dladm_wlan_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
10944ac67f02SAnurag S. Maskey     wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen)
10950ba2cbe9Sxc {
1096d62bc4baSyz 	char			linkname[MAXPATHLEN];
1097d62bc4baSyz 	int			fd, rc;
10980ba2cbe9Sxc 	struct	strioctl	stri;
1099d62bc4baSyz 	uint32_t		flags;
1100d62bc4baSyz 	dladm_status_t		status;
1101d62bc4baSyz 	uint32_t		media;
1102d62bc4baSyz 	char			link[MAXLINKNAMELEN];
1103d62bc4baSyz 
11044ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
11054ac67f02SAnurag S. Maskey 	    &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1106d62bc4baSyz 		return (status);
1107d62bc4baSyz 	}
1108d62bc4baSyz 
1109d62bc4baSyz 	if (media != DL_WIFI)
1110d62bc4baSyz 		return (DLADM_STATUS_BADARG);
1111d62bc4baSyz 
1112d62bc4baSyz 	if (!(flags & DLADM_OPT_ACTIVE))
1113d62bc4baSyz 		return (DLADM_STATUS_TEMPONLY);
1114d62bc4baSyz 
1115d62bc4baSyz 	/*
1116d62bc4baSyz 	 * dlpi_open() is not used here because libdlpi depends on libdladm,
1117d62bc4baSyz 	 * and we do not want to introduce recursive dependencies.
1118d62bc4baSyz 	 */
1119d62bc4baSyz 	(void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
1120d62bc4baSyz 	if ((fd = open(linkname, O_RDWR)) < 0)
1121eae72b5bSSebastien Roy 		return (dladm_errno2status(errno));
11220ba2cbe9Sxc 
11230ba2cbe9Sxc 	gbuf->wldp_type = NET_802_11;
11240ba2cbe9Sxc 	gbuf->wldp_id	= id;
11250ba2cbe9Sxc 	gbuf->wldp_length = len;
11260ba2cbe9Sxc 
11270ba2cbe9Sxc 	stri.ic_timout	= 0;
11280ba2cbe9Sxc 	stri.ic_dp	= (char *)gbuf;
11290ba2cbe9Sxc 	stri.ic_cmd	= cmd;
11300ba2cbe9Sxc 	stri.ic_len	= cmdlen;
11310ba2cbe9Sxc 
11320ba2cbe9Sxc 	if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
1133d62bc4baSyz 		if (rc > 0) {
1134d62bc4baSyz 			/*
1135d62bc4baSyz 			 * Non-negative return value indicates the specific
1136d62bc4baSyz 			 * operation failed and the reason for the failure
1137d62bc4baSyz 			 * was stored in gbuf->wldp_result.
1138d62bc4baSyz 			 */
1139d62bc4baSyz 			status = dladm_wlan_wlresult2status(gbuf);
1140d62bc4baSyz 		} else {
1141d62bc4baSyz 			/*
1142d62bc4baSyz 			 * Negative return value indicates the ioctl failed.
1143d62bc4baSyz 			 */
1144d62bc4baSyz 			status = dladm_errno2status(errno);
1145d62bc4baSyz 		}
11460ba2cbe9Sxc 	}
1147d62bc4baSyz 	(void) close(fd);
1148d62bc4baSyz 	return (status);
11490ba2cbe9Sxc }
11500ba2cbe9Sxc 
1151bcb5c89dSSowmini Varadhan static dladm_status_t
do_cmd_ioctl(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen,uint_t cmd)11524ac67f02SAnurag S. Maskey do_cmd_ioctl(dladm_handle_t handle, datalink_id_t linkid, void *buf,
11534ac67f02SAnurag S. Maskey     int buflen, uint_t cmd)
11540ba2cbe9Sxc {
1155d62bc4baSyz 	wldp_t *gbuf;
1156d62bc4baSyz 	dladm_status_t status = DLADM_STATUS_OK;
1157d62bc4baSyz 
1158d62bc4baSyz 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1159d62bc4baSyz 		return (DLADM_STATUS_NOMEM);
1160d62bc4baSyz 
11610ba2cbe9Sxc 	(void) memset(gbuf, 0, MAX_BUF_LEN);
11624ac67f02SAnurag S. Maskey 	status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, cmd,
11634ac67f02SAnurag S. Maskey 	    WLDP_BUFSIZE, WLAN_COMMAND, sizeof (wldp_t));
1164bcb5c89dSSowmini Varadhan 	(void) memcpy(buf, gbuf->wldp_buf, buflen);
1165d62bc4baSyz 	free(gbuf);
1166d62bc4baSyz 	return (status);
11670ba2cbe9Sxc }
11680ba2cbe9Sxc 
1169d62bc4baSyz static dladm_status_t
do_scan(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)11704ac67f02SAnurag S. Maskey do_scan(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
11710ba2cbe9Sxc {
11724ac67f02SAnurag S. Maskey 	return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_SCAN));
11730ba2cbe9Sxc }
11740ba2cbe9Sxc 
1175d62bc4baSyz static dladm_status_t
do_disconnect(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)11764ac67f02SAnurag S. Maskey do_disconnect(dladm_handle_t handle, datalink_id_t linkid, void *buf,
11774ac67f02SAnurag S. Maskey     int buflen)
11780ba2cbe9Sxc {
11794ac67f02SAnurag S. Maskey 	if (do_get_wpamode(handle, linkid, buf, buflen) == 0 &&
1180bcb5c89dSSowmini Varadhan 	    ((wl_wpa_t *)(buf))->wpa_flag > 0)
11814ac67f02SAnurag S. Maskey 		(void) wpa_instance_delete(handle, linkid);
1182a399b765Szf 
11834ac67f02SAnurag S. Maskey 	return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_DISASSOCIATE));
11840ba2cbe9Sxc }
11850ba2cbe9Sxc 
1186d62bc4baSyz static dladm_status_t
do_get_esslist(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)11874ac67f02SAnurag S. Maskey do_get_esslist(dladm_handle_t handle, datalink_id_t linkid, void *buf,
11884ac67f02SAnurag S. Maskey     int buflen)
11890ba2cbe9Sxc {
11904ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESS_LIST,
11914ac67f02SAnurag S. Maskey 	    buflen, B_FALSE));
11920ba2cbe9Sxc }
11930ba2cbe9Sxc 
1194d62bc4baSyz static dladm_status_t
do_get_bssid(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)11954ac67f02SAnurag S. Maskey do_get_bssid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
11960ba2cbe9Sxc {
11974ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSID,
11984ac67f02SAnurag S. Maskey 	    buflen, B_FALSE));
11990ba2cbe9Sxc }
12000ba2cbe9Sxc 
1201d62bc4baSyz static dladm_status_t
do_get_essid(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12024ac67f02SAnurag S. Maskey do_get_essid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
12030ba2cbe9Sxc {
12044ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESSID,
12054ac67f02SAnurag S. Maskey 	    buflen, B_FALSE));
12060ba2cbe9Sxc }
12070ba2cbe9Sxc 
1208d62bc4baSyz static dladm_status_t
do_get_bsstype(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12094ac67f02SAnurag S. Maskey do_get_bsstype(dladm_handle_t handle, datalink_id_t linkid, void *buf,
12104ac67f02SAnurag S. Maskey     int buflen)
12110ba2cbe9Sxc {
12124ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSTYPE,
12134ac67f02SAnurag S. Maskey 	    buflen, B_FALSE));
12140ba2cbe9Sxc }
12150ba2cbe9Sxc 
1216f595a68aSyz static dladm_status_t
do_get_linkstatus(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12174ac67f02SAnurag S. Maskey do_get_linkstatus(dladm_handle_t handle, datalink_id_t linkid, void *buf,
12184ac67f02SAnurag S. Maskey     int buflen)
12190ba2cbe9Sxc {
12204ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_LINKSTATUS,
12214ac67f02SAnurag S. Maskey 	    buflen, B_FALSE));
12220ba2cbe9Sxc }
12230ba2cbe9Sxc 
1224f595a68aSyz static dladm_status_t
do_get_rate(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12254ac67f02SAnurag S. Maskey do_get_rate(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
12260ba2cbe9Sxc {
12274ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf,
12284ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_DESIRED_RATES, buflen, B_FALSE));
12290ba2cbe9Sxc }
12300ba2cbe9Sxc 
1231f595a68aSyz static dladm_status_t
do_get_authmode(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12324ac67f02SAnurag S. Maskey do_get_authmode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
12334ac67f02SAnurag S. Maskey     int buflen)
12340ba2cbe9Sxc {
12354ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf,
12364ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_AUTH_MODE, buflen, B_FALSE));
12370ba2cbe9Sxc }
12380ba2cbe9Sxc 
1239f595a68aSyz static dladm_status_t
do_get_encryption(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12404ac67f02SAnurag S. Maskey do_get_encryption(dladm_handle_t handle, datalink_id_t linkid, void *buf,
12414ac67f02SAnurag S. Maskey     int buflen)
12420ba2cbe9Sxc {
12434ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf,
12444ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_ENCRYPTION, buflen, B_FALSE));
12450ba2cbe9Sxc }
12460ba2cbe9Sxc 
1247f595a68aSyz static dladm_status_t
do_get_signal(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12484ac67f02SAnurag S. Maskey do_get_signal(dladm_handle_t handle, datalink_id_t linkid, void *buf,
12494ac67f02SAnurag S. Maskey     int buflen)
12500ba2cbe9Sxc {
12514ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RSSI,
12524ac67f02SAnurag S. Maskey 	    buflen, B_FALSE));
12530ba2cbe9Sxc }
12540ba2cbe9Sxc 
1255f595a68aSyz static dladm_status_t
do_get_mode(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)12564ac67f02SAnurag S. Maskey do_get_mode(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
12570ba2cbe9Sxc {
12584ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
1259bcb5c89dSSowmini Varadhan 	    buflen, B_FALSE));
12600ba2cbe9Sxc }
12610ba2cbe9Sxc 
1262d62bc4baSyz static dladm_status_t
do_set_bsstype(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_bsstype_t * bsstype)12634ac67f02SAnurag S. Maskey do_set_bsstype(dladm_handle_t handle, datalink_id_t linkid,
12644ac67f02SAnurag S. Maskey     dladm_wlan_bsstype_t *bsstype)
12650ba2cbe9Sxc {
12660ba2cbe9Sxc 	wl_bss_type_t	ibsstype;
12670ba2cbe9Sxc 
12680ba2cbe9Sxc 	switch (*bsstype) {
1269f595a68aSyz 	case DLADM_WLAN_BSSTYPE_BSS:
12700ba2cbe9Sxc 		ibsstype = WL_BSS_BSS;
12710ba2cbe9Sxc 		break;
1272f595a68aSyz 	case DLADM_WLAN_BSSTYPE_IBSS:
12730ba2cbe9Sxc 		ibsstype = WL_BSS_IBSS;
12740ba2cbe9Sxc 		break;
12750ba2cbe9Sxc 	default:
12760ba2cbe9Sxc 		ibsstype = WL_BSS_ANY;
12770ba2cbe9Sxc 		break;
12780ba2cbe9Sxc 	}
12794ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &ibsstype,
12804ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_BSSTYPE, sizeof (ibsstype), B_TRUE));
12810ba2cbe9Sxc }
12820ba2cbe9Sxc 
1283d62bc4baSyz static dladm_status_t
do_set_authmode(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_auth_t * auth)12844ac67f02SAnurag S. Maskey do_set_authmode(dladm_handle_t handle, datalink_id_t linkid,
12854ac67f02SAnurag S. Maskey     dladm_wlan_auth_t *auth)
12860ba2cbe9Sxc {
12870ba2cbe9Sxc 	wl_authmode_t	auth_mode;
12880ba2cbe9Sxc 
12890ba2cbe9Sxc 	switch (*auth) {
1290f595a68aSyz 	case DLADM_WLAN_AUTH_OPEN:
12910ba2cbe9Sxc 		auth_mode = WL_OPENSYSTEM;
12920ba2cbe9Sxc 		break;
1293f595a68aSyz 	case DLADM_WLAN_AUTH_SHARED:
12940ba2cbe9Sxc 		auth_mode = WL_SHAREDKEY;
12950ba2cbe9Sxc 		break;
12960ba2cbe9Sxc 	default:
1297d62bc4baSyz 		return (DLADM_STATUS_NOTSUP);
12980ba2cbe9Sxc 	}
12994ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &auth_mode,
13004ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_AUTH_MODE, sizeof (auth_mode), B_TRUE));
13010ba2cbe9Sxc }
13020ba2cbe9Sxc 
1303d62bc4baSyz static dladm_status_t
do_set_encryption(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_secmode_t * secmode)13044ac67f02SAnurag S. Maskey do_set_encryption(dladm_handle_t handle, datalink_id_t linkid,
13054ac67f02SAnurag S. Maskey     dladm_wlan_secmode_t *secmode)
13060ba2cbe9Sxc {
13070ba2cbe9Sxc 	wl_encryption_t	encryption;
13080ba2cbe9Sxc 
13090ba2cbe9Sxc 	switch (*secmode) {
1310f595a68aSyz 	case DLADM_WLAN_SECMODE_NONE:
13110ba2cbe9Sxc 		encryption = WL_NOENCRYPTION;
13120ba2cbe9Sxc 		break;
1313f595a68aSyz 	case DLADM_WLAN_SECMODE_WEP:
13140ba2cbe9Sxc 		encryption = WL_ENC_WEP;
13150ba2cbe9Sxc 		break;
1316a399b765Szf 	case DLADM_WLAN_SECMODE_WPA:
1317a399b765Szf 		return (0);
13180ba2cbe9Sxc 	default:
1319d62bc4baSyz 		return (DLADM_STATUS_NOTSUP);
13200ba2cbe9Sxc 	}
13214ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &encryption,
13224ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_ENCRYPTION, sizeof (encryption), B_TRUE));
13230ba2cbe9Sxc }
13240ba2cbe9Sxc 
1325d62bc4baSyz static dladm_status_t
do_set_key(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_key_t * keys,uint_t key_count)13264ac67f02SAnurag S. Maskey do_set_key(dladm_handle_t handle, datalink_id_t linkid, dladm_wlan_key_t *keys,
1327f595a68aSyz     uint_t key_count)
13280ba2cbe9Sxc {
1329*4202e8bfSToomas Soome 	uint_t			i;
13300ba2cbe9Sxc 	wl_wep_key_t		*wkp;
13310ba2cbe9Sxc 	wl_wep_key_tab_t	wepkey_tab;
1332a399b765Szf 	dladm_wlan_key_t	*kp;
13330ba2cbe9Sxc 
13340ba2cbe9Sxc 	if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
1335d62bc4baSyz 		return (DLADM_STATUS_BADARG);
13360ba2cbe9Sxc 
13370ba2cbe9Sxc 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
13380ba2cbe9Sxc 	for (i = 0; i < MAX_NWEPKEYS; i++)
13390ba2cbe9Sxc 		wepkey_tab[i].wl_wep_operation = WL_NUL;
13400ba2cbe9Sxc 
13410ba2cbe9Sxc 	for (i = 0; i < key_count; i++) {
13420ba2cbe9Sxc 		kp = &keys[i];
13430ba2cbe9Sxc 		if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
1344d62bc4baSyz 			return (DLADM_STATUS_BADARG);
1345f595a68aSyz 		if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
1346f595a68aSyz 		    kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
1347d62bc4baSyz 			return (DLADM_STATUS_BADARG);
13480ba2cbe9Sxc 
13490ba2cbe9Sxc 		wkp = &wepkey_tab[kp->wk_idx - 1];
13500ba2cbe9Sxc 		wkp->wl_wep_operation = WL_ADD;
13510ba2cbe9Sxc 		wkp->wl_wep_length = kp->wk_len;
13520ba2cbe9Sxc 		(void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
13530ba2cbe9Sxc 	}
13540ba2cbe9Sxc 
13554ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &wepkey_tab,
13564ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_KEY_TAB, sizeof (wepkey_tab), B_TRUE));
13570ba2cbe9Sxc }
13580ba2cbe9Sxc 
1359d62bc4baSyz static dladm_status_t
do_set_essid(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_essid_t * essid)13604ac67f02SAnurag S. Maskey do_set_essid(dladm_handle_t handle, datalink_id_t linkid,
13614ac67f02SAnurag S. Maskey     dladm_wlan_essid_t *essid)
13620ba2cbe9Sxc {
13630ba2cbe9Sxc 	wl_essid_t	iessid;
13640ba2cbe9Sxc 
13650ba2cbe9Sxc 	(void) memset(&iessid, 0, sizeof (essid));
13660ba2cbe9Sxc 
13670ba2cbe9Sxc 	if (essid != NULL && essid->we_bytes[0] != '\0') {
13680ba2cbe9Sxc 		iessid.wl_essid_length = strlen(essid->we_bytes);
13690ba2cbe9Sxc 		(void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
13700ba2cbe9Sxc 		    sizeof (iessid.wl_essid_essid));
13710ba2cbe9Sxc 	} else {
1372d62bc4baSyz 		return (DLADM_STATUS_BADARG);
13730ba2cbe9Sxc 	}
13744ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &iessid, MAC_PROP_WL_ESSID,
1375bcb5c89dSSowmini Varadhan 	    sizeof (iessid), B_TRUE));
13760ba2cbe9Sxc }
13770ba2cbe9Sxc 
1378f595a68aSyz static dladm_status_t
do_set_channel(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_channel_t * channel)13794ac67f02SAnurag S. Maskey do_set_channel(dladm_handle_t handle, datalink_id_t linkid,
13804ac67f02SAnurag S. Maskey     dladm_wlan_channel_t *channel)
13810ba2cbe9Sxc {
13820ba2cbe9Sxc 	wl_phy_conf_t phy_conf;
13830ba2cbe9Sxc 
13840ba2cbe9Sxc 	if (*channel > MAX_CHANNEL_NUM)
1385d62bc4baSyz 		return (DLADM_STATUS_BADVAL);
13860ba2cbe9Sxc 
13870ba2cbe9Sxc 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
13880ba2cbe9Sxc 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
13890ba2cbe9Sxc 
13904ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &phy_conf,
13914ac67f02SAnurag S. Maskey 	    MAC_PROP_WL_PHY_CONFIG, sizeof (phy_conf), B_TRUE));
13920ba2cbe9Sxc }
13930ba2cbe9Sxc 
1394d62bc4baSyz static dladm_status_t
do_set_createibss(dladm_handle_t handle,datalink_id_t linkid,boolean_t * create_ibss)13954ac67f02SAnurag S. Maskey do_set_createibss(dladm_handle_t handle, datalink_id_t linkid,
13964ac67f02SAnurag S. Maskey     boolean_t *create_ibss)
13970ba2cbe9Sxc {
13980ba2cbe9Sxc 	wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
13990ba2cbe9Sxc 
14004ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &cr, MAC_PROP_WL_CREATE_IBSS,
1401bcb5c89dSSowmini Varadhan 	    sizeof (cr), B_TRUE));
14020ba2cbe9Sxc }
14030ba2cbe9Sxc 
14040ba2cbe9Sxc static void
generate_essid(dladm_wlan_essid_t * essid)1405f595a68aSyz generate_essid(dladm_wlan_essid_t *essid)
14060ba2cbe9Sxc {
14070ba2cbe9Sxc 	srandom(gethrtime());
1408f595a68aSyz 	(void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
1409f595a68aSyz 	    random());
14100ba2cbe9Sxc }
1411a399b765Szf 
1412a399b765Szf static dladm_status_t
do_get_capability(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)14134ac67f02SAnurag S. Maskey do_get_capability(dladm_handle_t handle, datalink_id_t linkid, void *buf,
14144ac67f02SAnurag S. Maskey     int buflen)
1415a399b765Szf {
14164ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_CAPABILITY,
1417bcb5c89dSSowmini Varadhan 	    buflen, B_FALSE));
1418a399b765Szf }
1419a399b765Szf 
1420a399b765Szf static dladm_status_t
do_get_wpamode(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)14214ac67f02SAnurag S. Maskey do_get_wpamode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
14224ac67f02SAnurag S. Maskey     int buflen)
1423a399b765Szf {
14244ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_WPA, buflen,
1425bcb5c89dSSowmini Varadhan 	    B_FALSE));
1426a399b765Szf }
1427a399b765Szf 
1428a399b765Szf dladm_status_t
dladm_wlan_wpa_get_sr(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_ess_t * sr,uint_t escnt,uint_t * estot)14294ac67f02SAnurag S. Maskey dladm_wlan_wpa_get_sr(dladm_handle_t handle, datalink_id_t linkid,
14304ac67f02SAnurag S. Maskey     dladm_wlan_ess_t *sr, uint_t escnt, uint_t *estot)
1431a399b765Szf {
1432a399b765Szf 	int		i, n;
1433a399b765Szf 	wl_wpa_ess_t	*es;
1434a399b765Szf 	dladm_status_t	status;
1435a399b765Szf 
1436bcb5c89dSSowmini Varadhan 	es = malloc(WLDP_BUFSIZE);
1437bcb5c89dSSowmini Varadhan 	if (es == NULL)
1438a399b765Szf 		return (DLADM_STATUS_NOMEM);
1439a399b765Szf 
14404ac67f02SAnurag S. Maskey 	status = i_dladm_wlan_param(handle, linkid, es, MAC_PROP_WL_SCANRESULTS,
1441bcb5c89dSSowmini Varadhan 	    WLDP_BUFSIZE, B_FALSE);
1442a399b765Szf 
1443a399b765Szf 	if (status == DLADM_STATUS_OK) {
1444a399b765Szf 		n = (es->count > escnt) ? escnt : es->count;
1445a399b765Szf 		for (i = 0; i < n; i ++) {
1446a399b765Szf 			(void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
1447a399b765Szf 			    DLADM_WLAN_BSSID_LEN);
1448a399b765Szf 			sr[i].we_ssid_len = es->ess[i].ssid_len;
1449a399b765Szf 			(void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
1450a399b765Szf 			    es->ess[i].ssid_len);
1451a399b765Szf 			sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
1452a399b765Szf 			(void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
1453a399b765Szf 			    es->ess[i].wpa_ie_len);
1454a399b765Szf 			sr[i].we_freq = es->ess[i].freq;
1455a399b765Szf 		}
1456a399b765Szf 		*estot = n;
1457a399b765Szf 	}
1458a399b765Szf 
1459bcb5c89dSSowmini Varadhan 	free(es);
1460a399b765Szf 	return (status);
1461a399b765Szf }
1462a399b765Szf 
1463a399b765Szf dladm_status_t
dladm_wlan_wpa_set_ie(dladm_handle_t handle,datalink_id_t linkid,uint8_t * wpa_ie,uint_t wpa_ie_len)14644ac67f02SAnurag S. Maskey dladm_wlan_wpa_set_ie(dladm_handle_t handle, datalink_id_t linkid,
14654ac67f02SAnurag S. Maskey     uint8_t *wpa_ie, uint_t wpa_ie_len)
1466a399b765Szf {
1467a399b765Szf 	wl_wpa_ie_t *ie;
1468a399b765Szf 	uint_t len;
1469a399b765Szf 	dladm_status_t	status;
1470a399b765Szf 
1471a399b765Szf 	if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
1472a399b765Szf 		return (DLADM_STATUS_BADARG);
1473a399b765Szf 	len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
1474a399b765Szf 	ie = malloc(len);
1475a399b765Szf 	if (ie == NULL)
1476a399b765Szf 		return (DLADM_STATUS_NOMEM);
1477a399b765Szf 
1478a399b765Szf 	(void) memset(ie, 0, len);
1479a399b765Szf 	ie->wpa_ie_len = wpa_ie_len;
1480a399b765Szf 	(void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
1481a399b765Szf 
14824ac67f02SAnurag S. Maskey 	status = i_dladm_wlan_param(handle, linkid, ie, MAC_PROP_WL_SETOPTIE,
14834ac67f02SAnurag S. Maskey 	    len, B_TRUE);
1484a399b765Szf 	free(ie);
1485a399b765Szf 
1486a399b765Szf 	return (status);
1487a399b765Szf }
1488a399b765Szf 
1489a399b765Szf dladm_status_t
dladm_wlan_wpa_set_wpa(dladm_handle_t handle,datalink_id_t linkid,boolean_t flag)14904ac67f02SAnurag S. Maskey dladm_wlan_wpa_set_wpa(dladm_handle_t handle, datalink_id_t linkid,
14914ac67f02SAnurag S. Maskey     boolean_t flag)
1492a399b765Szf {
1493d62bc4baSyz 	wl_wpa_t	wpa;
1494a399b765Szf 
1495a399b765Szf 	wpa.wpa_flag = flag;
14964ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &wpa, MAC_PROP_WL_WPA,
1497bcb5c89dSSowmini Varadhan 	    sizeof (wpa), B_TRUE));
1498a399b765Szf }
1499a399b765Szf 
1500a399b765Szf dladm_status_t
dladm_wlan_wpa_del_key(dladm_handle_t handle,datalink_id_t linkid,uint_t key_idx,const dladm_wlan_bssid_t * addr)15014ac67f02SAnurag S. Maskey dladm_wlan_wpa_del_key(dladm_handle_t handle, datalink_id_t linkid,
15024ac67f02SAnurag S. Maskey     uint_t key_idx, const dladm_wlan_bssid_t *addr)
1503a399b765Szf {
1504d62bc4baSyz 	wl_del_key_t	wk;
1505a399b765Szf 
1506a399b765Szf 	wk.idk_keyix = key_idx;
1507a399b765Szf 	if (addr != NULL)
1508a399b765Szf 		(void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
1509a399b765Szf 		    DLADM_WLAN_BSSID_LEN);
1510a399b765Szf 
15114ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_DELKEY,
1512bcb5c89dSSowmini Varadhan 	    sizeof (wk), B_TRUE));
1513a399b765Szf }
1514a399b765Szf 
1515a399b765Szf dladm_status_t
dladm_wlan_wpa_set_key(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_cipher_t cipher,const dladm_wlan_bssid_t * addr,boolean_t set_tx,uint64_t seq,uint_t key_idx,uint8_t * key,uint_t key_len)15164ac67f02SAnurag S. Maskey dladm_wlan_wpa_set_key(dladm_handle_t handle, datalink_id_t linkid,
15174ac67f02SAnurag S. Maskey     dladm_wlan_cipher_t cipher, const dladm_wlan_bssid_t *addr,
15184ac67f02SAnurag S. Maskey     boolean_t set_tx, uint64_t seq, uint_t key_idx, uint8_t *key,
15194ac67f02SAnurag S. Maskey     uint_t key_len)
1520a399b765Szf {
1521d62bc4baSyz 	wl_key_t	wk;
1522a399b765Szf 
1523a399b765Szf 	(void) memset(&wk, 0, sizeof (wl_key_t));
1524a399b765Szf 	switch (cipher) {
1525a399b765Szf 	case DLADM_WLAN_CIPHER_WEP:
1526a399b765Szf 		wk.ik_type = IEEE80211_CIPHER_WEP;
1527a399b765Szf 		break;
1528a399b765Szf 	case DLADM_WLAN_CIPHER_TKIP:
1529a399b765Szf 		wk.ik_type = IEEE80211_CIPHER_TKIP;
1530a399b765Szf 		break;
1531a399b765Szf 	case DLADM_WLAN_CIPHER_AES_OCB:
1532a399b765Szf 		wk.ik_type = IEEE80211_CIPHER_AES_OCB;
1533a399b765Szf 		break;
1534a399b765Szf 	case DLADM_WLAN_CIPHER_AES_CCM:
1535a399b765Szf 		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
1536a399b765Szf 		break;
1537a399b765Szf 	case DLADM_WLAN_CIPHER_CKIP:
1538a399b765Szf 		wk.ik_type = IEEE80211_CIPHER_CKIP;
1539a399b765Szf 		break;
1540a399b765Szf 	case DLADM_WLAN_CIPHER_NONE:
1541a399b765Szf 		wk.ik_type = IEEE80211_CIPHER_NONE;
1542a399b765Szf 		break;
1543a399b765Szf 	default:
1544a399b765Szf 		return (DLADM_STATUS_BADARG);
1545a399b765Szf 	}
1546a399b765Szf 	wk.ik_flags = IEEE80211_KEY_RECV;
1547a399b765Szf 	if (set_tx) {
1548a399b765Szf 		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
1549a399b765Szf 		(void) memcpy(wk.ik_macaddr, addr->wb_bytes,
1550a399b765Szf 		    DLADM_WLAN_BSSID_LEN);
1551a399b765Szf 	} else
1552a399b765Szf 		(void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
1553a399b765Szf 	wk.ik_keyix = key_idx;
1554a399b765Szf 	wk.ik_keylen = key_len;
1555a399b765Szf 	(void) memcpy(&wk.ik_keyrsc, &seq, 6);	/* only use 48-bit of seq */
1556a399b765Szf 	(void) memcpy(wk.ik_keydata, key, key_len);
1557a399b765Szf 
15584ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_KEY,
1559bcb5c89dSSowmini Varadhan 	    sizeof (wk), B_TRUE));
1560a399b765Szf }
1561a399b765Szf 
1562a399b765Szf dladm_status_t
dladm_wlan_wpa_set_mlme(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_mlme_op_t op,dladm_wlan_reason_t reason,dladm_wlan_bssid_t * bssid)15634ac67f02SAnurag S. Maskey dladm_wlan_wpa_set_mlme(dladm_handle_t handle, datalink_id_t linkid,
15644ac67f02SAnurag S. Maskey     dladm_wlan_mlme_op_t op, dladm_wlan_reason_t reason,
15654ac67f02SAnurag S. Maskey     dladm_wlan_bssid_t *bssid)
1566a399b765Szf {
1567a399b765Szf 	wl_mlme_t mlme;
1568a399b765Szf 
1569a399b765Szf 	(void) memset(&mlme, 0, sizeof (wl_mlme_t));
1570a399b765Szf 	switch (op) {
1571a399b765Szf 	case DLADM_WLAN_MLME_ASSOC:
1572a399b765Szf 		mlme.im_op = IEEE80211_MLME_ASSOC;
1573a399b765Szf 		break;
1574a399b765Szf 	case DLADM_WLAN_MLME_DISASSOC:
1575a399b765Szf 		mlme.im_op = IEEE80211_MLME_DISASSOC;
1576a399b765Szf 		break;
1577a399b765Szf 	default:
1578a399b765Szf 		return (DLADM_STATUS_BADARG);
1579a399b765Szf 	}
1580a399b765Szf 	mlme.im_reason = reason;
1581a399b765Szf 	if (bssid != NULL)
1582a399b765Szf 		(void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
1583a399b765Szf 		    DLADM_WLAN_BSSID_LEN);
1584a399b765Szf 
15854ac67f02SAnurag S. Maskey 	return (i_dladm_wlan_param(handle, linkid, &mlme, MAC_PROP_WL_MLME,
1586bcb5c89dSSowmini Varadhan 	    sizeof (mlme), B_TRUE));
1587a399b765Szf }
1588a399b765Szf 
1589a399b765Szf /*
1590a399b765Szf  * routines of create instance
1591a399b765Szf  */
1592a399b765Szf static scf_propertygroup_t *
add_property_group_to_instance(scf_handle_t * handle,scf_instance_t * instance,const char * pg_name,const char * pg_type)1593a399b765Szf add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
1594a399b765Szf     const char *pg_name, const char *pg_type)
1595a399b765Szf {
1596a399b765Szf 	scf_propertygroup_t *pg;
1597a399b765Szf 
1598a399b765Szf 	pg = scf_pg_create(handle);
1599a399b765Szf 	if (pg == NULL)
1600a399b765Szf 		return (NULL);
1601a399b765Szf 
1602a399b765Szf 	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
1603a399b765Szf 		scf_pg_destroy(pg);
1604a399b765Szf 		return (NULL);
1605a399b765Szf 	}
1606a399b765Szf 
1607a399b765Szf 	return (pg);
1608a399b765Szf }
1609a399b765Szf 
1610d62bc4baSyz static dladm_status_t
add_new_property(scf_handle_t * handle,const char * prop_name,scf_type_t type,const char * val,scf_transaction_t * tx)1611a399b765Szf add_new_property(scf_handle_t *handle, const char *prop_name,
1612a399b765Szf     scf_type_t type, const char *val, scf_transaction_t *tx)
1613a399b765Szf {
1614a399b765Szf 	scf_value_t *value = NULL;
1615a399b765Szf 	scf_transaction_entry_t *entry = NULL;
1616a399b765Szf 
1617a399b765Szf 	entry = scf_entry_create(handle);
1618a399b765Szf 	if (entry == NULL)
1619a399b765Szf 		goto out;
1620a399b765Szf 
1621a399b765Szf 	value = scf_value_create(handle);
1622a399b765Szf 	if (value == NULL)
1623a399b765Szf 		goto out;
1624a399b765Szf 
1625a399b765Szf 	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
1626a399b765Szf 		goto out;
1627a399b765Szf 
1628a399b765Szf 	if (scf_value_set_from_string(value, type, val) != 0)
1629a399b765Szf 		goto out;
1630a399b765Szf 
1631a399b765Szf 	if (scf_entry_add_value(entry, value) != 0)
1632a399b765Szf 		goto out;
1633a399b765Szf 
1634d62bc4baSyz 	return (DLADM_STATUS_OK);
1635a399b765Szf 
1636a399b765Szf out:
1637a399b765Szf 	if (value != NULL)
1638a399b765Szf 		scf_value_destroy(value);
1639a399b765Szf 	if (entry != NULL)
1640a399b765Szf 		scf_entry_destroy(entry);
1641a399b765Szf 
1642d62bc4baSyz 	return (DLADM_STATUS_FAILED);
1643a399b765Szf }
1644a399b765Szf 
1645d62bc4baSyz static dladm_status_t
add_pg_method(scf_handle_t * handle,scf_instance_t * instance,const char * pg_name,const char * flags)1646a399b765Szf add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
1647a399b765Szf     const char *pg_name, const char *flags)
1648a399b765Szf {
1649a399b765Szf 	int			rv, size;
1650d62bc4baSyz 	dladm_status_t		status = DLADM_STATUS_FAILED;
1651a399b765Szf 	char			*command = NULL;
1652a399b765Szf 	scf_transaction_t	*tran = NULL;
1653a399b765Szf 	scf_propertygroup_t	*pg;
1654a399b765Szf 
1655a399b765Szf 	pg = add_property_group_to_instance(handle, instance,
1656a399b765Szf 	    pg_name, SCF_GROUP_METHOD);
1657a399b765Szf 	if (pg == NULL)
1658a399b765Szf 		goto out;
1659a399b765Szf 
1660a399b765Szf 	tran = scf_transaction_create(handle);
1661a399b765Szf 	if (tran == NULL)
1662a399b765Szf 		goto out;
1663a399b765Szf 
1664a399b765Szf 	size = strlen(SVC_METHOD) + strlen("  ") + strlen(flags) + 1;
1665a399b765Szf 	command = malloc(size);
1666a399b765Szf 	if (command == NULL) {
1667d62bc4baSyz 		status = DLADM_STATUS_NOMEM;
1668a399b765Szf 		goto out;
1669a399b765Szf 	}
1670a399b765Szf 	(void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
1671a399b765Szf 
1672a399b765Szf 	do {
1673a399b765Szf 		if (scf_transaction_start(tran, pg) != 0)
1674a399b765Szf 			goto out;
1675a399b765Szf 
1676a399b765Szf 		if (add_new_property(handle, SCF_PROPERTY_EXEC,
1677d62bc4baSyz 		    SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
1678a399b765Szf 			goto out;
1679a399b765Szf 		}
1680a399b765Szf 
1681a399b765Szf 		rv = scf_transaction_commit(tran);
1682a399b765Szf 		switch (rv) {
1683a399b765Szf 		case 1:
1684d62bc4baSyz 			status = DLADM_STATUS_OK;
1685a399b765Szf 			goto out;
1686a399b765Szf 		case 0:
1687a399b765Szf 			scf_transaction_destroy_children(tran);
1688a399b765Szf 			if (scf_pg_update(pg) == -1) {
1689a399b765Szf 				goto out;
1690a399b765Szf 			}
1691a399b765Szf 			break;
1692a399b765Szf 		case -1:
1693a399b765Szf 		default:
1694a399b765Szf 			goto out;
1695a399b765Szf 		}
1696a399b765Szf 	} while (rv == 0);
1697a399b765Szf 
1698a399b765Szf out:
1699a399b765Szf 	if (tran != NULL) {
1700a399b765Szf 		scf_transaction_destroy_children(tran);
1701a399b765Szf 		scf_transaction_destroy(tran);
1702a399b765Szf 	}
1703a399b765Szf 
1704a399b765Szf 	if (pg != NULL)
1705a399b765Szf 		scf_pg_destroy(pg);
1706a399b765Szf 
1707a399b765Szf 	if (command != NULL)
1708a399b765Szf 		free(command);
1709a399b765Szf 
1710a399b765Szf 	return (status);
1711a399b765Szf }
1712a399b765Szf 
1713d62bc4baSyz static dladm_status_t
do_create_instance(scf_handle_t * handle,scf_service_t * svc,const char * instance_name,const char * command)1714a399b765Szf do_create_instance(scf_handle_t *handle, scf_service_t *svc,
1715a399b765Szf     const char *instance_name, const char *command)
1716a399b765Szf {
1717d62bc4baSyz 	dladm_status_t status = DLADM_STATUS_FAILED;
1718a399b765Szf 	char *buf;
1719a399b765Szf 	ssize_t max_fmri_len;
1720a399b765Szf 	scf_instance_t *instance;
1721a399b765Szf 
1722a399b765Szf 	instance = scf_instance_create(handle);
1723a399b765Szf 	if (instance == NULL)
1724a399b765Szf 		goto out;
1725a399b765Szf 
1726a399b765Szf 	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
1727a399b765Szf 		if (scf_error() == SCF_ERROR_EXISTS)
1728a399b765Szf 			/* Let the caller deal with the duplicate instance */
1729d62bc4baSyz 			status = DLADM_STATUS_EXIST;
1730a399b765Szf 		goto out;
1731a399b765Szf 	}
1732a399b765Szf 
1733a399b765Szf 	if (add_pg_method(handle, instance, "start",
1734d62bc4baSyz 	    command) != DLADM_STATUS_OK) {
1735a399b765Szf 		goto out;
1736a399b765Szf 	}
1737a399b765Szf 
1738a399b765Szf 	/* enabling the instance */
1739a399b765Szf 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1740a399b765Szf 	if ((buf = malloc(max_fmri_len + 1)) == NULL)
1741a399b765Szf 		goto out;
1742a399b765Szf 
1743a399b765Szf 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1744a399b765Szf 		if ((smf_disable_instance(buf, 0) != 0) ||
1745a399b765Szf 		    (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
1746a399b765Szf 			goto out;
1747a399b765Szf 		}
1748d62bc4baSyz 		status = DLADM_STATUS_OK;
1749a399b765Szf 	}
1750a399b765Szf 
1751a399b765Szf out:
1752a399b765Szf 	if (instance != NULL)
1753a399b765Szf 		scf_instance_destroy(instance);
1754a399b765Szf 	return (status);
1755a399b765Szf }
1756a399b765Szf 
1757d62bc4baSyz static dladm_status_t
create_instance(const char * instance_name,const char * command)1758a399b765Szf create_instance(const char *instance_name, const char *command)
1759a399b765Szf {
1760d62bc4baSyz 	dladm_status_t status = DLADM_STATUS_FAILED;
1761a399b765Szf 	scf_service_t *svc = NULL;
1762a399b765Szf 	scf_handle_t *handle = NULL;
1763a399b765Szf 
1764a399b765Szf 	handle = scf_handle_create(SCF_VERSION);
1765a399b765Szf 	if (handle == NULL)
1766a399b765Szf 		goto out;
1767a399b765Szf 
1768a399b765Szf 	if (scf_handle_bind(handle) == -1)
1769a399b765Szf 		goto out;
1770a399b765Szf 
1771a399b765Szf 	if ((svc = scf_service_create(handle)) == NULL)
1772a399b765Szf 		goto out;
1773a399b765Szf 
1774a399b765Szf 	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
1775a399b765Szf 	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
1776a399b765Szf 		goto out;
1777a399b765Szf 
1778a399b765Szf 	status = do_create_instance(handle, svc, instance_name, command);
1779a399b765Szf 
1780a399b765Szf out:
1781a399b765Szf 	if (svc != NULL)
1782a399b765Szf 		scf_service_destroy(svc);
1783a399b765Szf 
1784a399b765Szf 	if (handle != NULL) {
1785a399b765Szf 		(void) scf_handle_unbind(handle);
1786a399b765Szf 		scf_handle_destroy(handle);
1787a399b765Szf 	}
1788a399b765Szf 
1789a399b765Szf 	return (status);
1790a399b765Szf }
1791a399b765Szf 
1792a399b765Szf /*
1793a399b765Szf  * routines of delete instance
1794a399b765Szf  */
1795a399b765Szf #define	DEFAULT_TIMEOUT	60000000
1796a399b765Szf #define	INIT_WAIT_USECS	50000
1797a399b765Szf 
1798a399b765Szf static void
wait_until_disabled(scf_handle_t * handle,char * fmri)1799a399b765Szf wait_until_disabled(scf_handle_t *handle, char *fmri)
1800a399b765Szf {
1801a399b765Szf 	char		*state;
1802a399b765Szf 	useconds_t	max;
1803a399b765Szf 	useconds_t	usecs;
1804a399b765Szf 	uint64_t	*cp = NULL;
1805a399b765Szf 	scf_simple_prop_t *sp = NULL;
1806a399b765Szf 
1807a399b765Szf 	max = DEFAULT_TIMEOUT;
1808a399b765Szf 
1809a399b765Szf 	if (((sp = scf_simple_prop_get(handle, fmri, "stop",
1810a399b765Szf 	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
1811a399b765Szf 	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
1812a399b765Szf 		max = (*cp) * 1000000;	/* convert to usecs */
1813a399b765Szf 
1814a399b765Szf 	if (sp != NULL)
1815a399b765Szf 		scf_simple_prop_free(sp);
1816a399b765Szf 
1817a399b765Szf 	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
1818a399b765Szf 		/* incremental wait */
1819a399b765Szf 		usecs *= 2;
1820a399b765Szf 		usecs = (usecs > max) ? max : usecs;
1821a399b765Szf 
1822a399b765Szf 		(void) usleep(usecs);
1823a399b765Szf 
1824a399b765Szf 		/* Check state after the wait */
1825a399b765Szf 		if ((state = smf_get_state(fmri)) != NULL) {
1826a399b765Szf 			if (strcmp(state, "disabled") == 0)
1827a399b765Szf 				return;
1828a399b765Szf 		}
1829a399b765Szf 	}
1830a399b765Szf }
1831a399b765Szf 
1832d62bc4baSyz static dladm_status_t
delete_instance(const char * instance_name)1833a399b765Szf delete_instance(const char *instance_name)
1834a399b765Szf {
1835d62bc4baSyz 	dladm_status_t	status = DLADM_STATUS_FAILED;
1836a399b765Szf 	char		*buf;
1837a399b765Szf 	ssize_t		max_fmri_len;
1838a399b765Szf 	scf_scope_t	*scope = NULL;
1839a399b765Szf 	scf_service_t	*svc = NULL;
1840a399b765Szf 	scf_handle_t	*handle = NULL;
1841a399b765Szf 	scf_instance_t	*instance;
1842a399b765Szf 
1843a399b765Szf 	handle = scf_handle_create(SCF_VERSION);
1844a399b765Szf 	if (handle == NULL)
1845a399b765Szf 		goto out;
1846a399b765Szf 
1847a399b765Szf 	if (scf_handle_bind(handle) == -1)
1848a399b765Szf 		goto out;
1849a399b765Szf 
1850a399b765Szf 	if ((scope = scf_scope_create(handle)) == NULL)
1851a399b765Szf 		goto out;
1852a399b765Szf 
1853a399b765Szf 	if ((svc = scf_service_create(handle)) == NULL)
1854a399b765Szf 		goto out;
1855a399b765Szf 
1856a399b765Szf 	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
1857a399b765Szf 		goto out;
1858a399b765Szf 
1859a399b765Szf 	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
1860a399b765Szf 		goto out;
1861a399b765Szf 
1862a399b765Szf 	instance = scf_instance_create(handle);
1863a399b765Szf 	if (instance == NULL)
1864a399b765Szf 		goto out;
1865a399b765Szf 
1866a399b765Szf 	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
1867a399b765Szf 		scf_error_t scf_errnum = scf_error();
1868a399b765Szf 
1869a399b765Szf 		if (scf_errnum == SCF_ERROR_NOT_FOUND)
1870d62bc4baSyz 			status = DLADM_STATUS_OK;
1871a399b765Szf 
1872a399b765Szf 		scf_instance_destroy(instance);
1873a399b765Szf 		goto out;
1874a399b765Szf 	}
1875a399b765Szf 
1876a399b765Szf 	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1877a399b765Szf 	if ((buf = malloc(max_fmri_len + 1)) == NULL) {
1878a399b765Szf 		scf_instance_destroy(instance);
1879a399b765Szf 		goto out;
1880a399b765Szf 	}
1881a399b765Szf 
1882a399b765Szf 	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1883a399b765Szf 		char *state;
1884a399b765Szf 
1885a399b765Szf 		state = smf_get_state(buf);
1886a399b765Szf 		if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
1887a399b765Szf 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
1888a399b765Szf 			if (smf_disable_instance(buf, 0) == 0) {
1889a399b765Szf 				/*
1890a399b765Szf 				 * Wait for some time till timeout to avoid
1891a399b765Szf 				 * a race with scf_instance_delete() below.
1892a399b765Szf 				 */
1893a399b765Szf 				wait_until_disabled(handle, buf);
1894a399b765Szf 			}
1895a399b765Szf 		}
1896a399b765Szf 	}
1897a399b765Szf 
1898a399b765Szf 	if (scf_instance_delete(instance) != 0) {
1899a399b765Szf 		scf_instance_destroy(instance);
1900a399b765Szf 		goto out;
1901a399b765Szf 	}
1902a399b765Szf 
1903a399b765Szf 	scf_instance_destroy(instance);
1904a399b765Szf 
1905d62bc4baSyz 	status = DLADM_STATUS_OK;
1906a399b765Szf 
1907a399b765Szf out:
1908a399b765Szf 	if (svc != NULL)
1909a399b765Szf 		scf_service_destroy(svc);
1910a399b765Szf 
1911a399b765Szf 	if (scope != NULL)
1912a399b765Szf 		scf_scope_destroy(scope);
1913a399b765Szf 
1914a399b765Szf 	if (handle != NULL) {
1915a399b765Szf 		(void) scf_handle_unbind(handle);
1916a399b765Szf 		scf_handle_destroy(handle);
1917a399b765Szf 	}
1918a399b765Szf 
1919a399b765Szf 	return (status);
1920a399b765Szf }
1921a399b765Szf 
1922d62bc4baSyz static dladm_status_t
wpa_instance_create(dladm_handle_t handle,datalink_id_t linkid,void * key)19234ac67f02SAnurag S. Maskey wpa_instance_create(dladm_handle_t handle, datalink_id_t linkid, void *key)
1924a399b765Szf {
1925d62bc4baSyz 	dladm_status_t	status = DLADM_STATUS_FAILED;
1926a399b765Szf 	char		*command = NULL;
1927a399b765Szf 	char		*wk_name = ((dladm_wlan_key_t *)key)->wk_name;
1928a399b765Szf 	int		size;
1929d62bc4baSyz 	char		instance_name[MAXLINKNAMELEN];
1930d62bc4baSyz 
1931d62bc4baSyz 	/*
1932d62bc4baSyz 	 * Use the link name as the instance name of the network/wpad service.
1933d62bc4baSyz 	 */
19344ac67f02SAnurag S. Maskey 	status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
19354ac67f02SAnurag S. Maskey 	    instance_name, sizeof (instance_name));
1936d62bc4baSyz 	if (status != DLADM_STATUS_OK)
1937d62bc4baSyz 		goto out;
1938a399b765Szf 
1939a399b765Szf 	size = strlen(instance_name) + strlen(" -i  -k ") + strlen(wk_name) + 1;
1940a399b765Szf 	command = malloc(size);
1941a399b765Szf 	if (command == NULL) {
1942d62bc4baSyz 		status = DLADM_STATUS_NOMEM;
1943a399b765Szf 		goto out;
1944a399b765Szf 	}
1945a399b765Szf 	(void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
1946a399b765Szf 
1947a399b765Szf 	status = create_instance(instance_name, command);
1948d62bc4baSyz 	if (status == DLADM_STATUS_EXIST) {
1949a399b765Szf 		/*
1950a399b765Szf 		 * Delete the existing instance and create a new instance
1951a399b765Szf 		 * with the supplied arguments.
1952a399b765Szf 		 */
1953a399b765Szf 		if ((status = delete_instance(instance_name)) ==
1954d62bc4baSyz 		    DLADM_STATUS_OK) {
1955a399b765Szf 			status = create_instance(instance_name, command);
1956a399b765Szf 		}
1957a399b765Szf 	}
1958a399b765Szf 
1959a399b765Szf out:
1960a399b765Szf 	if (command != NULL)
1961a399b765Szf 		free(command);
1962a399b765Szf 
1963a399b765Szf 	return (status);
1964a399b765Szf }
1965a399b765Szf 
1966d62bc4baSyz static dladm_status_t
wpa_instance_delete(dladm_handle_t handle,datalink_id_t linkid)19674ac67f02SAnurag S. Maskey wpa_instance_delete(dladm_handle_t handle, datalink_id_t linkid)
1968a399b765Szf {
1969d62bc4baSyz 	char	instance_name[MAXLINKNAMELEN];
1970a399b765Szf 
1971d62bc4baSyz 	/*
1972d62bc4baSyz 	 * Get the instance name of the network/wpad service (the same as
1973d62bc4baSyz 	 * the link name).
1974d62bc4baSyz 	 */
19754ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
19764ac67f02SAnurag S. Maskey 	    instance_name, sizeof (instance_name)) != DLADM_STATUS_OK)
1977d62bc4baSyz 		return (DLADM_STATUS_FAILED);
1978a399b765Szf 
1979d62bc4baSyz 	return (delete_instance(instance_name));
1980a399b765Szf }
1981