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