6659 nvlist_free(NULL) is a no-op
[illumos-gate.git] / usr / src / lib / libdladm / common / libdlwlan.c
blob0593ae3cfc233dbec0ebec73b43d19268b30dd68
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
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);
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);
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 *);
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 *);
99 static dladm_status_t dladm_wlan_wlresult2status(wldp_t *);
100 static dladm_status_t dladm_wlan_validate(dladm_handle_t, datalink_id_t);
102 static val_desc_t linkstatus_vals[] = {
103 { "disconnected", DLADM_WLAN_LINK_DISCONNECTED },
104 { "connected", DLADM_WLAN_LINK_CONNECTED }
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 }
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 }
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 }
129 static val_desc_t auth_vals[] = {
130 { "open", DLADM_WLAN_AUTH_OPEN },
131 { "shared", DLADM_WLAN_AUTH_SHARED }
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 }
140 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
142 static dladm_status_t
143 dladm_wlan_wlresult2status(wldp_t *gbuf)
145 switch (gbuf->wldp_result) {
146 case WL_SUCCESS:
147 return (DLADM_STATUS_OK);
149 case WL_NOTSUPPORTED:
150 case WL_LACK_FEATURE:
151 return (DLADM_STATUS_NOTSUP);
153 case WL_READONLY:
154 return (DLADM_STATUS_PROPRDONLY);
156 default:
157 break;
160 return (DLADM_STATUS_FAILED);
163 static dladm_wlan_mode_t
164 do_convert_mode(wl_phy_conf_t *phyp)
166 wl_erp_t *wlep = &phyp->wl_phy_erp_conf;
167 wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
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;
183 return (DLADM_WLAN_MODE_NONE);
186 boolean_t
187 i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp)
189 wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf;
190 wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
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);
206 return (B_TRUE);
209 #define IEEE80211_RATE 0x7f
210 static void
211 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp)
213 int i;
215 (void) memset(attrp, 0, sizeof (*attrp));
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;
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;
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;
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;
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;
239 attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
240 attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
242 attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
243 attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
245 for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
246 wlp->wl_supported_rates[i] &= IEEE80211_RATE;
247 if (wlp->wl_supported_rates[i] > attrp->wa_speed)
248 attrp->wa_speed = wlp->wl_supported_rates[i];
250 if (attrp->wa_speed > 0)
251 attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
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;
258 dladm_status_t
259 dladm_wlan_scan(dladm_handle_t handle, datalink_id_t linkid, void *arg,
260 boolean_t (*func)(void *, dladm_wlan_attr_t *))
262 int 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;
271 if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
272 goto done;
274 status = do_get_linkstatus(handle, linkid, &wl_status,
275 sizeof (wl_status));
276 if (status != DLADM_STATUS_OK)
277 goto done;
279 if ((status = do_scan(handle, linkid, buf, sizeof (buf))) !=
280 DLADM_STATUS_OK)
281 goto done;
283 if (func == NULL) {
284 status = DLADM_STATUS_OK;
285 goto done;
288 wls = malloc(WLDP_BUFSIZE);
289 if (wls == NULL) {
290 status = DLADM_STATUS_NOMEM;
291 goto done;
294 if ((status = do_get_esslist(handle, linkid, wls, WLDP_BUFSIZE))
295 != DLADM_STATUS_OK)
296 goto done;
298 wlp = wls->wl_ess_list_ess;
299 count = wls->wl_ess_list_num;
301 for (i = 0; i < count; i++, wlp++) {
302 fill_wlan_attr(wlp, &wlattr);
303 if (!func(arg, &wlattr))
304 break;
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));
316 status = DLADM_STATUS_OK;
317 done:
318 free(wls);
319 return (status);
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.
330 typedef struct attr_node {
331 dladm_wlan_attr_t an_attr;
332 struct attr_node *an_next;
333 } attr_node_t;
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;
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().
346 static int
347 attr_compare(const void *p1, const void *p2)
349 dladm_wlan_attr_t *attrp1, *attrp2;
351 attrp1 = (*(dladm_wlan_attr_t **)p1);
352 attrp2 = (*(dladm_wlan_attr_t **)p2);
354 if (attrp1->wa_strength < attrp2->wa_strength)
355 return (1);
357 if (attrp1->wa_strength > attrp2->wa_strength)
358 return (-1);
360 return (attrp2->wa_speed - attrp1->wa_speed);
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.
368 static boolean_t
369 connect_cb(void *arg, dladm_wlan_attr_t *attrp)
371 attr_node_t *nodep;
372 dladm_wlan_attr_t *fattrp;
373 connect_state_t *statep = (connect_state_t *)arg;
375 fattrp = statep->cs_attr;
376 if (fattrp == NULL)
377 goto append;
379 if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
380 return (B_TRUE);
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);
387 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
388 fattrp->wa_secmode != attrp->wa_secmode)
389 return (B_TRUE);
391 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 &&
392 fattrp->wa_mode != attrp->wa_mode)
393 return (B_TRUE);
395 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 &&
396 fattrp->wa_strength != attrp->wa_strength)
397 return (B_TRUE);
399 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 &&
400 fattrp->wa_speed != attrp->wa_speed)
401 return (B_TRUE);
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;
408 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
409 fattrp->wa_bsstype != attrp->wa_bsstype)
410 return (B_TRUE);
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);
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++;
426 return (B_TRUE);
429 #define IEEE80211_C_WPA 0x01800000
431 static dladm_status_t
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)
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;
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;
454 secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ?
455 attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE;
457 if ((status = do_set_encryption(handle, linkid, &secmode)) !=
458 DLADM_STATUS_OK)
459 goto fail;
461 authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ?
462 attrp->wa_auth : DLADM_WLAN_AUTH_OPEN;
464 if ((status = do_set_authmode(handle, linkid, &authmode)) !=
465 DLADM_STATUS_OK)
466 goto fail;
468 bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ?
469 attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS;
471 if ((status = do_set_bsstype(handle, linkid, &bsstype)) !=
472 DLADM_STATUS_OK)
473 goto fail;
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;
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;
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);
498 if (create_ibss) {
499 status = do_set_channel(handle, linkid, &channel);
500 if (status != DLADM_STATUS_OK)
501 goto fail;
503 status = do_set_createibss(handle, linkid, &create_ibss);
504 if (status != DLADM_STATUS_OK)
505 goto fail;
507 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) {
508 generate_essid(&essid);
509 essid_valid = B_TRUE;
513 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) {
514 essid = attrp->wa_essid;
515 essid_valid = B_TRUE;
518 if (!essid_valid) {
519 status = DLADM_STATUS_FAILED;
520 goto fail;
523 if ((status = do_set_essid(handle, linkid, &essid)) != DLADM_STATUS_OK)
524 goto fail;
527 * Because wpa daemon needs getting essid from driver,
528 * we need call do_set_essid() first, then call wpa_instance_create().
530 if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL)
531 (void) wpa_instance_create(handle, linkid, keys);
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;
540 if (wl_status == WL_CONNECTED)
541 break;
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;
550 status = DLADM_STATUS_OK;
551 fail:
552 return (status);
555 dladm_status_t
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)
560 int i;
561 char buf[WLDP_BUFSIZE];
562 connect_state_t state = {0, NULL, 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;
569 if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
570 return (status);
572 if ((status = do_get_linkstatus(handle, linkid, &wl_status,
573 sizeof (wl_status))) != DLADM_STATUS_OK)
574 goto done;
576 if (wl_status == WL_CONNECTED) {
577 status = DLADM_STATUS_ISCONN;
578 goto done;
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);
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;
596 state.cs_attr = attrp;
597 state.cs_list = NULL;
598 state.cs_count = 0;
600 status = dladm_wlan_scan(handle, linkid, &state, connect_cb);
601 if (status != DLADM_STATUS_OK)
602 goto done;
604 if (state.cs_count == 0) {
605 if (!create_ibss) {
606 status = DLADM_STATUS_NOTFOUND;
607 goto done;
609 status = do_connect(handle, linkid, buf, sizeof (buf),
610 attrp, create_ibss, keys, key_count, timeout);
611 goto done;
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;
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;
625 qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
626 attr_compare);
628 for (i = 0; i < state.cs_count; i++) {
629 dladm_wlan_attr_t *ap = wl_list[i];
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;
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;
645 done:
646 if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
647 (void) do_disconnect(handle, linkid, buf, sizeof (buf));
649 while (state.cs_list != NULL) {
650 nodep = state.cs_list;
651 state.cs_list = nodep->an_next;
652 free(nodep);
654 free(wl_list);
655 return (status);
658 dladm_status_t
659 dladm_wlan_disconnect(dladm_handle_t handle, datalink_id_t linkid)
661 char buf[WLDP_BUFSIZE];
662 dladm_status_t status;
663 wl_linkstatus_t wl_status;
665 if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
666 return (status);
668 if ((status = do_get_linkstatus(handle, linkid, &wl_status,
669 sizeof (wl_status))) != DLADM_STATUS_OK)
670 goto done;
672 if (wl_status != WL_CONNECTED) {
673 status = DLADM_STATUS_NOTCONN;
674 goto done;
677 if ((status = do_disconnect(handle, linkid, buf, sizeof (buf)))
678 != DLADM_STATUS_OK)
679 goto done;
681 if ((status = do_get_linkstatus(handle, linkid, &wl_status,
682 sizeof (wl_status))) != DLADM_STATUS_OK)
683 goto done;
685 if (wl_status == WL_CONNECTED) {
686 status = DLADM_STATUS_FAILED;
687 goto done;
690 status = DLADM_STATUS_OK;
691 done:
692 return (status);
695 dladm_status_t
696 dladm_wlan_get_linkattr(dladm_handle_t handle, datalink_id_t linkid,
697 dladm_wlan_linkattr_t *attrp)
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;
711 if (attrp == NULL)
712 return (DLADM_STATUS_BADARG);
714 if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
715 goto done;
717 (void) memset(attrp, 0, sizeof (*attrp));
718 wl_attrp = &attrp->la_wlan_attr;
720 if ((status = do_get_linkstatus(handle, linkid, &wl_status,
721 sizeof (wl_status))) != DLADM_STATUS_OK)
722 goto done;
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;
730 if ((status = do_get_essid(handle, linkid, &wls, sizeof (wls)))
731 != DLADM_STATUS_OK)
732 goto done;
734 (void) strlcpy(wl_attrp->wa_essid.we_bytes, wls.wl_essid_essid,
735 DLADM_WLAN_MAX_ESSID_LEN);
737 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
739 if ((status = do_get_bssid(handle, linkid, buf, sizeof (buf)))
740 != DLADM_STATUS_OK)
741 goto done;
743 (void) memcpy(wl_attrp->wa_bssid.wb_bytes, buf, DLADM_WLAN_BSSID_LEN);
745 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
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;
753 if ((status = do_get_encryption(handle, linkid, &encryption,
754 sizeof (encryption))) != DLADM_STATUS_OK)
755 goto done;
757 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
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;
774 if ((status = do_get_signal(handle, linkid, &signal, sizeof (signal)))
775 != DLADM_STATUS_OK)
776 goto done;
778 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
779 wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
781 ratesp = malloc(WLDP_BUFSIZE);
782 if (ratesp == NULL) {
783 status = DLADM_STATUS_NOMEM;
784 goto done;
787 if ((status = do_get_rate(handle, linkid, ratesp, WLDP_BUFSIZE))
788 != DLADM_STATUS_OK)
789 goto done;
791 if (ratesp->wl_rates_num > 0) {
792 uint_t i, r = 0;
794 for (i = 0; i < ratesp->wl_rates_num; i++) {
795 if (ratesp->wl_rates_rates[i] > r)
796 r = ratesp->wl_rates_rates[i];
798 wl_attrp->wa_speed = r;
799 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
802 if ((status = do_get_authmode(handle, linkid, &authmode,
803 sizeof (authmode))) != DLADM_STATUS_OK)
804 goto done;
806 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
808 switch (authmode) {
809 case WL_OPENSYSTEM:
810 wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
811 break;
812 case WL_SHAREDKEY:
813 wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
814 break;
815 default:
816 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
817 break;
820 if ((status = do_get_bsstype(handle, linkid, &bsstype,
821 sizeof (bsstype))) != DLADM_STATUS_OK)
822 goto done;
824 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
826 switch (bsstype) {
827 case WL_BSS_BSS:
828 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
829 break;
830 case WL_BSS_IBSS:
831 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
832 break;
833 case WL_BSS_ANY:
834 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
835 break;
836 default:
837 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
838 break;
841 if ((status = do_get_mode(handle, linkid, &wl_phy_conf,
842 sizeof (wl_phy_conf))) != DLADM_STATUS_OK)
843 goto done;
845 wl_attrp->wa_mode = do_convert_mode(&wl_phy_conf);
846 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
847 if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
848 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
850 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
851 status = DLADM_STATUS_OK;
853 done:
854 free(ratesp);
855 return (status);
859 * Check to see if the link is wireless.
861 static dladm_status_t
862 dladm_wlan_validate(dladm_handle_t handle, datalink_id_t linkid)
864 uint32_t media;
865 dladm_status_t status;
867 status = dladm_datalink_id2info(handle, linkid, NULL, NULL, &media,
868 NULL, 0);
869 if (status == DLADM_STATUS_OK) {
870 if (media != DL_WIFI)
871 status = DLADM_STATUS_LINKINVAL;
873 return (status);
876 static boolean_t
877 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
879 int i;
881 for (i = 0; i < cnt; i++) {
882 if (strcasecmp(str, vdp[i].vd_name) == 0) {
883 *valp = vdp[i].vd_val;
884 return (B_TRUE);
887 return (B_FALSE);
890 static boolean_t
891 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
893 int i;
895 for (i = 0; i < cnt; i++) {
896 if (val == vdp[i].vd_val) {
897 *strp = vdp[i].vd_name;
898 return (B_TRUE);
901 return (B_FALSE);
904 const char *
905 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
907 (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
908 return (buf);
911 const char *
912 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
914 return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
915 IFT_OTHER));
918 static const char *
919 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
921 char *s;
923 if (!find_name_by_val(val, vdp, cnt, &s))
924 s = "";
926 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
927 return (buf);
930 const char *
931 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
933 return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
934 VALCNT(secmode_vals), buf));
937 const char *
938 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
940 return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
941 VALCNT(strength_vals), buf));
944 const char *
945 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
947 return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
948 VALCNT(mode_vals), buf));
951 const char *
952 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
954 (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
955 (float)(*speed) / 2);
956 return (buf);
959 const char *
960 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
962 return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
963 VALCNT(auth_vals), buf));
966 const char *
967 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
969 return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
970 VALCNT(bsstype_vals), buf));
973 const char *
974 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
976 return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
977 VALCNT(linkstatus_vals), buf));
980 dladm_status_t
981 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
983 if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1)
984 return (DLADM_STATUS_BADARG);
986 (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
987 return (DLADM_STATUS_OK);
990 dladm_status_t
991 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
993 int len;
994 uchar_t *buf;
996 buf = _link_aton(str, &len);
997 if (buf == NULL)
998 return (DLADM_STATUS_BADARG);
1000 if (len != DLADM_WLAN_BSSID_LEN) {
1001 free(buf);
1002 return (DLADM_STATUS_BADARG);
1005 (void) memcpy(bssid->wb_bytes, buf, len);
1006 free(buf);
1007 return (DLADM_STATUS_OK);
1010 dladm_status_t
1011 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
1013 uint_t val;
1015 if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
1016 return (DLADM_STATUS_BADARG);
1018 *secmode = (dladm_wlan_secmode_t)val;
1019 return (DLADM_STATUS_OK);
1022 dladm_status_t
1023 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
1025 uint_t val;
1027 if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
1028 return (DLADM_STATUS_BADARG);
1030 *strength = (dladm_wlan_strength_t)val;
1031 return (DLADM_STATUS_OK);
1034 dladm_status_t
1035 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
1037 uint_t val;
1039 if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
1040 return (DLADM_STATUS_BADARG);
1042 *mode = (dladm_wlan_mode_t)val;
1043 return (DLADM_STATUS_OK);
1046 dladm_status_t
1047 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
1049 *speed = (dladm_wlan_speed_t)(atof(str) * 2);
1050 return (DLADM_STATUS_OK);
1053 dladm_status_t
1054 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
1056 uint_t val;
1058 if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
1059 return (DLADM_STATUS_BADARG);
1061 *auth = (dladm_wlan_auth_t)val;
1062 return (DLADM_STATUS_OK);
1065 dladm_status_t
1066 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
1068 uint_t val;
1070 if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
1071 return (DLADM_STATUS_BADARG);
1073 *bsstype = (dladm_wlan_bsstype_t)val;
1074 return (DLADM_STATUS_OK);
1077 dladm_status_t
1078 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
1080 uint_t val;
1082 if (!find_val_by_name(str, linkstatus_vals,
1083 VALCNT(linkstatus_vals), &val)) {
1084 return (DLADM_STATUS_BADARG);
1087 *linkstatus = (dladm_wlan_linkstatus_t)val;
1088 return (DLADM_STATUS_OK);
1091 dladm_status_t
1092 i_dladm_wlan_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
1093 wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen)
1095 char linkname[MAXPATHLEN];
1096 int fd, rc;
1097 struct strioctl stri;
1098 uint32_t flags;
1099 dladm_status_t status;
1100 uint32_t media;
1101 char link[MAXLINKNAMELEN];
1103 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
1104 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1105 return (status);
1108 if (media != DL_WIFI)
1109 return (DLADM_STATUS_BADARG);
1111 if (!(flags & DLADM_OPT_ACTIVE))
1112 return (DLADM_STATUS_TEMPONLY);
1115 * dlpi_open() is not used here because libdlpi depends on libdladm,
1116 * and we do not want to introduce recursive dependencies.
1118 (void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
1119 if ((fd = open(linkname, O_RDWR)) < 0)
1120 return (dladm_errno2status(errno));
1122 gbuf->wldp_type = NET_802_11;
1123 gbuf->wldp_id = id;
1124 gbuf->wldp_length = len;
1126 stri.ic_timout = 0;
1127 stri.ic_dp = (char *)gbuf;
1128 stri.ic_cmd = cmd;
1129 stri.ic_len = cmdlen;
1131 if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
1132 if (rc > 0) {
1134 * Non-negative return value indicates the specific
1135 * operation failed and the reason for the failure
1136 * was stored in gbuf->wldp_result.
1138 status = dladm_wlan_wlresult2status(gbuf);
1139 } else {
1141 * Negative return value indicates the ioctl failed.
1143 status = dladm_errno2status(errno);
1146 (void) close(fd);
1147 return (status);
1150 static dladm_status_t
1151 do_cmd_ioctl(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1152 int buflen, uint_t cmd)
1154 wldp_t *gbuf;
1155 dladm_status_t status = DLADM_STATUS_OK;
1157 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1158 return (DLADM_STATUS_NOMEM);
1160 (void) memset(gbuf, 0, MAX_BUF_LEN);
1161 status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, cmd,
1162 WLDP_BUFSIZE, WLAN_COMMAND, sizeof (wldp_t));
1163 (void) memcpy(buf, gbuf->wldp_buf, buflen);
1164 free(gbuf);
1165 return (status);
1168 static dladm_status_t
1169 do_scan(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1171 return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_SCAN));
1174 static dladm_status_t
1175 do_disconnect(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1176 int buflen)
1178 if (do_get_wpamode(handle, linkid, buf, buflen) == 0 &&
1179 ((wl_wpa_t *)(buf))->wpa_flag > 0)
1180 (void) wpa_instance_delete(handle, linkid);
1182 return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_DISASSOCIATE));
1185 static dladm_status_t
1186 do_get_esslist(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1187 int buflen)
1189 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESS_LIST,
1190 buflen, B_FALSE));
1193 static dladm_status_t
1194 do_get_bssid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1196 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSID,
1197 buflen, B_FALSE));
1200 static dladm_status_t
1201 do_get_essid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1203 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESSID,
1204 buflen, B_FALSE));
1207 static dladm_status_t
1208 do_get_bsstype(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1209 int buflen)
1211 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSTYPE,
1212 buflen, B_FALSE));
1215 static dladm_status_t
1216 do_get_linkstatus(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1217 int buflen)
1219 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_LINKSTATUS,
1220 buflen, B_FALSE));
1223 static dladm_status_t
1224 do_get_rate(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1226 return (i_dladm_wlan_param(handle, linkid, buf,
1227 MAC_PROP_WL_DESIRED_RATES, buflen, B_FALSE));
1230 static dladm_status_t
1231 do_get_authmode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1232 int buflen)
1234 return (i_dladm_wlan_param(handle, linkid, buf,
1235 MAC_PROP_WL_AUTH_MODE, buflen, B_FALSE));
1238 static dladm_status_t
1239 do_get_encryption(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1240 int buflen)
1242 return (i_dladm_wlan_param(handle, linkid, buf,
1243 MAC_PROP_WL_ENCRYPTION, buflen, B_FALSE));
1246 static dladm_status_t
1247 do_get_signal(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1248 int buflen)
1250 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RSSI,
1251 buflen, B_FALSE));
1254 static dladm_status_t
1255 do_get_mode(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1257 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
1258 buflen, B_FALSE));
1261 static dladm_status_t
1262 do_set_bsstype(dladm_handle_t handle, datalink_id_t linkid,
1263 dladm_wlan_bsstype_t *bsstype)
1265 wl_bss_type_t ibsstype;
1267 switch (*bsstype) {
1268 case DLADM_WLAN_BSSTYPE_BSS:
1269 ibsstype = WL_BSS_BSS;
1270 break;
1271 case DLADM_WLAN_BSSTYPE_IBSS:
1272 ibsstype = WL_BSS_IBSS;
1273 break;
1274 default:
1275 ibsstype = WL_BSS_ANY;
1276 break;
1278 return (i_dladm_wlan_param(handle, linkid, &ibsstype,
1279 MAC_PROP_WL_BSSTYPE, sizeof (ibsstype), B_TRUE));
1282 static dladm_status_t
1283 do_set_authmode(dladm_handle_t handle, datalink_id_t linkid,
1284 dladm_wlan_auth_t *auth)
1286 wl_authmode_t auth_mode;
1288 switch (*auth) {
1289 case DLADM_WLAN_AUTH_OPEN:
1290 auth_mode = WL_OPENSYSTEM;
1291 break;
1292 case DLADM_WLAN_AUTH_SHARED:
1293 auth_mode = WL_SHAREDKEY;
1294 break;
1295 default:
1296 return (DLADM_STATUS_NOTSUP);
1298 return (i_dladm_wlan_param(handle, linkid, &auth_mode,
1299 MAC_PROP_WL_AUTH_MODE, sizeof (auth_mode), B_TRUE));
1302 static dladm_status_t
1303 do_set_encryption(dladm_handle_t handle, datalink_id_t linkid,
1304 dladm_wlan_secmode_t *secmode)
1306 wl_encryption_t encryption;
1308 switch (*secmode) {
1309 case DLADM_WLAN_SECMODE_NONE:
1310 encryption = WL_NOENCRYPTION;
1311 break;
1312 case DLADM_WLAN_SECMODE_WEP:
1313 encryption = WL_ENC_WEP;
1314 break;
1315 case DLADM_WLAN_SECMODE_WPA:
1316 return (0);
1317 default:
1318 return (DLADM_STATUS_NOTSUP);
1320 return (i_dladm_wlan_param(handle, linkid, &encryption,
1321 MAC_PROP_WL_ENCRYPTION, sizeof (encryption), B_TRUE));
1324 static dladm_status_t
1325 do_set_key(dladm_handle_t handle, datalink_id_t linkid, dladm_wlan_key_t *keys,
1326 uint_t key_count)
1328 int i;
1329 wl_wep_key_t *wkp;
1330 wl_wep_key_tab_t wepkey_tab;
1331 dladm_wlan_key_t *kp;
1333 if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
1334 return (DLADM_STATUS_BADARG);
1336 (void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
1337 for (i = 0; i < MAX_NWEPKEYS; i++)
1338 wepkey_tab[i].wl_wep_operation = WL_NUL;
1340 for (i = 0; i < key_count; i++) {
1341 kp = &keys[i];
1342 if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
1343 return (DLADM_STATUS_BADARG);
1344 if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
1345 kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
1346 return (DLADM_STATUS_BADARG);
1348 wkp = &wepkey_tab[kp->wk_idx - 1];
1349 wkp->wl_wep_operation = WL_ADD;
1350 wkp->wl_wep_length = kp->wk_len;
1351 (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
1354 return (i_dladm_wlan_param(handle, linkid, &wepkey_tab,
1355 MAC_PROP_WL_KEY_TAB, sizeof (wepkey_tab), B_TRUE));
1358 static dladm_status_t
1359 do_set_essid(dladm_handle_t handle, datalink_id_t linkid,
1360 dladm_wlan_essid_t *essid)
1362 wl_essid_t iessid;
1364 (void) memset(&iessid, 0, sizeof (essid));
1366 if (essid != NULL && essid->we_bytes[0] != '\0') {
1367 iessid.wl_essid_length = strlen(essid->we_bytes);
1368 (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
1369 sizeof (iessid.wl_essid_essid));
1370 } else {
1371 return (DLADM_STATUS_BADARG);
1373 return (i_dladm_wlan_param(handle, linkid, &iessid, MAC_PROP_WL_ESSID,
1374 sizeof (iessid), B_TRUE));
1377 static dladm_status_t
1378 do_set_channel(dladm_handle_t handle, datalink_id_t linkid,
1379 dladm_wlan_channel_t *channel)
1381 wl_phy_conf_t phy_conf;
1383 if (*channel > MAX_CHANNEL_NUM)
1384 return (DLADM_STATUS_BADVAL);
1386 (void) memset(&phy_conf, 0xff, sizeof (phy_conf));
1387 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
1389 return (i_dladm_wlan_param(handle, linkid, &phy_conf,
1390 MAC_PROP_WL_PHY_CONFIG, sizeof (phy_conf), B_TRUE));
1393 static dladm_status_t
1394 do_set_createibss(dladm_handle_t handle, datalink_id_t linkid,
1395 boolean_t *create_ibss)
1397 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
1399 return (i_dladm_wlan_param(handle, linkid, &cr, MAC_PROP_WL_CREATE_IBSS,
1400 sizeof (cr), B_TRUE));
1403 static void
1404 generate_essid(dladm_wlan_essid_t *essid)
1406 srandom(gethrtime());
1407 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
1408 random());
1411 static dladm_status_t
1412 do_get_capability(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1413 int buflen)
1415 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_CAPABILITY,
1416 buflen, B_FALSE));
1419 static dladm_status_t
1420 do_get_wpamode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1421 int buflen)
1423 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_WPA, buflen,
1424 B_FALSE));
1427 dladm_status_t
1428 dladm_wlan_wpa_get_sr(dladm_handle_t handle, datalink_id_t linkid,
1429 dladm_wlan_ess_t *sr, uint_t escnt, uint_t *estot)
1431 int i, n;
1432 wl_wpa_ess_t *es;
1433 dladm_status_t status;
1435 es = malloc(WLDP_BUFSIZE);
1436 if (es == NULL)
1437 return (DLADM_STATUS_NOMEM);
1439 status = i_dladm_wlan_param(handle, linkid, es, MAC_PROP_WL_SCANRESULTS,
1440 WLDP_BUFSIZE, B_FALSE);
1442 if (status == DLADM_STATUS_OK) {
1443 n = (es->count > escnt) ? escnt : es->count;
1444 for (i = 0; i < n; i ++) {
1445 (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
1446 DLADM_WLAN_BSSID_LEN);
1447 sr[i].we_ssid_len = es->ess[i].ssid_len;
1448 (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
1449 es->ess[i].ssid_len);
1450 sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
1451 (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
1452 es->ess[i].wpa_ie_len);
1453 sr[i].we_freq = es->ess[i].freq;
1455 *estot = n;
1458 free(es);
1459 return (status);
1462 dladm_status_t
1463 dladm_wlan_wpa_set_ie(dladm_handle_t handle, datalink_id_t linkid,
1464 uint8_t *wpa_ie, uint_t wpa_ie_len)
1466 wl_wpa_ie_t *ie;
1467 uint_t len;
1468 dladm_status_t status;
1470 if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
1471 return (DLADM_STATUS_BADARG);
1472 len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
1473 ie = malloc(len);
1474 if (ie == NULL)
1475 return (DLADM_STATUS_NOMEM);
1477 (void) memset(ie, 0, len);
1478 ie->wpa_ie_len = wpa_ie_len;
1479 (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
1481 status = i_dladm_wlan_param(handle, linkid, ie, MAC_PROP_WL_SETOPTIE,
1482 len, B_TRUE);
1483 free(ie);
1485 return (status);
1488 dladm_status_t
1489 dladm_wlan_wpa_set_wpa(dladm_handle_t handle, datalink_id_t linkid,
1490 boolean_t flag)
1492 wl_wpa_t wpa;
1494 wpa.wpa_flag = flag;
1495 return (i_dladm_wlan_param(handle, linkid, &wpa, MAC_PROP_WL_WPA,
1496 sizeof (wpa), B_TRUE));
1499 dladm_status_t
1500 dladm_wlan_wpa_del_key(dladm_handle_t handle, datalink_id_t linkid,
1501 uint_t key_idx, const dladm_wlan_bssid_t *addr)
1503 wl_del_key_t wk;
1505 wk.idk_keyix = key_idx;
1506 if (addr != NULL)
1507 (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
1508 DLADM_WLAN_BSSID_LEN);
1510 return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_DELKEY,
1511 sizeof (wk), B_TRUE));
1514 dladm_status_t
1515 dladm_wlan_wpa_set_key(dladm_handle_t handle, datalink_id_t linkid,
1516 dladm_wlan_cipher_t cipher, const dladm_wlan_bssid_t *addr,
1517 boolean_t set_tx, uint64_t seq, uint_t key_idx, uint8_t *key,
1518 uint_t key_len)
1520 wl_key_t wk;
1522 (void) memset(&wk, 0, sizeof (wl_key_t));
1523 switch (cipher) {
1524 case DLADM_WLAN_CIPHER_WEP:
1525 wk.ik_type = IEEE80211_CIPHER_WEP;
1526 break;
1527 case DLADM_WLAN_CIPHER_TKIP:
1528 wk.ik_type = IEEE80211_CIPHER_TKIP;
1529 break;
1530 case DLADM_WLAN_CIPHER_AES_OCB:
1531 wk.ik_type = IEEE80211_CIPHER_AES_OCB;
1532 break;
1533 case DLADM_WLAN_CIPHER_AES_CCM:
1534 wk.ik_type = IEEE80211_CIPHER_AES_CCM;
1535 break;
1536 case DLADM_WLAN_CIPHER_CKIP:
1537 wk.ik_type = IEEE80211_CIPHER_CKIP;
1538 break;
1539 case DLADM_WLAN_CIPHER_NONE:
1540 wk.ik_type = IEEE80211_CIPHER_NONE;
1541 break;
1542 default:
1543 return (DLADM_STATUS_BADARG);
1545 wk.ik_flags = IEEE80211_KEY_RECV;
1546 if (set_tx) {
1547 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
1548 (void) memcpy(wk.ik_macaddr, addr->wb_bytes,
1549 DLADM_WLAN_BSSID_LEN);
1550 } else
1551 (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
1552 wk.ik_keyix = key_idx;
1553 wk.ik_keylen = key_len;
1554 (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */
1555 (void) memcpy(wk.ik_keydata, key, key_len);
1557 return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_KEY,
1558 sizeof (wk), B_TRUE));
1561 dladm_status_t
1562 dladm_wlan_wpa_set_mlme(dladm_handle_t handle, datalink_id_t linkid,
1563 dladm_wlan_mlme_op_t op, dladm_wlan_reason_t reason,
1564 dladm_wlan_bssid_t *bssid)
1566 wl_mlme_t mlme;
1568 (void) memset(&mlme, 0, sizeof (wl_mlme_t));
1569 switch (op) {
1570 case DLADM_WLAN_MLME_ASSOC:
1571 mlme.im_op = IEEE80211_MLME_ASSOC;
1572 break;
1573 case DLADM_WLAN_MLME_DISASSOC:
1574 mlme.im_op = IEEE80211_MLME_DISASSOC;
1575 break;
1576 default:
1577 return (DLADM_STATUS_BADARG);
1579 mlme.im_reason = reason;
1580 if (bssid != NULL)
1581 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
1582 DLADM_WLAN_BSSID_LEN);
1584 return (i_dladm_wlan_param(handle, linkid, &mlme, MAC_PROP_WL_MLME,
1585 sizeof (mlme), B_TRUE));
1589 * routines of create instance
1591 static scf_propertygroup_t *
1592 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
1593 const char *pg_name, const char *pg_type)
1595 scf_propertygroup_t *pg;
1597 pg = scf_pg_create(handle);
1598 if (pg == NULL)
1599 return (NULL);
1601 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
1602 scf_pg_destroy(pg);
1603 return (NULL);
1606 return (pg);
1609 static dladm_status_t
1610 add_new_property(scf_handle_t *handle, const char *prop_name,
1611 scf_type_t type, const char *val, scf_transaction_t *tx)
1613 scf_value_t *value = NULL;
1614 scf_transaction_entry_t *entry = NULL;
1616 entry = scf_entry_create(handle);
1617 if (entry == NULL)
1618 goto out;
1620 value = scf_value_create(handle);
1621 if (value == NULL)
1622 goto out;
1624 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
1625 goto out;
1627 if (scf_value_set_from_string(value, type, val) != 0)
1628 goto out;
1630 if (scf_entry_add_value(entry, value) != 0)
1631 goto out;
1633 return (DLADM_STATUS_OK);
1635 out:
1636 if (value != NULL)
1637 scf_value_destroy(value);
1638 if (entry != NULL)
1639 scf_entry_destroy(entry);
1641 return (DLADM_STATUS_FAILED);
1644 static dladm_status_t
1645 add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
1646 const char *pg_name, const char *flags)
1648 int rv, size;
1649 dladm_status_t status = DLADM_STATUS_FAILED;
1650 char *command = NULL;
1651 scf_transaction_t *tran = NULL;
1652 scf_propertygroup_t *pg;
1654 pg = add_property_group_to_instance(handle, instance,
1655 pg_name, SCF_GROUP_METHOD);
1656 if (pg == NULL)
1657 goto out;
1659 tran = scf_transaction_create(handle);
1660 if (tran == NULL)
1661 goto out;
1663 size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1;
1664 command = malloc(size);
1665 if (command == NULL) {
1666 status = DLADM_STATUS_NOMEM;
1667 goto out;
1669 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
1671 do {
1672 if (scf_transaction_start(tran, pg) != 0)
1673 goto out;
1675 if (add_new_property(handle, SCF_PROPERTY_EXEC,
1676 SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
1677 goto out;
1680 rv = scf_transaction_commit(tran);
1681 switch (rv) {
1682 case 1:
1683 status = DLADM_STATUS_OK;
1684 goto out;
1685 case 0:
1686 scf_transaction_destroy_children(tran);
1687 if (scf_pg_update(pg) == -1) {
1688 goto out;
1690 break;
1691 case -1:
1692 default:
1693 goto out;
1695 } while (rv == 0);
1697 out:
1698 if (tran != NULL) {
1699 scf_transaction_destroy_children(tran);
1700 scf_transaction_destroy(tran);
1703 if (pg != NULL)
1704 scf_pg_destroy(pg);
1706 if (command != NULL)
1707 free(command);
1709 return (status);
1712 static dladm_status_t
1713 do_create_instance(scf_handle_t *handle, scf_service_t *svc,
1714 const char *instance_name, const char *command)
1716 dladm_status_t status = DLADM_STATUS_FAILED;
1717 char *buf;
1718 ssize_t max_fmri_len;
1719 scf_instance_t *instance;
1721 instance = scf_instance_create(handle);
1722 if (instance == NULL)
1723 goto out;
1725 if (scf_service_add_instance(svc, instance_name, instance) != 0) {
1726 if (scf_error() == SCF_ERROR_EXISTS)
1727 /* Let the caller deal with the duplicate instance */
1728 status = DLADM_STATUS_EXIST;
1729 goto out;
1732 if (add_pg_method(handle, instance, "start",
1733 command) != DLADM_STATUS_OK) {
1734 goto out;
1737 /* enabling the instance */
1738 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1739 if ((buf = malloc(max_fmri_len + 1)) == NULL)
1740 goto out;
1742 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1743 if ((smf_disable_instance(buf, 0) != 0) ||
1744 (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
1745 goto out;
1747 status = DLADM_STATUS_OK;
1750 out:
1751 if (instance != NULL)
1752 scf_instance_destroy(instance);
1753 return (status);
1756 static dladm_status_t
1757 create_instance(const char *instance_name, const char *command)
1759 dladm_status_t status = DLADM_STATUS_FAILED;
1760 scf_service_t *svc = NULL;
1761 scf_handle_t *handle = NULL;
1763 handle = scf_handle_create(SCF_VERSION);
1764 if (handle == NULL)
1765 goto out;
1767 if (scf_handle_bind(handle) == -1)
1768 goto out;
1770 if ((svc = scf_service_create(handle)) == NULL)
1771 goto out;
1773 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
1774 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
1775 goto out;
1777 status = do_create_instance(handle, svc, instance_name, command);
1779 out:
1780 if (svc != NULL)
1781 scf_service_destroy(svc);
1783 if (handle != NULL) {
1784 (void) scf_handle_unbind(handle);
1785 scf_handle_destroy(handle);
1788 return (status);
1792 * routines of delete instance
1794 #define DEFAULT_TIMEOUT 60000000
1795 #define INIT_WAIT_USECS 50000
1797 static void
1798 wait_until_disabled(scf_handle_t *handle, char *fmri)
1800 char *state;
1801 useconds_t max;
1802 useconds_t usecs;
1803 uint64_t *cp = NULL;
1804 scf_simple_prop_t *sp = NULL;
1806 max = DEFAULT_TIMEOUT;
1808 if (((sp = scf_simple_prop_get(handle, fmri, "stop",
1809 SCF_PROPERTY_TIMEOUT)) != NULL) &&
1810 ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
1811 max = (*cp) * 1000000; /* convert to usecs */
1813 if (sp != NULL)
1814 scf_simple_prop_free(sp);
1816 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
1817 /* incremental wait */
1818 usecs *= 2;
1819 usecs = (usecs > max) ? max : usecs;
1821 (void) usleep(usecs);
1823 /* Check state after the wait */
1824 if ((state = smf_get_state(fmri)) != NULL) {
1825 if (strcmp(state, "disabled") == 0)
1826 return;
1831 static dladm_status_t
1832 delete_instance(const char *instance_name)
1834 dladm_status_t status = DLADM_STATUS_FAILED;
1835 char *buf;
1836 ssize_t max_fmri_len;
1837 scf_scope_t *scope = NULL;
1838 scf_service_t *svc = NULL;
1839 scf_handle_t *handle = NULL;
1840 scf_instance_t *instance;
1842 handle = scf_handle_create(SCF_VERSION);
1843 if (handle == NULL)
1844 goto out;
1846 if (scf_handle_bind(handle) == -1)
1847 goto out;
1849 if ((scope = scf_scope_create(handle)) == NULL)
1850 goto out;
1852 if ((svc = scf_service_create(handle)) == NULL)
1853 goto out;
1855 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
1856 goto out;
1858 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
1859 goto out;
1861 instance = scf_instance_create(handle);
1862 if (instance == NULL)
1863 goto out;
1865 if (scf_service_get_instance(svc, instance_name, instance) != 0) {
1866 scf_error_t scf_errnum = scf_error();
1868 if (scf_errnum == SCF_ERROR_NOT_FOUND)
1869 status = DLADM_STATUS_OK;
1871 scf_instance_destroy(instance);
1872 goto out;
1875 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1876 if ((buf = malloc(max_fmri_len + 1)) == NULL) {
1877 scf_instance_destroy(instance);
1878 goto out;
1881 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1882 char *state;
1884 state = smf_get_state(buf);
1885 if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
1886 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
1887 if (smf_disable_instance(buf, 0) == 0) {
1889 * Wait for some time till timeout to avoid
1890 * a race with scf_instance_delete() below.
1892 wait_until_disabled(handle, buf);
1897 if (scf_instance_delete(instance) != 0) {
1898 scf_instance_destroy(instance);
1899 goto out;
1902 scf_instance_destroy(instance);
1904 status = DLADM_STATUS_OK;
1906 out:
1907 if (svc != NULL)
1908 scf_service_destroy(svc);
1910 if (scope != NULL)
1911 scf_scope_destroy(scope);
1913 if (handle != NULL) {
1914 (void) scf_handle_unbind(handle);
1915 scf_handle_destroy(handle);
1918 return (status);
1921 static dladm_status_t
1922 wpa_instance_create(dladm_handle_t handle, datalink_id_t linkid, void *key)
1924 dladm_status_t status = DLADM_STATUS_FAILED;
1925 char *command = NULL;
1926 char *wk_name = ((dladm_wlan_key_t *)key)->wk_name;
1927 int size;
1928 char instance_name[MAXLINKNAMELEN];
1931 * Use the link name as the instance name of the network/wpad service.
1933 status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
1934 instance_name, sizeof (instance_name));
1935 if (status != DLADM_STATUS_OK)
1936 goto out;
1938 size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1;
1939 command = malloc(size);
1940 if (command == NULL) {
1941 status = DLADM_STATUS_NOMEM;
1942 goto out;
1944 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
1946 status = create_instance(instance_name, command);
1947 if (status == DLADM_STATUS_EXIST) {
1949 * Delete the existing instance and create a new instance
1950 * with the supplied arguments.
1952 if ((status = delete_instance(instance_name)) ==
1953 DLADM_STATUS_OK) {
1954 status = create_instance(instance_name, command);
1958 out:
1959 if (command != NULL)
1960 free(command);
1962 return (status);
1965 static dladm_status_t
1966 wpa_instance_delete(dladm_handle_t handle, datalink_id_t linkid)
1968 char instance_name[MAXLINKNAMELEN];
1971 * Get the instance name of the network/wpad service (the same as
1972 * the link name).
1974 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
1975 instance_name, sizeof (instance_name)) != DLADM_STATUS_OK)
1976 return (DLADM_STATUS_FAILED);
1978 return (delete_instance(instance_name));