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