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 (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 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;
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 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;
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, r = 0;
793
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];
797 }
798 wl_attrp->wa_speed = r;
799 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
800 }
801
802 if ((status = do_get_authmode(handle, linkid, &authmode,
803 sizeof (authmode))) != DLADM_STATUS_OK)
804 goto done;
805
806 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
807
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;
818 }
819
820 if ((status = do_get_bsstype(handle, linkid, &bsstype,
821 sizeof (bsstype))) != DLADM_STATUS_OK)
822 goto done;
823
824 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
825
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;
839 }
840
841 if ((status = do_get_mode(handle, linkid, &wl_phy_conf,
842 sizeof (wl_phy_conf))) != DLADM_STATUS_OK)
843 goto done;
844
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;
849
850 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
851 status = DLADM_STATUS_OK;
852
853 done:
854 free(ratesp);
855 return (status);
856 }
857
858 /*
859 * Check to see if the link is wireless.
860 */
861 static dladm_status_t
dladm_wlan_validate(dladm_handle_t handle,datalink_id_t linkid)862 dladm_wlan_validate(dladm_handle_t handle, datalink_id_t linkid)
863 {
864 uint32_t media;
865 dladm_status_t status;
866
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;
872 }
873 return (status);
874 }
875
876 static boolean_t
find_val_by_name(const char * str,val_desc_t * vdp,uint_t cnt,uint_t * valp)877 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
878 {
879 int i;
880
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);
885 }
886 }
887 return (B_FALSE);
888 }
889
890 static boolean_t
find_name_by_val(uint_t val,val_desc_t * vdp,uint_t cnt,char ** strp)891 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
892 {
893 int i;
894
895 for (i = 0; i < cnt; i++) {
896 if (val == vdp[i].vd_val) {
897 *strp = vdp[i].vd_name;
898 return (B_TRUE);
899 }
900 }
901 return (B_FALSE);
902 }
903
904 const char *
dladm_wlan_essid2str(dladm_wlan_essid_t * essid,char * buf)905 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
906 {
907 (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
908 return (buf);
909 }
910
911 const char *
dladm_wlan_bssid2str(dladm_wlan_bssid_t * bssid,char * buf)912 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
913 {
914 return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
915 IFT_OTHER));
916 }
917
918 static const char *
dladm_wlan_val2str(uint_t val,val_desc_t * vdp,uint_t cnt,char * buf)919 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
920 {
921 char *s;
922
923 if (!find_name_by_val(val, vdp, cnt, &s))
924 s = "";
925
926 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
927 return (buf);
928 }
929
930 const char *
dladm_wlan_secmode2str(dladm_wlan_secmode_t * secmode,char * buf)931 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
932 {
933 return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
934 VALCNT(secmode_vals), buf));
935 }
936
937 const char *
dladm_wlan_strength2str(dladm_wlan_strength_t * strength,char * buf)938 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
939 {
940 return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
941 VALCNT(strength_vals), buf));
942 }
943
944 const char *
dladm_wlan_mode2str(dladm_wlan_mode_t * mode,char * buf)945 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
946 {
947 return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
948 VALCNT(mode_vals), buf));
949 }
950
951 const char *
dladm_wlan_speed2str(dladm_wlan_speed_t * speed,char * buf)952 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
953 {
954 (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
955 (float)(*speed) / 2);
956 return (buf);
957 }
958
959 const char *
dladm_wlan_auth2str(dladm_wlan_auth_t * auth,char * buf)960 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
961 {
962 return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
963 VALCNT(auth_vals), buf));
964 }
965
966 const char *
dladm_wlan_bsstype2str(dladm_wlan_bsstype_t * bsstype,char * buf)967 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
968 {
969 return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
970 VALCNT(bsstype_vals), buf));
971 }
972
973 const char *
dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t * linkstatus,char * buf)974 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
975 {
976 return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
977 VALCNT(linkstatus_vals), buf));
978 }
979
980 dladm_status_t
dladm_wlan_str2essid(const char * str,dladm_wlan_essid_t * essid)981 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
982 {
983 if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1)
984 return (DLADM_STATUS_BADARG);
985
986 (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
987 return (DLADM_STATUS_OK);
988 }
989
990 dladm_status_t
dladm_wlan_str2bssid(const char * str,dladm_wlan_bssid_t * bssid)991 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
992 {
993 int len;
994 uchar_t *buf;
995
996 buf = _link_aton(str, &len);
997 if (buf == NULL)
998 return (DLADM_STATUS_BADARG);
999
1000 if (len != DLADM_WLAN_BSSID_LEN) {
1001 free(buf);
1002 return (DLADM_STATUS_BADARG);
1003 }
1004
1005 (void) memcpy(bssid->wb_bytes, buf, len);
1006 free(buf);
1007 return (DLADM_STATUS_OK);
1008 }
1009
1010 dladm_status_t
dladm_wlan_str2secmode(const char * str,dladm_wlan_secmode_t * secmode)1011 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode)
1012 {
1013 uint_t val;
1014
1015 if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
1016 return (DLADM_STATUS_BADARG);
1017
1018 *secmode = (dladm_wlan_secmode_t)val;
1019 return (DLADM_STATUS_OK);
1020 }
1021
1022 dladm_status_t
dladm_wlan_str2strength(const char * str,dladm_wlan_strength_t * strength)1023 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
1024 {
1025 uint_t val;
1026
1027 if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
1028 return (DLADM_STATUS_BADARG);
1029
1030 *strength = (dladm_wlan_strength_t)val;
1031 return (DLADM_STATUS_OK);
1032 }
1033
1034 dladm_status_t
dladm_wlan_str2mode(const char * str,dladm_wlan_mode_t * mode)1035 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
1036 {
1037 uint_t val;
1038
1039 if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
1040 return (DLADM_STATUS_BADARG);
1041
1042 *mode = (dladm_wlan_mode_t)val;
1043 return (DLADM_STATUS_OK);
1044 }
1045
1046 dladm_status_t
dladm_wlan_str2speed(const char * str,dladm_wlan_speed_t * speed)1047 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
1048 {
1049 *speed = (dladm_wlan_speed_t)(atof(str) * 2);
1050 return (DLADM_STATUS_OK);
1051 }
1052
1053 dladm_status_t
dladm_wlan_str2auth(const char * str,dladm_wlan_auth_t * auth)1054 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
1055 {
1056 uint_t val;
1057
1058 if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
1059 return (DLADM_STATUS_BADARG);
1060
1061 *auth = (dladm_wlan_auth_t)val;
1062 return (DLADM_STATUS_OK);
1063 }
1064
1065 dladm_status_t
dladm_wlan_str2bsstype(const char * str,dladm_wlan_bsstype_t * bsstype)1066 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
1067 {
1068 uint_t val;
1069
1070 if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
1071 return (DLADM_STATUS_BADARG);
1072
1073 *bsstype = (dladm_wlan_bsstype_t)val;
1074 return (DLADM_STATUS_OK);
1075 }
1076
1077 dladm_status_t
dladm_wlan_str2linkstatus(const char * str,dladm_wlan_linkstatus_t * linkstatus)1078 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
1079 {
1080 uint_t val;
1081
1082 if (!find_val_by_name(str, linkstatus_vals,
1083 VALCNT(linkstatus_vals), &val)) {
1084 return (DLADM_STATUS_BADARG);
1085 }
1086
1087 *linkstatus = (dladm_wlan_linkstatus_t)val;
1088 return (DLADM_STATUS_OK);
1089 }
1090
1091 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)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)
1094 {
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];
1102
1103 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
1104 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1105 return (status);
1106 }
1107
1108 if (media != DL_WIFI)
1109 return (DLADM_STATUS_BADARG);
1110
1111 if (!(flags & DLADM_OPT_ACTIVE))
1112 return (DLADM_STATUS_TEMPONLY);
1113
1114 /*
1115 * dlpi_open() is not used here because libdlpi depends on libdladm,
1116 * and we do not want to introduce recursive dependencies.
1117 */
1118 (void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
1119 if ((fd = open(linkname, O_RDWR)) < 0)
1120 return (dladm_errno2status(errno));
1121
1122 gbuf->wldp_type = NET_802_11;
1123 gbuf->wldp_id = id;
1124 gbuf->wldp_length = len;
1125
1126 stri.ic_timout = 0;
1127 stri.ic_dp = (char *)gbuf;
1128 stri.ic_cmd = cmd;
1129 stri.ic_len = cmdlen;
1130
1131 if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
1132 if (rc > 0) {
1133 /*
1134 * Non-negative return value indicates the specific
1135 * operation failed and the reason for the failure
1136 * was stored in gbuf->wldp_result.
1137 */
1138 status = dladm_wlan_wlresult2status(gbuf);
1139 } else {
1140 /*
1141 * Negative return value indicates the ioctl failed.
1142 */
1143 status = dladm_errno2status(errno);
1144 }
1145 }
1146 (void) close(fd);
1147 return (status);
1148 }
1149
1150 static dladm_status_t
do_cmd_ioctl(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen,uint_t cmd)1151 do_cmd_ioctl(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1152 int buflen, uint_t cmd)
1153 {
1154 wldp_t *gbuf;
1155 dladm_status_t status = DLADM_STATUS_OK;
1156
1157 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1158 return (DLADM_STATUS_NOMEM);
1159
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);
1166 }
1167
1168 static dladm_status_t
do_scan(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1169 do_scan(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1170 {
1171 return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_SCAN));
1172 }
1173
1174 static dladm_status_t
do_disconnect(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1175 do_disconnect(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1176 int buflen)
1177 {
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);
1181
1182 return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_DISASSOCIATE));
1183 }
1184
1185 static dladm_status_t
do_get_esslist(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1186 do_get_esslist(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1187 int buflen)
1188 {
1189 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESS_LIST,
1190 buflen, B_FALSE));
1191 }
1192
1193 static dladm_status_t
do_get_bssid(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1194 do_get_bssid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1195 {
1196 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSID,
1197 buflen, B_FALSE));
1198 }
1199
1200 static dladm_status_t
do_get_essid(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1201 do_get_essid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1202 {
1203 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESSID,
1204 buflen, B_FALSE));
1205 }
1206
1207 static dladm_status_t
do_get_bsstype(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1208 do_get_bsstype(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1209 int buflen)
1210 {
1211 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSTYPE,
1212 buflen, B_FALSE));
1213 }
1214
1215 static dladm_status_t
do_get_linkstatus(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1216 do_get_linkstatus(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1217 int buflen)
1218 {
1219 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_LINKSTATUS,
1220 buflen, B_FALSE));
1221 }
1222
1223 static dladm_status_t
do_get_rate(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1224 do_get_rate(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1225 {
1226 return (i_dladm_wlan_param(handle, linkid, buf,
1227 MAC_PROP_WL_DESIRED_RATES, buflen, B_FALSE));
1228 }
1229
1230 static dladm_status_t
do_get_authmode(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1231 do_get_authmode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1232 int buflen)
1233 {
1234 return (i_dladm_wlan_param(handle, linkid, buf,
1235 MAC_PROP_WL_AUTH_MODE, buflen, B_FALSE));
1236 }
1237
1238 static dladm_status_t
do_get_encryption(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1239 do_get_encryption(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1240 int buflen)
1241 {
1242 return (i_dladm_wlan_param(handle, linkid, buf,
1243 MAC_PROP_WL_ENCRYPTION, buflen, B_FALSE));
1244 }
1245
1246 static dladm_status_t
do_get_signal(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1247 do_get_signal(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1248 int buflen)
1249 {
1250 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RSSI,
1251 buflen, B_FALSE));
1252 }
1253
1254 static dladm_status_t
do_get_mode(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1255 do_get_mode(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1256 {
1257 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
1258 buflen, B_FALSE));
1259 }
1260
1261 static dladm_status_t
do_set_bsstype(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_bsstype_t * bsstype)1262 do_set_bsstype(dladm_handle_t handle, datalink_id_t linkid,
1263 dladm_wlan_bsstype_t *bsstype)
1264 {
1265 wl_bss_type_t ibsstype;
1266
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;
1277 }
1278 return (i_dladm_wlan_param(handle, linkid, &ibsstype,
1279 MAC_PROP_WL_BSSTYPE, sizeof (ibsstype), B_TRUE));
1280 }
1281
1282 static dladm_status_t
do_set_authmode(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_auth_t * auth)1283 do_set_authmode(dladm_handle_t handle, datalink_id_t linkid,
1284 dladm_wlan_auth_t *auth)
1285 {
1286 wl_authmode_t auth_mode;
1287
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);
1297 }
1298 return (i_dladm_wlan_param(handle, linkid, &auth_mode,
1299 MAC_PROP_WL_AUTH_MODE, sizeof (auth_mode), B_TRUE));
1300 }
1301
1302 static dladm_status_t
do_set_encryption(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_secmode_t * secmode)1303 do_set_encryption(dladm_handle_t handle, datalink_id_t linkid,
1304 dladm_wlan_secmode_t *secmode)
1305 {
1306 wl_encryption_t encryption;
1307
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);
1319 }
1320 return (i_dladm_wlan_param(handle, linkid, &encryption,
1321 MAC_PROP_WL_ENCRYPTION, sizeof (encryption), B_TRUE));
1322 }
1323
1324 static dladm_status_t
do_set_key(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_key_t * keys,uint_t key_count)1325 do_set_key(dladm_handle_t handle, datalink_id_t linkid, dladm_wlan_key_t *keys,
1326 uint_t key_count)
1327 {
1328 int i;
1329 wl_wep_key_t *wkp;
1330 wl_wep_key_tab_t wepkey_tab;
1331 dladm_wlan_key_t *kp;
1332
1333 if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
1334 return (DLADM_STATUS_BADARG);
1335
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;
1339
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);
1347
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);
1352 }
1353
1354 return (i_dladm_wlan_param(handle, linkid, &wepkey_tab,
1355 MAC_PROP_WL_KEY_TAB, sizeof (wepkey_tab), B_TRUE));
1356 }
1357
1358 static dladm_status_t
do_set_essid(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_essid_t * essid)1359 do_set_essid(dladm_handle_t handle, datalink_id_t linkid,
1360 dladm_wlan_essid_t *essid)
1361 {
1362 wl_essid_t iessid;
1363
1364 (void) memset(&iessid, 0, sizeof (essid));
1365
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);
1372 }
1373 return (i_dladm_wlan_param(handle, linkid, &iessid, MAC_PROP_WL_ESSID,
1374 sizeof (iessid), B_TRUE));
1375 }
1376
1377 static dladm_status_t
do_set_channel(dladm_handle_t handle,datalink_id_t linkid,dladm_wlan_channel_t * channel)1378 do_set_channel(dladm_handle_t handle, datalink_id_t linkid,
1379 dladm_wlan_channel_t *channel)
1380 {
1381 wl_phy_conf_t phy_conf;
1382
1383 if (*channel > MAX_CHANNEL_NUM)
1384 return (DLADM_STATUS_BADVAL);
1385
1386 (void) memset(&phy_conf, 0xff, sizeof (phy_conf));
1387 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
1388
1389 return (i_dladm_wlan_param(handle, linkid, &phy_conf,
1390 MAC_PROP_WL_PHY_CONFIG, sizeof (phy_conf), B_TRUE));
1391 }
1392
1393 static dladm_status_t
do_set_createibss(dladm_handle_t handle,datalink_id_t linkid,boolean_t * create_ibss)1394 do_set_createibss(dladm_handle_t handle, datalink_id_t linkid,
1395 boolean_t *create_ibss)
1396 {
1397 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
1398
1399 return (i_dladm_wlan_param(handle, linkid, &cr, MAC_PROP_WL_CREATE_IBSS,
1400 sizeof (cr), B_TRUE));
1401 }
1402
1403 static void
generate_essid(dladm_wlan_essid_t * essid)1404 generate_essid(dladm_wlan_essid_t *essid)
1405 {
1406 srandom(gethrtime());
1407 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
1408 random());
1409 }
1410
1411 static dladm_status_t
do_get_capability(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1412 do_get_capability(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1413 int buflen)
1414 {
1415 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_CAPABILITY,
1416 buflen, B_FALSE));
1417 }
1418
1419 static dladm_status_t
do_get_wpamode(dladm_handle_t handle,datalink_id_t linkid,void * buf,int buflen)1420 do_get_wpamode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1421 int buflen)
1422 {
1423 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_WPA, buflen,
1424 B_FALSE));
1425 }
1426
1427 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)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)
1430 {
1431 int i, n;
1432 wl_wpa_ess_t *es;
1433 dladm_status_t status;
1434
1435 es = malloc(WLDP_BUFSIZE);
1436 if (es == NULL)
1437 return (DLADM_STATUS_NOMEM);
1438
1439 status = i_dladm_wlan_param(handle, linkid, es, MAC_PROP_WL_SCANRESULTS,
1440 WLDP_BUFSIZE, B_FALSE);
1441
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;
1454 }
1455 *estot = n;
1456 }
1457
1458 free(es);
1459 return (status);
1460 }
1461
1462 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)1463 dladm_wlan_wpa_set_ie(dladm_handle_t handle, datalink_id_t linkid,
1464 uint8_t *wpa_ie, uint_t wpa_ie_len)
1465 {
1466 wl_wpa_ie_t *ie;
1467 uint_t len;
1468 dladm_status_t status;
1469
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);
1476
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);
1480
1481 status = i_dladm_wlan_param(handle, linkid, ie, MAC_PROP_WL_SETOPTIE,
1482 len, B_TRUE);
1483 free(ie);
1484
1485 return (status);
1486 }
1487
1488 dladm_status_t
dladm_wlan_wpa_set_wpa(dladm_handle_t handle,datalink_id_t linkid,boolean_t flag)1489 dladm_wlan_wpa_set_wpa(dladm_handle_t handle, datalink_id_t linkid,
1490 boolean_t flag)
1491 {
1492 wl_wpa_t wpa;
1493
1494 wpa.wpa_flag = flag;
1495 return (i_dladm_wlan_param(handle, linkid, &wpa, MAC_PROP_WL_WPA,
1496 sizeof (wpa), B_TRUE));
1497 }
1498
1499 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)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)
1502 {
1503 wl_del_key_t wk;
1504
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);
1509
1510 return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_DELKEY,
1511 sizeof (wk), B_TRUE));
1512 }
1513
1514 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)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)
1519 {
1520 wl_key_t wk;
1521
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);
1544 }
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);
1556
1557 return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_KEY,
1558 sizeof (wk), B_TRUE));
1559 }
1560
1561 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)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)
1565 {
1566 wl_mlme_t mlme;
1567
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);
1578 }
1579 mlme.im_reason = reason;
1580 if (bssid != NULL)
1581 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
1582 DLADM_WLAN_BSSID_LEN);
1583
1584 return (i_dladm_wlan_param(handle, linkid, &mlme, MAC_PROP_WL_MLME,
1585 sizeof (mlme), B_TRUE));
1586 }
1587
1588 /*
1589 * routines of create instance
1590 */
1591 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)1592 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
1593 const char *pg_name, const char *pg_type)
1594 {
1595 scf_propertygroup_t *pg;
1596
1597 pg = scf_pg_create(handle);
1598 if (pg == NULL)
1599 return (NULL);
1600
1601 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
1602 scf_pg_destroy(pg);
1603 return (NULL);
1604 }
1605
1606 return (pg);
1607 }
1608
1609 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)1610 add_new_property(scf_handle_t *handle, const char *prop_name,
1611 scf_type_t type, const char *val, scf_transaction_t *tx)
1612 {
1613 scf_value_t *value = NULL;
1614 scf_transaction_entry_t *entry = NULL;
1615
1616 entry = scf_entry_create(handle);
1617 if (entry == NULL)
1618 goto out;
1619
1620 value = scf_value_create(handle);
1621 if (value == NULL)
1622 goto out;
1623
1624 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
1625 goto out;
1626
1627 if (scf_value_set_from_string(value, type, val) != 0)
1628 goto out;
1629
1630 if (scf_entry_add_value(entry, value) != 0)
1631 goto out;
1632
1633 return (DLADM_STATUS_OK);
1634
1635 out:
1636 if (value != NULL)
1637 scf_value_destroy(value);
1638 if (entry != NULL)
1639 scf_entry_destroy(entry);
1640
1641 return (DLADM_STATUS_FAILED);
1642 }
1643
1644 static dladm_status_t
add_pg_method(scf_handle_t * handle,scf_instance_t * instance,const char * pg_name,const char * flags)1645 add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
1646 const char *pg_name, const char *flags)
1647 {
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;
1653
1654 pg = add_property_group_to_instance(handle, instance,
1655 pg_name, SCF_GROUP_METHOD);
1656 if (pg == NULL)
1657 goto out;
1658
1659 tran = scf_transaction_create(handle);
1660 if (tran == NULL)
1661 goto out;
1662
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;
1668 }
1669 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
1670
1671 do {
1672 if (scf_transaction_start(tran, pg) != 0)
1673 goto out;
1674
1675 if (add_new_property(handle, SCF_PROPERTY_EXEC,
1676 SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
1677 goto out;
1678 }
1679
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;
1689 }
1690 break;
1691 case -1:
1692 default:
1693 goto out;
1694 }
1695 } while (rv == 0);
1696
1697 out:
1698 if (tran != NULL) {
1699 scf_transaction_destroy_children(tran);
1700 scf_transaction_destroy(tran);
1701 }
1702
1703 if (pg != NULL)
1704 scf_pg_destroy(pg);
1705
1706 if (command != NULL)
1707 free(command);
1708
1709 return (status);
1710 }
1711
1712 static dladm_status_t
do_create_instance(scf_handle_t * handle,scf_service_t * svc,const char * instance_name,const char * command)1713 do_create_instance(scf_handle_t *handle, scf_service_t *svc,
1714 const char *instance_name, const char *command)
1715 {
1716 dladm_status_t status = DLADM_STATUS_FAILED;
1717 char *buf;
1718 ssize_t max_fmri_len;
1719 scf_instance_t *instance;
1720
1721 instance = scf_instance_create(handle);
1722 if (instance == NULL)
1723 goto out;
1724
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;
1730 }
1731
1732 if (add_pg_method(handle, instance, "start",
1733 command) != DLADM_STATUS_OK) {
1734 goto out;
1735 }
1736
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;
1741
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;
1746 }
1747 status = DLADM_STATUS_OK;
1748 }
1749
1750 out:
1751 if (instance != NULL)
1752 scf_instance_destroy(instance);
1753 return (status);
1754 }
1755
1756 static dladm_status_t
create_instance(const char * instance_name,const char * command)1757 create_instance(const char *instance_name, const char *command)
1758 {
1759 dladm_status_t status = DLADM_STATUS_FAILED;
1760 scf_service_t *svc = NULL;
1761 scf_handle_t *handle = NULL;
1762
1763 handle = scf_handle_create(SCF_VERSION);
1764 if (handle == NULL)
1765 goto out;
1766
1767 if (scf_handle_bind(handle) == -1)
1768 goto out;
1769
1770 if ((svc = scf_service_create(handle)) == NULL)
1771 goto out;
1772
1773 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
1774 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
1775 goto out;
1776
1777 status = do_create_instance(handle, svc, instance_name, command);
1778
1779 out:
1780 if (svc != NULL)
1781 scf_service_destroy(svc);
1782
1783 if (handle != NULL) {
1784 (void) scf_handle_unbind(handle);
1785 scf_handle_destroy(handle);
1786 }
1787
1788 return (status);
1789 }
1790
1791 /*
1792 * routines of delete instance
1793 */
1794 #define DEFAULT_TIMEOUT 60000000
1795 #define INIT_WAIT_USECS 50000
1796
1797 static void
wait_until_disabled(scf_handle_t * handle,char * fmri)1798 wait_until_disabled(scf_handle_t *handle, char *fmri)
1799 {
1800 char *state;
1801 useconds_t max;
1802 useconds_t usecs;
1803 uint64_t *cp = NULL;
1804 scf_simple_prop_t *sp = NULL;
1805
1806 max = DEFAULT_TIMEOUT;
1807
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 */
1812
1813 if (sp != NULL)
1814 scf_simple_prop_free(sp);
1815
1816 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
1817 /* incremental wait */
1818 usecs *= 2;
1819 usecs = (usecs > max) ? max : usecs;
1820
1821 (void) usleep(usecs);
1822
1823 /* Check state after the wait */
1824 if ((state = smf_get_state(fmri)) != NULL) {
1825 if (strcmp(state, "disabled") == 0)
1826 return;
1827 }
1828 }
1829 }
1830
1831 static dladm_status_t
delete_instance(const char * instance_name)1832 delete_instance(const char *instance_name)
1833 {
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;
1841
1842 handle = scf_handle_create(SCF_VERSION);
1843 if (handle == NULL)
1844 goto out;
1845
1846 if (scf_handle_bind(handle) == -1)
1847 goto out;
1848
1849 if ((scope = scf_scope_create(handle)) == NULL)
1850 goto out;
1851
1852 if ((svc = scf_service_create(handle)) == NULL)
1853 goto out;
1854
1855 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
1856 goto out;
1857
1858 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
1859 goto out;
1860
1861 instance = scf_instance_create(handle);
1862 if (instance == NULL)
1863 goto out;
1864
1865 if (scf_service_get_instance(svc, instance_name, instance) != 0) {
1866 scf_error_t scf_errnum = scf_error();
1867
1868 if (scf_errnum == SCF_ERROR_NOT_FOUND)
1869 status = DLADM_STATUS_OK;
1870
1871 scf_instance_destroy(instance);
1872 goto out;
1873 }
1874
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;
1879 }
1880
1881 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
1882 char *state;
1883
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) {
1888 /*
1889 * Wait for some time till timeout to avoid
1890 * a race with scf_instance_delete() below.
1891 */
1892 wait_until_disabled(handle, buf);
1893 }
1894 }
1895 }
1896
1897 if (scf_instance_delete(instance) != 0) {
1898 scf_instance_destroy(instance);
1899 goto out;
1900 }
1901
1902 scf_instance_destroy(instance);
1903
1904 status = DLADM_STATUS_OK;
1905
1906 out:
1907 if (svc != NULL)
1908 scf_service_destroy(svc);
1909
1910 if (scope != NULL)
1911 scf_scope_destroy(scope);
1912
1913 if (handle != NULL) {
1914 (void) scf_handle_unbind(handle);
1915 scf_handle_destroy(handle);
1916 }
1917
1918 return (status);
1919 }
1920
1921 static dladm_status_t
wpa_instance_create(dladm_handle_t handle,datalink_id_t linkid,void * key)1922 wpa_instance_create(dladm_handle_t handle, datalink_id_t linkid, void *key)
1923 {
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];
1929
1930 /*
1931 * Use the link name as the instance name of the network/wpad service.
1932 */
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;
1937
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;
1943 }
1944 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
1945
1946 status = create_instance(instance_name, command);
1947 if (status == DLADM_STATUS_EXIST) {
1948 /*
1949 * Delete the existing instance and create a new instance
1950 * with the supplied arguments.
1951 */
1952 if ((status = delete_instance(instance_name)) ==
1953 DLADM_STATUS_OK) {
1954 status = create_instance(instance_name, command);
1955 }
1956 }
1957
1958 out:
1959 if (command != NULL)
1960 free(command);
1961
1962 return (status);
1963 }
1964
1965 static dladm_status_t
wpa_instance_delete(dladm_handle_t handle,datalink_id_t linkid)1966 wpa_instance_delete(dladm_handle_t handle, datalink_id_t linkid)
1967 {
1968 char instance_name[MAXLINKNAMELEN];
1969
1970 /*
1971 * Get the instance name of the network/wpad service (the same as
1972 * the link name).
1973 */
1974 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
1975 instance_name, sizeof (instance_name)) != DLADM_STATUS_OK)
1976 return (DLADM_STATUS_FAILED);
1977
1978 return (delete_instance(instance_name));
1979 }
1980