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