13871Syz147064 /* 23871Syz147064 * CDDL HEADER START 33871Syz147064 * 43871Syz147064 * The contents of this file are subject to the terms of the 53871Syz147064 * Common Development and Distribution License (the "License"). 63871Syz147064 * You may not use this file except in compliance with the License. 73871Syz147064 * 83871Syz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93871Syz147064 * or http://www.opensolaris.org/os/licensing. 103871Syz147064 * See the License for the specific language governing permissions 113871Syz147064 * and limitations under the License. 123871Syz147064 * 133871Syz147064 * When distributing Covered Code, include this CDDL HEADER in each 143871Syz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153871Syz147064 * If applicable, add the following below this CDDL HEADER, with the 163871Syz147064 * fields enclosed by brackets "[]" replaced with your own identifying 173871Syz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 183871Syz147064 * 193871Syz147064 * CDDL HEADER END 203871Syz147064 */ 213871Syz147064 /* 223871Syz147064 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233871Syz147064 * Use is subject to license terms. 243871Syz147064 */ 253871Syz147064 263871Syz147064 #pragma ident "%Z%%M% %I% %E% SMI" 273871Syz147064 283871Syz147064 #include <libintl.h> 293871Syz147064 #include <stdio.h> 303871Syz147064 #include <stdlib.h> 313871Syz147064 #include <stddef.h> 323871Syz147064 #include <unistd.h> 333871Syz147064 #include <fcntl.h> 343871Syz147064 #include <string.h> 353871Syz147064 #include <stropts.h> 363871Syz147064 #include <libdevinfo.h> 373871Syz147064 #include <net/if.h> 383871Syz147064 #include <net/if_dl.h> 393871Syz147064 #include <net/if_types.h> 40*4126Szf162725 #include <libscf.h> 413871Syz147064 #include <libdlwlan.h> 423871Syz147064 #include <libdlwlan_impl.h> 43*4126Szf162725 #include <net/wpa.h> 443871Syz147064 453871Syz147064 typedef struct val_desc { 463871Syz147064 char *vd_name; 473871Syz147064 uint_t vd_val; 483871Syz147064 } val_desc_t; 493871Syz147064 503871Syz147064 struct prop_desc; 513871Syz147064 523871Syz147064 typedef dladm_status_t wl_pd_getf_t(int, wldp_t *, char **, uint_t *); 533871Syz147064 typedef dladm_status_t wl_pd_setf_t(int, wldp_t *, val_desc_t *, uint_t); 543871Syz147064 typedef dladm_status_t wl_pd_checkf_t(int, wldp_t *, struct prop_desc *, 553871Syz147064 char **, uint_t, val_desc_t **); 563871Syz147064 typedef struct prop_desc { 573871Syz147064 char *pd_name; 583871Syz147064 val_desc_t pd_defval; 593871Syz147064 val_desc_t *pd_modval; 603871Syz147064 uint_t pd_nmodval; 613871Syz147064 wl_pd_setf_t *pd_set; 623871Syz147064 wl_pd_getf_t *pd_getmod; 633871Syz147064 wl_pd_getf_t *pd_get; 643871Syz147064 wl_pd_checkf_t *pd_check; 653871Syz147064 } prop_desc_t; 663871Syz147064 67*4126Szf162725 static int wpa_instance_create(const char *, void *); 68*4126Szf162725 static int wpa_instance_delete(const char *); 69*4126Szf162725 703871Syz147064 static int do_get_bsstype(int, wldp_t *); 713871Syz147064 static int do_get_essid(int, wldp_t *); 723871Syz147064 static int do_get_bssid(int, wldp_t *); 733871Syz147064 static int do_get_signal(int, wldp_t *); 743871Syz147064 static int do_get_encryption(int, wldp_t *); 753871Syz147064 static int do_get_authmode(int, wldp_t *); 763871Syz147064 static int do_get_linkstatus(int, wldp_t *); 773871Syz147064 static int do_get_esslist(int, wldp_t *); 783871Syz147064 static int do_get_rate(int, wldp_t *); 793871Syz147064 static int do_get_phyconf(int, wldp_t *); 803871Syz147064 static int do_get_powermode(int, wldp_t *); 813871Syz147064 static int do_get_radio(int, wldp_t *); 823871Syz147064 static int do_get_mode(int, wldp_t *); 83*4126Szf162725 static int do_get_capability(int, wldp_t *); 84*4126Szf162725 static int do_get_wpamode(int, wldp_t *); 853871Syz147064 863871Syz147064 static int do_set_bsstype(int, wldp_t *, dladm_wlan_bsstype_t *); 873871Syz147064 static int do_set_authmode(int, wldp_t *, dladm_wlan_auth_t *); 883871Syz147064 static int do_set_encryption(int, wldp_t *, dladm_wlan_secmode_t *); 893871Syz147064 static int do_set_essid(int, wldp_t *, dladm_wlan_essid_t *); 903871Syz147064 static int do_set_createibss(int, wldp_t *, boolean_t *); 91*4126Szf162725 static int do_set_key(int, wldp_t *, dladm_wlan_key_t *, uint_t); 923871Syz147064 static int do_set_rate(int, wldp_t *, dladm_wlan_rates_t *); 933871Syz147064 static int do_set_powermode(int, wldp_t *, dladm_wlan_powermode_t *); 943871Syz147064 static int do_set_radio(int, wldp_t *, dladm_wlan_radio_t *); 953871Syz147064 static int do_set_channel(int, wldp_t *, dladm_wlan_channel_t *); 963871Syz147064 973871Syz147064 static int open_link(const char *); 983871Syz147064 static int do_scan(int, wldp_t *); 99*4126Szf162725 static int do_disconnect(const char *, int, wldp_t *); 1003871Syz147064 static boolean_t find_val_by_name(const char *, val_desc_t *, uint_t, uint_t *); 1013871Syz147064 static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); 1023871Syz147064 static void generate_essid(dladm_wlan_essid_t *); 1033871Syz147064 1043871Syz147064 static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); 1053871Syz147064 1063871Syz147064 static wl_pd_getf_t do_get_rate_mod, do_get_rate_prop, do_get_channel_prop, 1073871Syz147064 do_get_powermode_prop, do_get_radio_prop; 1083871Syz147064 static wl_pd_setf_t do_set_rate_prop, do_set_powermode_prop, 1093871Syz147064 do_set_radio_prop; 1103871Syz147064 static wl_pd_checkf_t do_check_prop, do_check_rate; 1113871Syz147064 1123871Syz147064 static val_desc_t linkstatus_vals[] = { 1133871Syz147064 { "disconnected", DLADM_WLAN_LINKSTATUS_DISCONNECTED }, 1143871Syz147064 { "connected", DLADM_WLAN_LINKSTATUS_CONNECTED } 1153871Syz147064 }; 1163871Syz147064 1173871Syz147064 static val_desc_t secmode_vals[] = { 1183871Syz147064 { "none", DLADM_WLAN_SECMODE_NONE }, 119*4126Szf162725 { "wep", DLADM_WLAN_SECMODE_WEP }, 120*4126Szf162725 { "wpa", DLADM_WLAN_SECMODE_WPA } 1213871Syz147064 }; 1223871Syz147064 1233871Syz147064 static val_desc_t strength_vals[] = { 1243871Syz147064 { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, 1253871Syz147064 { "weak", DLADM_WLAN_STRENGTH_WEAK }, 1263871Syz147064 { "good", DLADM_WLAN_STRENGTH_GOOD }, 1273871Syz147064 { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, 1283871Syz147064 { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } 1293871Syz147064 }; 1303871Syz147064 1313871Syz147064 static val_desc_t mode_vals[] = { 1323871Syz147064 { "a", DLADM_WLAN_MODE_80211A }, 1333871Syz147064 { "b", DLADM_WLAN_MODE_80211B }, 1343871Syz147064 { "g", DLADM_WLAN_MODE_80211G }, 1353871Syz147064 }; 1363871Syz147064 1373871Syz147064 static val_desc_t auth_vals[] = { 1383871Syz147064 { "open", DLADM_WLAN_AUTH_OPEN }, 1393871Syz147064 { "shared", DLADM_WLAN_AUTH_SHARED } 1403871Syz147064 }; 1413871Syz147064 1423871Syz147064 static val_desc_t bsstype_vals[] = { 1433871Syz147064 { "bss", DLADM_WLAN_BSSTYPE_BSS }, 1443871Syz147064 { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, 1453871Syz147064 { "any", DLADM_WLAN_BSSTYPE_ANY } 1463871Syz147064 }; 1473871Syz147064 1483871Syz147064 static val_desc_t radio_vals[] = { 1493871Syz147064 { "on", DLADM_WLAN_RADIO_ON }, 1503871Syz147064 { "off", DLADM_WLAN_RADIO_OFF } 1513871Syz147064 }; 1523871Syz147064 1533871Syz147064 static val_desc_t powermode_vals[] = { 1543871Syz147064 { "off", DLADM_WLAN_PM_OFF }, 1553871Syz147064 { "fast", DLADM_WLAN_PM_FAST }, 1563871Syz147064 { "max", DLADM_WLAN_PM_MAX } 1573871Syz147064 }; 1583871Syz147064 1593871Syz147064 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 1603871Syz147064 static prop_desc_t prop_table[] = { 1613871Syz147064 1623871Syz147064 { "channel", { NULL, 0 }, NULL, 0, 1633871Syz147064 NULL, NULL, do_get_channel_prop, do_check_prop}, 1643871Syz147064 1653871Syz147064 { "powermode", { "off", DLADM_WLAN_PM_OFF }, powermode_vals, 1663871Syz147064 VALCNT(powermode_vals), 1673871Syz147064 do_set_powermode_prop, NULL, 1683871Syz147064 do_get_powermode_prop, do_check_prop}, 1693871Syz147064 1703871Syz147064 { "radio", { "on", DLADM_WLAN_RADIO_ON }, radio_vals, 1713871Syz147064 VALCNT(radio_vals), 1723871Syz147064 do_set_radio_prop, NULL, 1733871Syz147064 do_get_radio_prop, do_check_prop}, 1743871Syz147064 1753871Syz147064 { "speed", { "", 0 }, NULL, 0, 1763871Syz147064 do_set_rate_prop, do_get_rate_mod, 1773871Syz147064 do_get_rate_prop, do_check_rate} 1783871Syz147064 }; 1793871Syz147064 /* 1803871Syz147064 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 1813871Syz147064 * rates to be retrieved. However, we cannot increase it at this 1823871Syz147064 * time because it will break binary comatibility with unbundled 1833871Syz147064 * WiFi drivers and utilities. So for now we define an additional 1843871Syz147064 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 1853871Syz147064 */ 1863871Syz147064 #define MAX_SUPPORT_RATES 64 1873871Syz147064 #define DLADM_WLAN_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 1883871Syz147064 #define IS_CONNECTED(gbuf) \ 1893871Syz147064 ((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED)) 1903871Syz147064 1913871Syz147064 static dladm_status_t 1923871Syz147064 dladm_wlan_wlresult2status(wldp_t *gbuf) 1933871Syz147064 { 1943871Syz147064 switch (gbuf->wldp_result) { 1953871Syz147064 case WL_SUCCESS: 1963871Syz147064 return (DLADM_STATUS_OK); 1973871Syz147064 1983871Syz147064 case WL_NOTSUPPORTED: 1993871Syz147064 case WL_LACK_FEATURE: 2003871Syz147064 return (DLADM_STATUS_NOTSUP); 2013871Syz147064 2023871Syz147064 case WL_READONLY: 2033871Syz147064 return (DLADM_STATUS_PROPRDONLY); 2043871Syz147064 2053871Syz147064 default: 2063871Syz147064 break; 2073871Syz147064 } 2083871Syz147064 2093871Syz147064 return (DLADM_STATUS_FAILED); 2103871Syz147064 } 2113871Syz147064 2123871Syz147064 static int 2133871Syz147064 open_link(const char *link) 2143871Syz147064 { 2153871Syz147064 char linkname[MAXPATHLEN]; 2163871Syz147064 wldp_t *gbuf; 2173871Syz147064 int fd; 2183871Syz147064 2193871Syz147064 if (link == NULL) 2203871Syz147064 return (-1); 2213871Syz147064 2223871Syz147064 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 2233871Syz147064 if ((fd = open(linkname, O_RDWR)) < 0) 2243871Syz147064 return (-1); 2253871Syz147064 2263871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 2273871Syz147064 (void) close(fd); 2283871Syz147064 return (-1); 2293871Syz147064 } 2303871Syz147064 2313871Syz147064 /* 2323871Syz147064 * Check to see if the link is wireless. 2333871Syz147064 */ 2343871Syz147064 if (do_get_bsstype(fd, gbuf) < 0) { 2353871Syz147064 free(gbuf); 2363871Syz147064 (void) close(fd); 2373871Syz147064 return (-1); 2383871Syz147064 } 2393871Syz147064 2403871Syz147064 free(gbuf); 2413871Syz147064 return (fd); 2423871Syz147064 } 2433871Syz147064 2443871Syz147064 static dladm_wlan_mode_t 2453871Syz147064 do_convert_mode(wl_phy_conf_t *phyp) 2463871Syz147064 { 2473871Syz147064 switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) { 2483871Syz147064 case WL_ERP: 2493871Syz147064 return (DLADM_WLAN_MODE_80211G); 2503871Syz147064 case WL_OFDM: 2513871Syz147064 return (DLADM_WLAN_MODE_80211A); 2523871Syz147064 case WL_DSSS: 2533871Syz147064 case WL_FHSS: 2543871Syz147064 return (DLADM_WLAN_MODE_80211B); 2553871Syz147064 default: 2563871Syz147064 break; 2573871Syz147064 } 2583871Syz147064 2593871Syz147064 return (DLADM_WLAN_MODE_NONE); 2603871Syz147064 } 2613871Syz147064 2623871Syz147064 static boolean_t 2633871Syz147064 do_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) 2643871Syz147064 { 2653871Syz147064 wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf; 2663871Syz147064 wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf; 2673871Syz147064 2683871Syz147064 switch (wlfp->wl_fhss_subtype) { 2693871Syz147064 case WL_FHSS: 2703871Syz147064 case WL_DSSS: 2713871Syz147064 case WL_IRBASE: 2723871Syz147064 case WL_HRDS: 2733871Syz147064 case WL_ERP: 2743871Syz147064 *channelp = wlfp->wl_fhss_channel; 2753871Syz147064 break; 2763871Syz147064 case WL_OFDM: 2773871Syz147064 *channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency); 2783871Syz147064 break; 2793871Syz147064 default: 2803871Syz147064 return (B_FALSE); 2813871Syz147064 } 2823871Syz147064 return (B_TRUE); 2833871Syz147064 } 2843871Syz147064 2853871Syz147064 #define IEEE80211_RATE 0x7f 2863871Syz147064 static void 2873871Syz147064 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp) 2883871Syz147064 { 2893871Syz147064 int i; 2903871Syz147064 2913871Syz147064 (void) memset(attrp, 0, sizeof (*attrp)); 2923871Syz147064 2933871Syz147064 (void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN, 2943871Syz147064 "%s", wlp->wl_ess_conf_essid.wl_essid_essid); 2953871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 2963871Syz147064 2973871Syz147064 (void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid, 2983871Syz147064 DLADM_WLAN_BSSID_LEN); 2993871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 3003871Syz147064 3013871Syz147064 attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled == 3023871Syz147064 WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE); 303*4126Szf162725 if (wlp->wl_ess_conf_reserved[0] > 0) 304*4126Szf162725 attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 3053871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 3063871Syz147064 3073871Syz147064 attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ? 3083871Syz147064 DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS); 3093871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 3103871Syz147064 3113871Syz147064 attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ? 3123871Syz147064 DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED); 3133871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 3143871Syz147064 3153871Syz147064 attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl); 3163871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 3173871Syz147064 3183871Syz147064 attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf); 3193871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 3203871Syz147064 3213871Syz147064 for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) { 3223871Syz147064 wlp->wl_supported_rates[i] &= IEEE80211_RATE; 3233871Syz147064 if (wlp->wl_supported_rates[i] > attrp->wa_speed) 3243871Syz147064 attrp->wa_speed = wlp->wl_supported_rates[i]; 3253871Syz147064 } 3263871Syz147064 if (attrp->wa_speed > 0) 3273871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 3283871Syz147064 3293871Syz147064 if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, 3303871Syz147064 &attrp->wa_channel)) 3313871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL; 3323871Syz147064 } 3333871Syz147064 3343871Syz147064 dladm_status_t 3353871Syz147064 dladm_wlan_scan(const char *link, void *arg, 3363871Syz147064 boolean_t (*func)(void *, dladm_wlan_attr_t *)) 3373871Syz147064 { 3383871Syz147064 int fd, i; 3393871Syz147064 uint32_t count; 3403871Syz147064 wl_ess_conf_t *wlp; 3413871Syz147064 wldp_t *gbuf; 3423871Syz147064 dladm_wlan_attr_t wlattr; 3433871Syz147064 dladm_status_t status; 3443871Syz147064 boolean_t connected; 3453871Syz147064 3463871Syz147064 if ((fd = open_link(link)) < 0) 3473871Syz147064 return (DLADM_STATUS_LINKINVAL); 3483871Syz147064 3493871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 3503871Syz147064 status = DLADM_STATUS_NOMEM; 3513871Syz147064 goto done; 3523871Syz147064 } 3533871Syz147064 3543871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 3553871Syz147064 status = DLADM_STATUS_FAILED; 3563871Syz147064 goto done; 3573871Syz147064 } 3583871Syz147064 connected = IS_CONNECTED(gbuf); 3593871Syz147064 3603871Syz147064 if (do_scan(fd, gbuf) < 0) { 3613871Syz147064 status = DLADM_STATUS_FAILED; 3623871Syz147064 goto done; 3633871Syz147064 } 3643871Syz147064 365*4126Szf162725 if (func == NULL) { 366*4126Szf162725 status = DLADM_STATUS_OK; 367*4126Szf162725 goto done; 368*4126Szf162725 } 369*4126Szf162725 3703871Syz147064 if (do_get_esslist(fd, gbuf) < 0) { 3713871Syz147064 status = DLADM_STATUS_FAILED; 3723871Syz147064 goto done; 3733871Syz147064 } 3743871Syz147064 3753871Syz147064 wlp = ((wl_ess_list_t *)gbuf->wldp_buf)->wl_ess_list_ess; 3763871Syz147064 count = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num; 3773871Syz147064 3783871Syz147064 for (i = 0; i < count; i++, wlp++) { 3793871Syz147064 fill_wlan_attr(wlp, &wlattr); 3803871Syz147064 if (!func(arg, &wlattr)) 3813871Syz147064 break; 3823871Syz147064 } 3833871Syz147064 3843871Syz147064 if (!connected) { 3853871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 3863871Syz147064 status = DLADM_STATUS_FAILED; 3873871Syz147064 goto done; 3883871Syz147064 } 3893871Syz147064 if (IS_CONNECTED(gbuf)) 390*4126Szf162725 (void) do_disconnect(link, fd, gbuf); 3913871Syz147064 } 3923871Syz147064 3933871Syz147064 status = DLADM_STATUS_OK; 3943871Syz147064 done: 3953871Syz147064 free(gbuf); 3963871Syz147064 (void) close(fd); 3973871Syz147064 return (status); 3983871Syz147064 } 3993871Syz147064 4003871Syz147064 /* 4013871Syz147064 * Structures used in building the list of eligible WLANs to connect to. 4023871Syz147064 * Specifically, `connect_state' has the WLAN attributes that must be matched 4033871Syz147064 * (in `cs_attr') and a growing list of WLANs that matched those attributes 4043871Syz147064 * chained through `cs_list'. Each element in the list is of type `attr_node' 4053871Syz147064 * and has the matching WLAN's attributes and a pointer to the next element. 4063871Syz147064 * For convenience, `cs_count' tracks the number of elements in the list. 4073871Syz147064 */ 4083871Syz147064 typedef struct attr_node { 4093871Syz147064 dladm_wlan_attr_t an_attr; 4103871Syz147064 struct attr_node *an_next; 4113871Syz147064 } attr_node_t; 4123871Syz147064 4133871Syz147064 typedef struct connect_state { 4143871Syz147064 dladm_wlan_attr_t *cs_attr; 4153871Syz147064 uint_t cs_count; 4163871Syz147064 attr_node_t *cs_list; 4173871Syz147064 } connect_state_t; 4183871Syz147064 4193871Syz147064 /* 4203871Syz147064 * Compare two sets of WLAN attributes. For now, we only consider strength 4213871Syz147064 * and speed (in that order), which matches the documented default policy for 4223871Syz147064 * dladm_wlan_connect(). 4233871Syz147064 */ 4243871Syz147064 static int 4253871Syz147064 attr_compare(const void *p1, const void *p2) 4263871Syz147064 { 4273871Syz147064 dladm_wlan_attr_t *attrp1, *attrp2; 4283871Syz147064 4293871Syz147064 attrp1 = (*(dladm_wlan_attr_t **)p1); 4303871Syz147064 attrp2 = (*(dladm_wlan_attr_t **)p2); 4313871Syz147064 4323871Syz147064 if (attrp1->wa_strength < attrp2->wa_strength) 4333871Syz147064 return (1); 4343871Syz147064 4353871Syz147064 if (attrp1->wa_strength > attrp2->wa_strength) 4363871Syz147064 return (-1); 4373871Syz147064 4383871Syz147064 return (attrp2->wa_speed - attrp1->wa_speed); 4393871Syz147064 } 4403871Syz147064 4413871Syz147064 /* 4423871Syz147064 * Callback function used by dladm_wlan_connect() to filter out unwanted 4433871Syz147064 * WLANs when scanning for available WLANs. Always returns B_TRUE to 4443871Syz147064 * continue the scan. 4453871Syz147064 */ 4463871Syz147064 static boolean_t 4473871Syz147064 connect_cb(void *arg, dladm_wlan_attr_t *attrp) 4483871Syz147064 { 4493871Syz147064 attr_node_t *nodep; 4503871Syz147064 dladm_wlan_attr_t *fattrp; 4513871Syz147064 connect_state_t *statep = (connect_state_t *)arg; 4523871Syz147064 4533871Syz147064 fattrp = statep->cs_attr; 4543871Syz147064 if (fattrp == NULL) 4553871Syz147064 goto append; 4563871Syz147064 4573871Syz147064 if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid) 4583871Syz147064 return (B_TRUE); 4593871Syz147064 4603871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 && 4613871Syz147064 strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes, 4623871Syz147064 DLADM_WLAN_MAX_ESSID_LEN) != 0) 4633871Syz147064 return (B_TRUE); 4643871Syz147064 4653871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 4663871Syz147064 fattrp->wa_secmode != attrp->wa_secmode) 4673871Syz147064 return (B_TRUE); 4683871Syz147064 4693871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 && 4703871Syz147064 fattrp->wa_mode != attrp->wa_mode) 4713871Syz147064 return (B_TRUE); 4723871Syz147064 4733871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 && 4743871Syz147064 fattrp->wa_strength != attrp->wa_strength) 4753871Syz147064 return (B_TRUE); 4763871Syz147064 4773871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 && 4783871Syz147064 fattrp->wa_speed != attrp->wa_speed) 4793871Syz147064 return (B_TRUE); 4803871Syz147064 4813871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) { 4823871Syz147064 attrp->wa_auth = fattrp->wa_auth; 4833871Syz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 4843871Syz147064 } 4853871Syz147064 4863871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 4873871Syz147064 fattrp->wa_bsstype != attrp->wa_bsstype) 4883871Syz147064 return (B_TRUE); 4893871Syz147064 4903871Syz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 && 4913871Syz147064 memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes, 4923871Syz147064 DLADM_WLAN_BSSID_LEN) != 0) 4933871Syz147064 return (B_TRUE); 4943871Syz147064 append: 4953871Syz147064 nodep = malloc(sizeof (attr_node_t)); 4963871Syz147064 if (nodep == NULL) 4973871Syz147064 return (B_TRUE); 4983871Syz147064 4993871Syz147064 (void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t)); 5003871Syz147064 nodep->an_next = statep->cs_list; 5013871Syz147064 statep->cs_list = nodep; 5023871Syz147064 statep->cs_count++; 5033871Syz147064 5043871Syz147064 return (B_TRUE); 5053871Syz147064 } 5063871Syz147064 507*4126Szf162725 #define IEEE80211_C_WPA 0x01800000 508*4126Szf162725 5093871Syz147064 static dladm_status_t 510*4126Szf162725 do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, 5113871Syz147064 boolean_t create_ibss, void *keys, uint_t key_count, int timeout) 5123871Syz147064 { 5133871Syz147064 dladm_wlan_secmode_t secmode; 5143871Syz147064 dladm_wlan_auth_t authmode; 5153871Syz147064 dladm_wlan_bsstype_t bsstype; 5163871Syz147064 dladm_wlan_essid_t essid; 517*4126Szf162725 boolean_t essid_valid = B_FALSE; 5183871Syz147064 dladm_wlan_channel_t channel; 519*4126Szf162725 hrtime_t start; 520*4126Szf162725 wl_capability_t *caps; 5213871Syz147064 5223871Syz147064 if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) { 5233871Syz147064 channel = attrp->wa_channel; 5243871Syz147064 if (do_set_channel(fd, gbuf, &channel) < 0) 5253871Syz147064 goto fail; 5263871Syz147064 } 5273871Syz147064 5283871Syz147064 secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ? 5293871Syz147064 attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE; 5303871Syz147064 5313871Syz147064 if (do_set_encryption(fd, gbuf, &secmode) < 0) 5323871Syz147064 goto fail; 5333871Syz147064 5343871Syz147064 authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ? 5353871Syz147064 attrp->wa_auth : DLADM_WLAN_AUTH_OPEN; 5363871Syz147064 5373871Syz147064 if (do_set_authmode(fd, gbuf, &authmode) < 0) 5383871Syz147064 goto fail; 5393871Syz147064 5403871Syz147064 bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ? 5413871Syz147064 attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS; 5423871Syz147064 5433871Syz147064 if (do_set_bsstype(fd, gbuf, &bsstype) < 0) 5443871Syz147064 goto fail; 5453871Syz147064 5463871Syz147064 if (secmode == DLADM_WLAN_SECMODE_WEP) { 5473871Syz147064 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 5483871Syz147064 return (DLADM_STATUS_BADARG); 549*4126Szf162725 if (do_set_key(fd, gbuf, keys, key_count) < 0) 5503871Syz147064 goto fail; 551*4126Szf162725 } else if (secmode == DLADM_WLAN_SECMODE_WPA) { 552*4126Szf162725 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 553*4126Szf162725 return (DLADM_STATUS_BADARG); 554*4126Szf162725 if (do_get_capability(fd, gbuf) < 0) 555*4126Szf162725 goto fail; 556*4126Szf162725 caps = (wl_capability_t *)(gbuf->wldp_buf); 557*4126Szf162725 if ((caps->caps & IEEE80211_C_WPA) == 0) 558*4126Szf162725 return (DLADM_STATUS_NOTSUP); 5593871Syz147064 } 5603871Syz147064 5613871Syz147064 if (create_ibss) { 5623871Syz147064 if (do_set_channel(fd, gbuf, &channel) < 0) 5633871Syz147064 goto fail; 5643871Syz147064 5653871Syz147064 if (do_set_createibss(fd, gbuf, &create_ibss) < 0) 5663871Syz147064 goto fail; 5673871Syz147064 5683871Syz147064 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) { 5693871Syz147064 generate_essid(&essid); 5703871Syz147064 essid_valid = B_TRUE; 5713871Syz147064 } 5723871Syz147064 } 5733871Syz147064 5743871Syz147064 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) { 5753871Syz147064 essid = attrp->wa_essid; 5763871Syz147064 essid_valid = B_TRUE; 5773871Syz147064 } 5783871Syz147064 5793871Syz147064 if (!essid_valid) 5803871Syz147064 return (DLADM_STATUS_FAILED); 5813871Syz147064 if (do_set_essid(fd, gbuf, &essid) < 0) 5823871Syz147064 goto fail; 5833871Syz147064 584*4126Szf162725 /* 585*4126Szf162725 * Because wpa daemon needs getting essid from driver, 586*4126Szf162725 * we need call do_set_essid() first, then call wpa_instance_create(). 587*4126Szf162725 */ 588*4126Szf162725 if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) 589*4126Szf162725 (void) wpa_instance_create(link, keys); 590*4126Szf162725 5913871Syz147064 start = gethrtime(); 5923871Syz147064 for (;;) { 5933871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) 5943871Syz147064 goto fail; 5953871Syz147064 5963871Syz147064 if (IS_CONNECTED(gbuf)) 5973871Syz147064 break; 5983871Syz147064 5993871Syz147064 (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE); 6003871Syz147064 if ((timeout >= 0) && (gethrtime() - start) / 6013871Syz147064 NANOSEC >= timeout) 6023871Syz147064 return (DLADM_STATUS_TIMEDOUT); 6033871Syz147064 } 6043871Syz147064 return (DLADM_STATUS_OK); 6053871Syz147064 fail: 6063871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 6073871Syz147064 } 6083871Syz147064 6093871Syz147064 dladm_status_t 6103871Syz147064 dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, 6113871Syz147064 int timeout, void *keys, uint_t key_count, uint_t flags) 6123871Syz147064 { 6133871Syz147064 int fd, i; 6143871Syz147064 wldp_t *gbuf = NULL; 6153871Syz147064 connect_state_t state = {0, NULL, NULL}; 6163871Syz147064 attr_node_t *nodep = NULL; 6173871Syz147064 boolean_t create_ibss, set_authmode; 6183871Syz147064 dladm_wlan_attr_t **wl_list = NULL; 6193871Syz147064 dladm_status_t status = DLADM_STATUS_FAILED; 6203871Syz147064 6213871Syz147064 if ((fd = open_link(link)) < 0) 6223871Syz147064 return (DLADM_STATUS_LINKINVAL); 6233871Syz147064 6243871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 6253871Syz147064 status = DLADM_STATUS_NOMEM; 6263871Syz147064 goto done; 6273871Syz147064 } 6283871Syz147064 6293871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 6303871Syz147064 status = DLADM_STATUS_FAILED; 6313871Syz147064 goto done; 6323871Syz147064 } 6333871Syz147064 6343871Syz147064 if (IS_CONNECTED(gbuf)) { 6353871Syz147064 status = DLADM_STATUS_ISCONN; 6363871Syz147064 goto done; 6373871Syz147064 } 6383871Syz147064 6393871Syz147064 set_authmode = ((attrp != NULL) && 6403871Syz147064 (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0); 6413871Syz147064 create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 && 6423871Syz147064 attrp != NULL && 6433871Syz147064 (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 6443871Syz147064 attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS); 6453871Syz147064 6463871Syz147064 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 || 6473871Syz147064 (create_ibss && attrp != NULL && 6483871Syz147064 (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) { 649*4126Szf162725 status = do_connect(link, fd, gbuf, attrp, 6503871Syz147064 create_ibss, keys, key_count, timeout); 6513871Syz147064 goto done; 6523871Syz147064 } 6533871Syz147064 6543871Syz147064 state.cs_attr = attrp; 6553871Syz147064 state.cs_list = NULL; 6563871Syz147064 state.cs_count = 0; 6573871Syz147064 6583871Syz147064 status = dladm_wlan_scan(link, &state, connect_cb); 6593871Syz147064 if (status != DLADM_STATUS_OK) 6603871Syz147064 goto done; 6613871Syz147064 6623871Syz147064 if (state.cs_count == 0) { 6633871Syz147064 if (!create_ibss) { 6643871Syz147064 status = DLADM_STATUS_NOTFOUND; 6653871Syz147064 goto done; 6663871Syz147064 } 667*4126Szf162725 status = do_connect(link, fd, gbuf, attrp, create_ibss, 6683871Syz147064 keys, key_count, timeout); 6693871Syz147064 goto done; 6703871Syz147064 } 6713871Syz147064 6723871Syz147064 wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *)); 6733871Syz147064 if (wl_list == NULL) { 6743871Syz147064 status = DLADM_STATUS_NOMEM; 6753871Syz147064 goto done; 6763871Syz147064 } 6773871Syz147064 6783871Syz147064 nodep = state.cs_list; 6793871Syz147064 for (i = 0; i < state.cs_count; i++) { 6803871Syz147064 wl_list[i] = &nodep->an_attr; 6813871Syz147064 nodep = nodep->an_next; 6823871Syz147064 } 6833871Syz147064 qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *), 6843871Syz147064 attr_compare); 6853871Syz147064 6863871Syz147064 for (i = 0; i < state.cs_count; i++) { 6873871Syz147064 dladm_wlan_attr_t *ap = wl_list[i]; 6883871Syz147064 689*4126Szf162725 status = do_connect(link, fd, gbuf, ap, create_ibss, keys, 6903871Syz147064 key_count, timeout); 6913871Syz147064 if (status == DLADM_STATUS_OK) 6923871Syz147064 break; 6933871Syz147064 6943871Syz147064 if (!set_authmode) { 6953871Syz147064 ap->wa_auth = DLADM_WLAN_AUTH_SHARED; 6963871Syz147064 ap->wa_valid |= DLADM_WLAN_ATTR_AUTH; 697*4126Szf162725 status = do_connect(link, fd, gbuf, ap, create_ibss, 698*4126Szf162725 keys, key_count, timeout); 6993871Syz147064 if (status == DLADM_STATUS_OK) 7003871Syz147064 break; 7013871Syz147064 } 7023871Syz147064 } 7033871Syz147064 done: 7043871Syz147064 if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN)) 705*4126Szf162725 (void) do_disconnect(link, fd, gbuf); 7063871Syz147064 7073871Syz147064 while (state.cs_list != NULL) { 7083871Syz147064 nodep = state.cs_list; 7093871Syz147064 state.cs_list = nodep->an_next; 7103871Syz147064 free(nodep); 7113871Syz147064 } 7123871Syz147064 free(gbuf); 7133871Syz147064 free(wl_list); 7143871Syz147064 (void) close(fd); 7153871Syz147064 return (status); 7163871Syz147064 } 7173871Syz147064 7183871Syz147064 dladm_status_t 7193871Syz147064 dladm_wlan_disconnect(const char *link) 7203871Syz147064 { 7213871Syz147064 int fd; 7223871Syz147064 wldp_t *gbuf; 7233871Syz147064 dladm_status_t status; 7243871Syz147064 7253871Syz147064 if ((fd = open_link(link)) < 0) 7263871Syz147064 return (DLADM_STATUS_BADARG); 7273871Syz147064 7283871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 7293871Syz147064 status = DLADM_STATUS_NOMEM; 7303871Syz147064 goto done; 7313871Syz147064 } 7323871Syz147064 7333871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 7343871Syz147064 status = DLADM_STATUS_FAILED; 7353871Syz147064 goto done; 7363871Syz147064 } 7373871Syz147064 7383871Syz147064 if (!IS_CONNECTED(gbuf)) { 7393871Syz147064 status = DLADM_STATUS_NOTCONN; 7403871Syz147064 goto done; 7413871Syz147064 } 7423871Syz147064 743*4126Szf162725 if (do_disconnect(link, fd, gbuf) < 0) { 7443871Syz147064 status = DLADM_STATUS_FAILED; 7453871Syz147064 goto done; 7463871Syz147064 } 7473871Syz147064 7483871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 7493871Syz147064 status = DLADM_STATUS_FAILED; 7503871Syz147064 goto done; 7513871Syz147064 } 7523871Syz147064 7533871Syz147064 if (IS_CONNECTED(gbuf)) { 7543871Syz147064 status = DLADM_STATUS_FAILED; 7553871Syz147064 goto done; 7563871Syz147064 } 7573871Syz147064 7583871Syz147064 status = DLADM_STATUS_OK; 7593871Syz147064 done: 7603871Syz147064 free(gbuf); 7613871Syz147064 (void) close(fd); 7623871Syz147064 return (status); 7633871Syz147064 } 7643871Syz147064 7653871Syz147064 typedef struct dladm_wlan_linkname { 7663871Syz147064 char wl_name[MAXNAMELEN]; 7673871Syz147064 struct dladm_wlan_linkname *wl_next; 7683871Syz147064 } dladm_wlan_linkname_t; 7693871Syz147064 7703871Syz147064 typedef struct dladm_wlan_walk { 7713871Syz147064 dladm_wlan_linkname_t *ww_list; 7723871Syz147064 dladm_status_t ww_status; 7733871Syz147064 } dladm_wlan_walk_t; 7743871Syz147064 7753871Syz147064 /* ARGSUSED */ 7763871Syz147064 static int 7773871Syz147064 append_linkname(di_node_t node, di_minor_t minor, void *arg) 7783871Syz147064 { 7793871Syz147064 dladm_wlan_walk_t *statep = arg; 7803871Syz147064 dladm_wlan_linkname_t **lastp = &statep->ww_list; 7813871Syz147064 dladm_wlan_linkname_t *wlp = *lastp; 7823871Syz147064 char name[MAXNAMELEN]; 7833871Syz147064 7843871Syz147064 (void) snprintf(name, MAXNAMELEN, "%s%d", 7853871Syz147064 di_driver_name(node), di_instance(node)); 7863871Syz147064 7873871Syz147064 while (wlp != NULL) { 7883871Syz147064 if (strcmp(wlp->wl_name, name) == 0) 7893871Syz147064 return (DI_WALK_CONTINUE); 7903871Syz147064 7913871Syz147064 lastp = &wlp->wl_next; 7923871Syz147064 wlp = wlp->wl_next; 7933871Syz147064 } 7943871Syz147064 if ((wlp = malloc(sizeof (*wlp))) == NULL) { 7953871Syz147064 statep->ww_status = DLADM_STATUS_NOMEM; 7963871Syz147064 return (DI_WALK_CONTINUE); 7973871Syz147064 } 7983871Syz147064 7993871Syz147064 (void) strlcpy(wlp->wl_name, name, MAXNAMELEN); 8003871Syz147064 wlp->wl_next = NULL; 8013871Syz147064 *lastp = wlp; 8023871Syz147064 8033871Syz147064 return (DI_WALK_CONTINUE); 8043871Syz147064 } 8053871Syz147064 8063871Syz147064 dladm_status_t 8073871Syz147064 dladm_wlan_walk(void *arg, boolean_t (*func)(void *, const char *)) 8083871Syz147064 { 8093871Syz147064 di_node_t root; 8103871Syz147064 dladm_wlan_walk_t state; 8113871Syz147064 dladm_wlan_linkname_t *wlp, *wlp_next; 8123871Syz147064 boolean_t cont = B_TRUE; 8133871Syz147064 8143871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 8153871Syz147064 return (DLADM_STATUS_FAILED); 8163871Syz147064 8173871Syz147064 state.ww_list = NULL; 8183871Syz147064 state.ww_status = DLADM_STATUS_OK; 8193871Syz147064 (void) di_walk_minor(root, DDI_NT_NET_WIFI, DI_CHECK_ALIAS, 8203871Syz147064 &state, append_linkname); 8213871Syz147064 di_fini(root); 8223871Syz147064 8233871Syz147064 for (wlp = state.ww_list; wlp != NULL; wlp = wlp_next) { 8243871Syz147064 /* 8253871Syz147064 * NOTE: even if (*func)() returns B_FALSE, the loop continues 8263871Syz147064 * since all memory must be freed. 8273871Syz147064 */ 8283871Syz147064 if (cont) 8293871Syz147064 cont = (*func)(arg, wlp->wl_name); 8303871Syz147064 wlp_next = wlp->wl_next; 8313871Syz147064 free(wlp); 8323871Syz147064 } 8333871Syz147064 return (state.ww_status); 8343871Syz147064 } 8353871Syz147064 8363871Syz147064 dladm_status_t 8373871Syz147064 dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) 8383871Syz147064 { 8393871Syz147064 int fd; 8403871Syz147064 wldp_t *gbuf; 8413871Syz147064 wl_rssi_t signal; 8423871Syz147064 wl_bss_type_t bsstype; 8433871Syz147064 wl_authmode_t authmode; 8443871Syz147064 wl_encryption_t encryption; 8453871Syz147064 wl_rates_t *ratesp; 8463871Syz147064 dladm_wlan_attr_t *wl_attrp; 8473871Syz147064 dladm_status_t status = DLADM_STATUS_FAILED; 8483871Syz147064 8493871Syz147064 if (attrp == NULL) 8503871Syz147064 return (DLADM_STATUS_BADARG); 8513871Syz147064 8523871Syz147064 if ((fd = open_link(link)) < 0) 8533871Syz147064 return (DLADM_STATUS_LINKINVAL); 8543871Syz147064 8553871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 8563871Syz147064 status = DLADM_STATUS_NOMEM; 8573871Syz147064 goto done; 8583871Syz147064 } 8593871Syz147064 8603871Syz147064 (void) memset(attrp, 0, sizeof (*attrp)); 8613871Syz147064 wl_attrp = &attrp->la_wlan_attr; 8623871Syz147064 8633871Syz147064 if (do_get_linkstatus(fd, gbuf) < 0) 8643871Syz147064 goto done; 8653871Syz147064 8663871Syz147064 attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS; 8673871Syz147064 if (!IS_CONNECTED(gbuf)) { 8683871Syz147064 attrp->la_status = DLADM_WLAN_LINKSTATUS_DISCONNECTED; 869*4126Szf162725 } else { 870*4126Szf162725 attrp->la_status = DLADM_WLAN_LINKSTATUS_CONNECTED; 8713871Syz147064 } 8723871Syz147064 8733871Syz147064 if (do_get_essid(fd, gbuf) < 0) 8743871Syz147064 goto done; 8753871Syz147064 8763871Syz147064 (void) strlcpy(wl_attrp->wa_essid.we_bytes, 8773871Syz147064 ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid, 8783871Syz147064 DLADM_WLAN_MAX_ESSID_LEN); 8793871Syz147064 8803871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 8813871Syz147064 8823871Syz147064 if (do_get_bssid(fd, gbuf) < 0) 8833871Syz147064 goto done; 8843871Syz147064 8853871Syz147064 (void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf, 8863871Syz147064 DLADM_WLAN_BSSID_LEN); 8873871Syz147064 8883871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 8893871Syz147064 890*4126Szf162725 if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) { 891*4126Szf162725 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 892*4126Szf162725 status = DLADM_STATUS_OK; 893*4126Szf162725 goto done; 894*4126Szf162725 } 895*4126Szf162725 8963871Syz147064 if (do_get_encryption(fd, gbuf) < 0) 8973871Syz147064 goto done; 8983871Syz147064 8993871Syz147064 encryption = *(wl_encryption_t *)(gbuf->wldp_buf); 9003871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 9013871Syz147064 9023871Syz147064 switch (encryption) { 9033871Syz147064 case WL_NOENCRYPTION: 9043871Syz147064 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE; 9053871Syz147064 break; 9063871Syz147064 case WL_ENC_WEP: 9073871Syz147064 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP; 9083871Syz147064 break; 909*4126Szf162725 case WL_ENC_WPA: 910*4126Szf162725 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 911*4126Szf162725 break; 9123871Syz147064 default: 9133871Syz147064 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE; 9143871Syz147064 break; 9153871Syz147064 } 9163871Syz147064 9173871Syz147064 if (do_get_signal(fd, gbuf) < 0) 9183871Syz147064 goto done; 9193871Syz147064 9203871Syz147064 signal = *(wl_rssi_t *)(gbuf->wldp_buf); 9213871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 9223871Syz147064 wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal); 9233871Syz147064 9243871Syz147064 if (do_get_rate(fd, gbuf) < 0) 9253871Syz147064 goto done; 9263871Syz147064 9273871Syz147064 ratesp = (wl_rates_t *)(gbuf->wldp_buf); 9283871Syz147064 if (ratesp->wl_rates_num > 0) { 9293871Syz147064 uint_t i, r = 0; 9303871Syz147064 9313871Syz147064 for (i = 0; i < ratesp->wl_rates_num; i++) { 9323871Syz147064 if (ratesp->wl_rates_rates[i] > r) 9333871Syz147064 r = ratesp->wl_rates_rates[i]; 9343871Syz147064 } 9353871Syz147064 wl_attrp->wa_speed = r; 9363871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 9373871Syz147064 } 9383871Syz147064 9393871Syz147064 if (do_get_authmode(fd, gbuf) < 0) 9403871Syz147064 goto done; 9413871Syz147064 9423871Syz147064 authmode = *(wl_authmode_t *)(gbuf->wldp_buf); 9433871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 9443871Syz147064 9453871Syz147064 switch (authmode) { 9463871Syz147064 case WL_OPENSYSTEM: 9473871Syz147064 wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN; 9483871Syz147064 break; 9493871Syz147064 case WL_SHAREDKEY: 9503871Syz147064 wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED; 9513871Syz147064 break; 9523871Syz147064 default: 9533871Syz147064 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH; 9543871Syz147064 break; 9553871Syz147064 } 9563871Syz147064 9573871Syz147064 if (do_get_bsstype(fd, gbuf) < 0) 9583871Syz147064 goto done; 9593871Syz147064 9603871Syz147064 bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf); 9613871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 9623871Syz147064 9633871Syz147064 switch (bsstype) { 9643871Syz147064 case WL_BSS_BSS: 9653871Syz147064 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS; 9663871Syz147064 break; 9673871Syz147064 case WL_BSS_IBSS: 9683871Syz147064 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS; 9693871Syz147064 break; 9703871Syz147064 case WL_BSS_ANY: 9713871Syz147064 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY; 9723871Syz147064 break; 9733871Syz147064 default: 9743871Syz147064 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE; 9753871Syz147064 break; 9763871Syz147064 } 9773871Syz147064 9783871Syz147064 if (do_get_mode(fd, gbuf) < 0) 9793871Syz147064 goto done; 9803871Syz147064 9813871Syz147064 wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf)); 9823871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 9833871Syz147064 if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE) 9843871Syz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 9853871Syz147064 9863871Syz147064 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 9873871Syz147064 status = DLADM_STATUS_OK; 9883871Syz147064 9893871Syz147064 done: 9903871Syz147064 free(gbuf); 9913871Syz147064 (void) close(fd); 9923871Syz147064 return (status); 9933871Syz147064 } 9943871Syz147064 9953871Syz147064 boolean_t 9963871Syz147064 dladm_wlan_is_valid(const char *link) 9973871Syz147064 { 9983871Syz147064 int fd = open_link(link); 9993871Syz147064 10003871Syz147064 if (fd < 0) 10013871Syz147064 return (B_FALSE); 10023871Syz147064 10033871Syz147064 (void) close(fd); 10043871Syz147064 return (B_TRUE); 10053871Syz147064 } 10063871Syz147064 10073871Syz147064 /* ARGSUSED */ 10083871Syz147064 static dladm_status_t 10093871Syz147064 do_check_prop(int fd, wldp_t *guf, prop_desc_t *pdp, char **prop_val, 10103871Syz147064 uint_t val_cnt, val_desc_t **vdpp) 10113871Syz147064 { 10123871Syz147064 int i; 10133871Syz147064 val_desc_t *vdp; 10143871Syz147064 10153871Syz147064 if (pdp->pd_nmodval == 0) 10163871Syz147064 return (DLADM_STATUS_PROPRDONLY); 10173871Syz147064 10183871Syz147064 if (val_cnt != 1) 10193871Syz147064 return (DLADM_STATUS_BADVALCNT); 10203871Syz147064 10213871Syz147064 for (i = 0; i < pdp->pd_nmodval; i++) 10223871Syz147064 if (strcasecmp(*prop_val, pdp->pd_modval[i].vd_name) == 0) 10233871Syz147064 break; 10243871Syz147064 10253871Syz147064 if (i == pdp->pd_nmodval) 10263871Syz147064 return (DLADM_STATUS_BADVAL); 10273871Syz147064 10283871Syz147064 vdp = malloc(sizeof (val_desc_t)); 10293871Syz147064 if (vdp == NULL) 10303871Syz147064 return (DLADM_STATUS_NOMEM); 10313871Syz147064 10323871Syz147064 (void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t)); 10333871Syz147064 *vdpp = vdp; 10343871Syz147064 return (DLADM_STATUS_OK); 10353871Syz147064 } 10363871Syz147064 10373871Syz147064 static dladm_status_t 10383871Syz147064 do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp, 10393871Syz147064 char **prop_val, uint_t val_cnt) 10403871Syz147064 { 10413871Syz147064 dladm_status_t status; 10423871Syz147064 val_desc_t *vdp = NULL; 10433871Syz147064 uint_t cnt; 10443871Syz147064 10453871Syz147064 if (pdp->pd_set == NULL) 10463871Syz147064 return (DLADM_STATUS_PROPRDONLY); 10473871Syz147064 10483871Syz147064 if (prop_val != NULL) { 10493871Syz147064 status = pdp->pd_check(fd, gbuf, pdp, prop_val, 10503871Syz147064 val_cnt, &vdp); 10513871Syz147064 10523871Syz147064 if (status != DLADM_STATUS_OK) 10533871Syz147064 return (status); 10543871Syz147064 10553871Syz147064 cnt = val_cnt; 10563871Syz147064 } else { 10573871Syz147064 if (pdp->pd_defval.vd_name == NULL) 10583871Syz147064 return (DLADM_STATUS_NOTSUP); 10593871Syz147064 10603871Syz147064 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 10613871Syz147064 return (DLADM_STATUS_NOMEM); 10623871Syz147064 10633871Syz147064 *vdp = pdp->pd_defval; 10643871Syz147064 cnt = 1; 10653871Syz147064 } 10663871Syz147064 status = pdp->pd_set(fd, gbuf, vdp, cnt); 10673871Syz147064 if (status == DLADM_STATUS_OK) { 10683871Syz147064 /* 10693871Syz147064 * Some ioctls return 0 but store error code in 10703871Syz147064 * wldp_result. Need to fix them. 10713871Syz147064 */ 10723871Syz147064 if (gbuf->wldp_result != WL_SUCCESS) 10733871Syz147064 status = dladm_wlan_wlresult2status(gbuf); 10743871Syz147064 } 10753871Syz147064 free(vdp); 10763871Syz147064 return (status); 10773871Syz147064 } 10783871Syz147064 10793871Syz147064 dladm_status_t 10803871Syz147064 dladm_wlan_set_prop(const char *link, const char *prop_name, 10813871Syz147064 char **prop_val, uint_t val_cnt, char **errprop) 10823871Syz147064 { 10833871Syz147064 int fd, i; 10843871Syz147064 wldp_t *gbuf = NULL; 10853871Syz147064 boolean_t found = B_FALSE; 10863871Syz147064 dladm_status_t status = DLADM_STATUS_OK; 10873871Syz147064 10883871Syz147064 if ((prop_name == NULL && prop_val != NULL) || 10893871Syz147064 (prop_val != NULL && val_cnt == 0)) 10903871Syz147064 return (DLADM_STATUS_BADARG); 10913871Syz147064 10923871Syz147064 if ((fd = open_link(link)) < 0) 10933871Syz147064 return (DLADM_STATUS_LINKINVAL); 10943871Syz147064 10953871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 10963871Syz147064 status = DLADM_STATUS_NOMEM; 10973871Syz147064 goto done; 10983871Syz147064 } 10993871Syz147064 11003871Syz147064 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { 11013871Syz147064 prop_desc_t *pdp = &prop_table[i]; 11023871Syz147064 dladm_status_t s; 11033871Syz147064 11043871Syz147064 if (prop_name != NULL && 11053871Syz147064 (strcasecmp(prop_name, pdp->pd_name) != 0)) 11063871Syz147064 continue; 11073871Syz147064 11083871Syz147064 found = B_TRUE; 11093871Syz147064 s = do_set_prop(fd, gbuf, pdp, prop_val, val_cnt); 11103871Syz147064 11113871Syz147064 if (prop_name != NULL) { 11123871Syz147064 status = s; 11133871Syz147064 break; 11143871Syz147064 } else { 11153871Syz147064 if (s != DLADM_STATUS_OK && 11163871Syz147064 s != DLADM_STATUS_NOTSUP) { 11173871Syz147064 if (errprop != NULL) 11183871Syz147064 *errprop = pdp->pd_name; 11193871Syz147064 status = s; 11203871Syz147064 break; 11213871Syz147064 } 11223871Syz147064 } 11233871Syz147064 } 11243871Syz147064 if (!found) 11253871Syz147064 status = DLADM_STATUS_NOTFOUND; 11263871Syz147064 done: 11273871Syz147064 free(gbuf); 11283871Syz147064 (void) close(fd); 11293871Syz147064 return (status); 11303871Syz147064 } 11313871Syz147064 11323871Syz147064 /* ARGSUSED */ 11333871Syz147064 dladm_status_t 11343871Syz147064 dladm_wlan_walk_prop(const char *link, void *arg, 11353871Syz147064 boolean_t (*func)(void *, const char *)) 11363871Syz147064 { 11373871Syz147064 int i; 11383871Syz147064 11393871Syz147064 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { 11403871Syz147064 if (!func(arg, prop_table[i].pd_name)) 11413871Syz147064 break; 11423871Syz147064 } 11433871Syz147064 return (DLADM_STATUS_OK); 11443871Syz147064 } 11453871Syz147064 11463871Syz147064 dladm_status_t 11473871Syz147064 dladm_wlan_get_prop(const char *link, dladm_prop_type_t type, 11483871Syz147064 const char *prop_name, char **prop_val, uint_t *val_cnt) 11493871Syz147064 { 11503871Syz147064 int fd; 11513871Syz147064 int i; 11523871Syz147064 wldp_t *gbuf; 11533871Syz147064 dladm_status_t status; 11543871Syz147064 uint_t cnt; 11553871Syz147064 prop_desc_t *pdp; 11563871Syz147064 11573871Syz147064 if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0) 11583871Syz147064 return (DLADM_STATUS_BADARG); 11593871Syz147064 11603871Syz147064 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) 11613871Syz147064 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 11623871Syz147064 break; 11633871Syz147064 11643871Syz147064 if (i == DLADM_WLAN_MAX_PROPS) 11653871Syz147064 return (DLADM_STATUS_NOTFOUND); 11663871Syz147064 11673871Syz147064 if ((fd = open_link(link)) < 0) 11683871Syz147064 return (DLADM_STATUS_LINKINVAL); 11693871Syz147064 11703871Syz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 11713871Syz147064 status = DLADM_STATUS_NOMEM; 11723871Syz147064 goto done; 11733871Syz147064 } 11743871Syz147064 pdp = &prop_table[i]; 11753871Syz147064 status = DLADM_STATUS_OK; 11763871Syz147064 11773871Syz147064 switch (type) { 11783871Syz147064 case DLADM_PROP_VAL_CURRENT: 11793871Syz147064 status = pdp->pd_get(fd, gbuf, prop_val, val_cnt); 11803871Syz147064 break; 11813871Syz147064 11823871Syz147064 case DLADM_PROP_VAL_DEFAULT: 11833871Syz147064 if (pdp->pd_defval.vd_name == NULL) { 11843871Syz147064 status = DLADM_STATUS_NOTSUP; 11853871Syz147064 break; 11863871Syz147064 } 11873871Syz147064 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 11883871Syz147064 *val_cnt = 1; 11893871Syz147064 break; 11903871Syz147064 11913871Syz147064 case DLADM_PROP_VAL_MODIFIABLE: 11923871Syz147064 if (pdp->pd_getmod != NULL) { 11933871Syz147064 status = pdp->pd_getmod(fd, gbuf, prop_val, val_cnt); 11943871Syz147064 break; 11953871Syz147064 } 11963871Syz147064 cnt = pdp->pd_nmodval; 11973871Syz147064 if (cnt == 0) { 11983871Syz147064 status = DLADM_STATUS_NOTSUP; 11993871Syz147064 } else if (cnt > *val_cnt) { 12003871Syz147064 status = DLADM_STATUS_TOOSMALL; 12013871Syz147064 } else { 12023871Syz147064 for (i = 0; i < cnt; i++) { 12033871Syz147064 (void) strcpy(prop_val[i], 12043871Syz147064 pdp->pd_modval[i].vd_name); 12053871Syz147064 } 12063871Syz147064 *val_cnt = cnt; 12073871Syz147064 } 12083871Syz147064 break; 12093871Syz147064 default: 12103871Syz147064 status = DLADM_STATUS_BADARG; 12113871Syz147064 break; 12123871Syz147064 } 12133871Syz147064 done: 12143871Syz147064 free(gbuf); 12153871Syz147064 (void) close(fd); 12163871Syz147064 return (status); 12173871Syz147064 } 12183871Syz147064 12193871Syz147064 static boolean_t 12203871Syz147064 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp) 12213871Syz147064 { 12223871Syz147064 int i; 12233871Syz147064 12243871Syz147064 for (i = 0; i < cnt; i++) { 12253871Syz147064 if (strcasecmp(str, vdp[i].vd_name) == 0) { 12263871Syz147064 *valp = vdp[i].vd_val; 12273871Syz147064 return (B_TRUE); 12283871Syz147064 } 12293871Syz147064 } 12303871Syz147064 return (B_FALSE); 12313871Syz147064 } 12323871Syz147064 12333871Syz147064 static boolean_t 12343871Syz147064 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp) 12353871Syz147064 { 12363871Syz147064 int i; 12373871Syz147064 12383871Syz147064 for (i = 0; i < cnt; i++) { 12393871Syz147064 if (val == vdp[i].vd_val) { 12403871Syz147064 *strp = vdp[i].vd_name; 12413871Syz147064 return (B_TRUE); 12423871Syz147064 } 12433871Syz147064 } 12443871Syz147064 return (B_FALSE); 12453871Syz147064 } 12463871Syz147064 12473871Syz147064 const char * 12483871Syz147064 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf) 12493871Syz147064 { 12503871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes); 12513871Syz147064 return (buf); 12523871Syz147064 } 12533871Syz147064 12543871Syz147064 const char * 12553871Syz147064 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf) 12563871Syz147064 { 12573871Syz147064 return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN, 12583871Syz147064 IFT_OTHER)); 12593871Syz147064 } 12603871Syz147064 12613871Syz147064 static const char * 12623871Syz147064 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf) 12633871Syz147064 { 12643871Syz147064 char *s; 12653871Syz147064 12663871Syz147064 if (!find_name_by_val(val, vdp, cnt, &s)) 12673871Syz147064 s = ""; 12683871Syz147064 12693871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 12703871Syz147064 return (buf); 12713871Syz147064 } 12723871Syz147064 12733871Syz147064 const char * 12743871Syz147064 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf) 12753871Syz147064 { 12763871Syz147064 return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals, 12773871Syz147064 VALCNT(secmode_vals), buf)); 12783871Syz147064 } 12793871Syz147064 12803871Syz147064 const char * 12813871Syz147064 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf) 12823871Syz147064 { 12833871Syz147064 return (dladm_wlan_val2str((uint_t)*strength, strength_vals, 12843871Syz147064 VALCNT(strength_vals), buf)); 12853871Syz147064 } 12863871Syz147064 12873871Syz147064 const char * 12883871Syz147064 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf) 12893871Syz147064 { 12903871Syz147064 return (dladm_wlan_val2str((uint_t)*mode, mode_vals, 12913871Syz147064 VALCNT(mode_vals), buf)); 12923871Syz147064 } 12933871Syz147064 12943871Syz147064 const char * 12953871Syz147064 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf) 12963871Syz147064 { 12973871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2, 12983871Syz147064 (float)(*speed) / 2); 12993871Syz147064 return (buf); 13003871Syz147064 } 13013871Syz147064 13023871Syz147064 const char * 13033871Syz147064 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf) 13043871Syz147064 { 13053871Syz147064 return (dladm_wlan_val2str((uint_t)*auth, auth_vals, 13063871Syz147064 VALCNT(auth_vals), buf)); 13073871Syz147064 } 13083871Syz147064 13093871Syz147064 const char * 13103871Syz147064 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf) 13113871Syz147064 { 13123871Syz147064 return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals, 13133871Syz147064 VALCNT(bsstype_vals), buf)); 13143871Syz147064 } 13153871Syz147064 13163871Syz147064 const char * 13173871Syz147064 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf) 13183871Syz147064 { 13193871Syz147064 return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals, 13203871Syz147064 VALCNT(linkstatus_vals), buf)); 13213871Syz147064 } 13223871Syz147064 13233871Syz147064 dladm_status_t 13243871Syz147064 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid) 13253871Syz147064 { 13263871Syz147064 if (str[0] == '\0') 13273871Syz147064 return (DLADM_STATUS_BADARG); 13283871Syz147064 13293871Syz147064 (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN); 13303871Syz147064 return (DLADM_STATUS_OK); 13313871Syz147064 } 13323871Syz147064 13333871Syz147064 dladm_status_t 13343871Syz147064 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid) 13353871Syz147064 { 13363871Syz147064 int len; 13373871Syz147064 uchar_t *buf; 13383871Syz147064 13393871Syz147064 buf = _link_aton(str, &len); 13403871Syz147064 if (buf == NULL) 13413871Syz147064 return (DLADM_STATUS_BADARG); 13423871Syz147064 13433871Syz147064 if (len != DLADM_WLAN_BSSID_LEN) { 13443871Syz147064 free(buf); 13453871Syz147064 return (DLADM_STATUS_BADARG); 13463871Syz147064 } 13473871Syz147064 13483871Syz147064 (void) memcpy(bssid->wb_bytes, buf, len); 13493871Syz147064 free(buf); 13503871Syz147064 return (DLADM_STATUS_OK); 13513871Syz147064 } 13523871Syz147064 13533871Syz147064 dladm_status_t 13543871Syz147064 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode) 13553871Syz147064 { 13563871Syz147064 uint_t val; 13573871Syz147064 13583871Syz147064 if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val)) 13593871Syz147064 return (DLADM_STATUS_BADARG); 13603871Syz147064 13613871Syz147064 *secmode = (dladm_wlan_secmode_t)val; 13623871Syz147064 return (DLADM_STATUS_OK); 13633871Syz147064 } 13643871Syz147064 13653871Syz147064 dladm_status_t 13663871Syz147064 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength) 13673871Syz147064 { 13683871Syz147064 uint_t val; 13693871Syz147064 13703871Syz147064 if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val)) 13713871Syz147064 return (DLADM_STATUS_BADARG); 13723871Syz147064 13733871Syz147064 *strength = (dladm_wlan_strength_t)val; 13743871Syz147064 return (DLADM_STATUS_OK); 13753871Syz147064 } 13763871Syz147064 13773871Syz147064 dladm_status_t 13783871Syz147064 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode) 13793871Syz147064 { 13803871Syz147064 uint_t val; 13813871Syz147064 13823871Syz147064 if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val)) 13833871Syz147064 return (DLADM_STATUS_BADARG); 13843871Syz147064 13853871Syz147064 *mode = (dladm_wlan_mode_t)val; 13863871Syz147064 return (DLADM_STATUS_OK); 13873871Syz147064 } 13883871Syz147064 13893871Syz147064 dladm_status_t 13903871Syz147064 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed) 13913871Syz147064 { 13923871Syz147064 *speed = (dladm_wlan_speed_t)(atof(str) * 2); 13933871Syz147064 return (DLADM_STATUS_OK); 13943871Syz147064 } 13953871Syz147064 13963871Syz147064 dladm_status_t 13973871Syz147064 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth) 13983871Syz147064 { 13993871Syz147064 uint_t val; 14003871Syz147064 14013871Syz147064 if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val)) 14023871Syz147064 return (DLADM_STATUS_BADARG); 14033871Syz147064 14043871Syz147064 *auth = (dladm_wlan_auth_t)val; 14053871Syz147064 return (DLADM_STATUS_OK); 14063871Syz147064 } 14073871Syz147064 14083871Syz147064 dladm_status_t 14093871Syz147064 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype) 14103871Syz147064 { 14113871Syz147064 uint_t val; 14123871Syz147064 14133871Syz147064 if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val)) 14143871Syz147064 return (DLADM_STATUS_BADARG); 14153871Syz147064 14163871Syz147064 *bsstype = (dladm_wlan_bsstype_t)val; 14173871Syz147064 return (DLADM_STATUS_OK); 14183871Syz147064 } 14193871Syz147064 14203871Syz147064 dladm_status_t 14213871Syz147064 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus) 14223871Syz147064 { 14233871Syz147064 uint_t val; 14243871Syz147064 14253871Syz147064 if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals), 14263871Syz147064 &val)) 14273871Syz147064 return (DLADM_STATUS_BADARG); 14283871Syz147064 14293871Syz147064 *linkstatus = (dladm_wlan_linkstatus_t)val; 14303871Syz147064 return (DLADM_STATUS_OK); 14313871Syz147064 } 14323871Syz147064 14333871Syz147064 static int 14343871Syz147064 do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) 14353871Syz147064 { 14363871Syz147064 int rc; 14373871Syz147064 struct strioctl stri; 14383871Syz147064 14393871Syz147064 gbuf->wldp_type = NET_802_11; 14403871Syz147064 gbuf->wldp_id = id; 14413871Syz147064 gbuf->wldp_length = len; 14423871Syz147064 14433871Syz147064 stri.ic_timout = 0; 14443871Syz147064 stri.ic_dp = (char *)gbuf; 14453871Syz147064 stri.ic_cmd = cmd; 14463871Syz147064 stri.ic_len = cmdlen; 14473871Syz147064 14483871Syz147064 if ((rc = ioctl(fd, I_STR, &stri)) != 0) { 14493871Syz147064 if (rc > 0) 14503871Syz147064 errno = rc; 14513871Syz147064 return (-1); 14523871Syz147064 } 14533871Syz147064 return (0); 14543871Syz147064 } 14553871Syz147064 14563871Syz147064 static int 14573871Syz147064 do_get_ioctl(int fd, wldp_t *gbuf, uint_t id) 14583871Syz147064 { 14593871Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 14603871Syz147064 return (do_ioctl(fd, gbuf, id, MAX_BUF_LEN, WLAN_GET_PARAM, 14613871Syz147064 MAX_BUF_LEN)); 14623871Syz147064 } 14633871Syz147064 14643871Syz147064 static int 14653871Syz147064 do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen) 14663871Syz147064 { 14673871Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 14683871Syz147064 (void) memcpy(gbuf->wldp_buf, buf, buflen); 14693871Syz147064 buflen += WIFI_BUF_OFFSET; 14703871Syz147064 return (do_ioctl(fd, gbuf, id, buflen, WLAN_SET_PARAM, buflen)); 14713871Syz147064 } 14723871Syz147064 14733871Syz147064 static int 14743871Syz147064 do_cmd_ioctl(int fd, wldp_t *gbuf, uint_t cmd) 14753871Syz147064 { 14763871Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 14773871Syz147064 return (do_ioctl(fd, gbuf, cmd, sizeof (wldp_t), WLAN_COMMAND, 14783871Syz147064 sizeof (wldp_t))); 14793871Syz147064 } 14803871Syz147064 14813871Syz147064 static int 14823871Syz147064 do_scan(int fd, wldp_t *gbuf) 14833871Syz147064 { 14843871Syz147064 return (do_cmd_ioctl(fd, gbuf, WL_SCAN)); 14853871Syz147064 } 14863871Syz147064 14873871Syz147064 static int 1488*4126Szf162725 do_disconnect(const char *link, int fd, wldp_t *gbuf) 14893871Syz147064 { 1490*4126Szf162725 if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf-> 1491*4126Szf162725 wldp_buf))->wpa_flag > 0) 1492*4126Szf162725 (void) wpa_instance_delete(link); 1493*4126Szf162725 14943871Syz147064 return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE)); 14953871Syz147064 } 14963871Syz147064 14973871Syz147064 static int 14983871Syz147064 do_get_esslist(int fd, wldp_t *gbuf) 14993871Syz147064 { 15003871Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 15013871Syz147064 return (do_ioctl(fd, gbuf, WL_ESS_LIST, MAX_BUF_LEN, 15023871Syz147064 WLAN_GET_PARAM, sizeof (wldp_t))); 15033871Syz147064 } 15043871Syz147064 15053871Syz147064 static int 15063871Syz147064 do_get_bssid(int fd, wldp_t *gbuf) 15073871Syz147064 { 15083871Syz147064 return (do_get_ioctl(fd, gbuf, WL_BSSID)); 15093871Syz147064 } 15103871Syz147064 15113871Syz147064 static int 15123871Syz147064 do_get_essid(int fd, wldp_t *gbuf) 15133871Syz147064 { 15143871Syz147064 return (do_get_ioctl(fd, gbuf, WL_ESSID)); 15153871Syz147064 } 15163871Syz147064 15173871Syz147064 static int 15183871Syz147064 do_get_bsstype(int fd, wldp_t *gbuf) 15193871Syz147064 { 15203871Syz147064 return (do_get_ioctl(fd, gbuf, WL_BSS_TYPE)); 15213871Syz147064 } 15223871Syz147064 15233871Syz147064 static int 15243871Syz147064 do_get_linkstatus(int fd, wldp_t *gbuf) 15253871Syz147064 { 15263871Syz147064 return (do_get_ioctl(fd, gbuf, WL_LINKSTATUS)); 15273871Syz147064 } 15283871Syz147064 15293871Syz147064 static int 15303871Syz147064 do_get_rate(int fd, wldp_t *gbuf) 15313871Syz147064 { 15323871Syz147064 return (do_get_ioctl(fd, gbuf, WL_DESIRED_RATES)); 15333871Syz147064 } 15343871Syz147064 15353871Syz147064 static int 15363871Syz147064 do_get_phyconf(int fd, wldp_t *gbuf) 15373871Syz147064 { 15383871Syz147064 return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); 15393871Syz147064 } 15403871Syz147064 15413871Syz147064 static int 15423871Syz147064 do_get_powermode(int fd, wldp_t *gbuf) 15433871Syz147064 { 15443871Syz147064 return (do_get_ioctl(fd, gbuf, WL_POWER_MODE)); 15453871Syz147064 } 15463871Syz147064 15473871Syz147064 static int 15483871Syz147064 do_get_radio(int fd, wldp_t *gbuf) 15493871Syz147064 { 15503871Syz147064 return (do_get_ioctl(fd, gbuf, WL_RADIO)); 15513871Syz147064 } 15523871Syz147064 15533871Syz147064 static int 15543871Syz147064 do_get_authmode(int fd, wldp_t *gbuf) 15553871Syz147064 { 15563871Syz147064 return (do_get_ioctl(fd, gbuf, WL_AUTH_MODE)); 15573871Syz147064 } 15583871Syz147064 15593871Syz147064 static int 15603871Syz147064 do_get_encryption(int fd, wldp_t *gbuf) 15613871Syz147064 { 15623871Syz147064 return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION)); 15633871Syz147064 } 15643871Syz147064 15653871Syz147064 static int 15663871Syz147064 do_get_signal(int fd, wldp_t *gbuf) 15673871Syz147064 { 15683871Syz147064 return (do_get_ioctl(fd, gbuf, WL_RSSI)); 15693871Syz147064 } 15703871Syz147064 15713871Syz147064 static int 15723871Syz147064 do_get_mode(int fd, wldp_t *gbuf) 15733871Syz147064 { 15743871Syz147064 return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); 15753871Syz147064 } 15763871Syz147064 15773871Syz147064 static dladm_status_t 15783871Syz147064 do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 15793871Syz147064 { 15803871Syz147064 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 15813871Syz147064 uint_t cnt = wrp->wl_rates_num; 15823871Syz147064 uint_t i; 15833871Syz147064 15843871Syz147064 if (cnt > *val_cnt) 15853871Syz147064 return (DLADM_STATUS_TOOSMALL); 15863871Syz147064 if (wrp->wl_rates_rates[0] == 0) { 15873871Syz147064 prop_val[0][0] = '\0'; 15883871Syz147064 *val_cnt = 1; 15893871Syz147064 return (DLADM_STATUS_OK); 15903871Syz147064 } 15913871Syz147064 15923871Syz147064 for (i = 0; i < cnt; i++) { 15933871Syz147064 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 15943871Syz147064 wrp->wl_rates_rates[i] % 2, 15953871Syz147064 (float)wrp->wl_rates_rates[i] / 2); 15963871Syz147064 } 15973871Syz147064 *val_cnt = cnt; 15983871Syz147064 return (DLADM_STATUS_OK); 15993871Syz147064 } 16003871Syz147064 16013871Syz147064 static dladm_status_t 16023871Syz147064 do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 16033871Syz147064 { 16043871Syz147064 if (do_get_rate(fd, gbuf) < 0) 16053871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 16063871Syz147064 16073871Syz147064 return (do_get_rate_common(gbuf, prop_val, val_cnt)); 16083871Syz147064 } 16093871Syz147064 16103871Syz147064 static dladm_status_t 16113871Syz147064 do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 16123871Syz147064 { 16133871Syz147064 if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0) 16143871Syz147064 return (DLADM_STATUS_FAILED); 16153871Syz147064 16163871Syz147064 return (do_get_rate_common(gbuf, prop_val, val_cnt)); 16173871Syz147064 } 16183871Syz147064 16193871Syz147064 static dladm_status_t 16203871Syz147064 do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 16213871Syz147064 { 16223871Syz147064 uint32_t channel; 16233871Syz147064 16243871Syz147064 if (do_get_phyconf(fd, gbuf) < 0) 16253871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 16263871Syz147064 16273871Syz147064 if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel)) 16283871Syz147064 return (DLADM_STATUS_NOTFOUND); 16293871Syz147064 16303871Syz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 16313871Syz147064 *val_cnt = 1; 16323871Syz147064 16333871Syz147064 return (DLADM_STATUS_OK); 16343871Syz147064 } 16353871Syz147064 16363871Syz147064 static dladm_status_t 16373871Syz147064 do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 16383871Syz147064 { 16393871Syz147064 wl_ps_mode_t *mode; 16403871Syz147064 const char *s; 16413871Syz147064 16423871Syz147064 if (do_get_powermode(fd, gbuf) < 0) 16433871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 16443871Syz147064 16453871Syz147064 mode = (wl_ps_mode_t *)(gbuf->wldp_buf); 16463871Syz147064 switch (mode->wl_ps_mode) { 16473871Syz147064 case WL_PM_AM: 16483871Syz147064 s = "off"; 16493871Syz147064 break; 16503871Syz147064 case WL_PM_MPS: 16513871Syz147064 s = "max"; 16523871Syz147064 break; 16533871Syz147064 case WL_PM_FAST: 16543871Syz147064 s = "fast"; 16553871Syz147064 break; 16563871Syz147064 default: 16573871Syz147064 return (DLADM_STATUS_NOTFOUND); 16583871Syz147064 } 16593871Syz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 16603871Syz147064 *val_cnt = 1; 16613871Syz147064 16623871Syz147064 return (DLADM_STATUS_OK); 16633871Syz147064 } 16643871Syz147064 16653871Syz147064 static dladm_status_t 16663871Syz147064 do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 16673871Syz147064 { 16683871Syz147064 wl_radio_t radio; 16693871Syz147064 const char *s; 16703871Syz147064 16713871Syz147064 if (do_get_radio(fd, gbuf) < 0) 16723871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 16733871Syz147064 16743871Syz147064 radio = *(wl_radio_t *)(gbuf->wldp_buf); 16753871Syz147064 switch (radio) { 16763871Syz147064 case B_TRUE: 16773871Syz147064 s = "on"; 16783871Syz147064 break; 16793871Syz147064 case B_FALSE: 16803871Syz147064 s = "off"; 16813871Syz147064 break; 16823871Syz147064 default: 16833871Syz147064 return (DLADM_STATUS_NOTFOUND); 16843871Syz147064 } 16853871Syz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 16863871Syz147064 *val_cnt = 1; 16873871Syz147064 16883871Syz147064 return (DLADM_STATUS_OK); 16893871Syz147064 } 16903871Syz147064 16913871Syz147064 static int 16923871Syz147064 do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) 16933871Syz147064 { 16943871Syz147064 wl_bss_type_t ibsstype; 16953871Syz147064 16963871Syz147064 switch (*bsstype) { 16973871Syz147064 case DLADM_WLAN_BSSTYPE_BSS: 16983871Syz147064 ibsstype = WL_BSS_BSS; 16993871Syz147064 break; 17003871Syz147064 case DLADM_WLAN_BSSTYPE_IBSS: 17013871Syz147064 ibsstype = WL_BSS_IBSS; 17023871Syz147064 break; 17033871Syz147064 default: 17043871Syz147064 ibsstype = WL_BSS_ANY; 17053871Syz147064 break; 17063871Syz147064 } 17073871Syz147064 return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype, 17083871Syz147064 sizeof (ibsstype))); 17093871Syz147064 } 17103871Syz147064 17113871Syz147064 static int 17123871Syz147064 do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) 17133871Syz147064 { 17143871Syz147064 wl_authmode_t auth_mode; 17153871Syz147064 17163871Syz147064 switch (*auth) { 17173871Syz147064 case DLADM_WLAN_AUTH_OPEN: 17183871Syz147064 auth_mode = WL_OPENSYSTEM; 17193871Syz147064 break; 17203871Syz147064 case DLADM_WLAN_AUTH_SHARED: 17213871Syz147064 auth_mode = WL_SHAREDKEY; 17223871Syz147064 break; 17233871Syz147064 default: 17243871Syz147064 return (-1); 17253871Syz147064 } 17263871Syz147064 return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode, 17273871Syz147064 sizeof (auth_mode))); 17283871Syz147064 } 17293871Syz147064 17303871Syz147064 static int 17313871Syz147064 do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) 17323871Syz147064 { 17333871Syz147064 wl_encryption_t encryption; 17343871Syz147064 17353871Syz147064 switch (*secmode) { 17363871Syz147064 case DLADM_WLAN_SECMODE_NONE: 17373871Syz147064 encryption = WL_NOENCRYPTION; 17383871Syz147064 break; 17393871Syz147064 case DLADM_WLAN_SECMODE_WEP: 17403871Syz147064 encryption = WL_ENC_WEP; 17413871Syz147064 break; 1742*4126Szf162725 case DLADM_WLAN_SECMODE_WPA: 1743*4126Szf162725 return (0); 17443871Syz147064 default: 17453871Syz147064 return (-1); 17463871Syz147064 } 17473871Syz147064 return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption, 17483871Syz147064 sizeof (encryption))); 17493871Syz147064 } 17503871Syz147064 17513871Syz147064 static int 1752*4126Szf162725 do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, 17533871Syz147064 uint_t key_count) 17543871Syz147064 { 17553871Syz147064 int i; 17563871Syz147064 wl_wep_key_t *wkp; 17573871Syz147064 wl_wep_key_tab_t wepkey_tab; 1758*4126Szf162725 dladm_wlan_key_t *kp; 17593871Syz147064 17603871Syz147064 if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL) 17613871Syz147064 return (-1); 17623871Syz147064 17633871Syz147064 (void) memset(wepkey_tab, 0, sizeof (wepkey_tab)); 17643871Syz147064 for (i = 0; i < MAX_NWEPKEYS; i++) 17653871Syz147064 wepkey_tab[i].wl_wep_operation = WL_NUL; 17663871Syz147064 17673871Syz147064 for (i = 0; i < key_count; i++) { 17683871Syz147064 kp = &keys[i]; 17693871Syz147064 if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS) 17703871Syz147064 return (-1); 17713871Syz147064 if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN && 17723871Syz147064 kp->wk_len != DLADM_WLAN_WEPKEY128_LEN) 17733871Syz147064 return (-1); 17743871Syz147064 17753871Syz147064 wkp = &wepkey_tab[kp->wk_idx - 1]; 17763871Syz147064 wkp->wl_wep_operation = WL_ADD; 17773871Syz147064 wkp->wl_wep_length = kp->wk_len; 17783871Syz147064 (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len); 17793871Syz147064 } 17803871Syz147064 17813871Syz147064 return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab, 17823871Syz147064 sizeof (wepkey_tab))); 17833871Syz147064 } 17843871Syz147064 17853871Syz147064 static int 17863871Syz147064 do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) 17873871Syz147064 { 17883871Syz147064 wl_essid_t iessid; 17893871Syz147064 17903871Syz147064 (void) memset(&iessid, 0, sizeof (essid)); 17913871Syz147064 17923871Syz147064 if (essid != NULL && essid->we_bytes[0] != '\0') { 17933871Syz147064 iessid.wl_essid_length = strlen(essid->we_bytes); 17943871Syz147064 (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes, 17953871Syz147064 sizeof (iessid.wl_essid_essid)); 17963871Syz147064 } else { 17973871Syz147064 return (-1); 17983871Syz147064 } 17993871Syz147064 return (do_set_ioctl(fd, gbuf, WL_ESSID, &iessid, sizeof (iessid))); 18003871Syz147064 } 18013871Syz147064 18023871Syz147064 /* ARGSUSED */ 18033871Syz147064 static dladm_status_t 18043871Syz147064 do_check_rate(int fd, wldp_t *gbuf, prop_desc_t *pdp, char **prop_val, 18053871Syz147064 uint_t val_cnt, val_desc_t **vdpp) 18063871Syz147064 { 18073871Syz147064 int i; 18083871Syz147064 uint_t modval_cnt = MAX_SUPPORT_RATES; 18093871Syz147064 char *buf, **modval; 18103871Syz147064 dladm_status_t status; 18113871Syz147064 val_desc_t *vdp = NULL; 18123871Syz147064 18133871Syz147064 if (val_cnt != 1) 18143871Syz147064 return (DLADM_STATUS_BADVALCNT); 18153871Syz147064 18163871Syz147064 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * MAX_SUPPORT_RATES); 18173871Syz147064 if (buf == NULL) 18183871Syz147064 goto done; 18193871Syz147064 18203871Syz147064 modval = (char **)(void *)buf; 18213871Syz147064 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 18223871Syz147064 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 18233871Syz147064 i * DLADM_STRSIZE; 18243871Syz147064 } 18253871Syz147064 18263871Syz147064 status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt); 18273871Syz147064 if (status != DLADM_STATUS_OK) 18283871Syz147064 goto done; 18293871Syz147064 18303871Syz147064 vdp = malloc(sizeof (val_desc_t)); 18313871Syz147064 if (vdp == NULL) { 18323871Syz147064 status = DLADM_STATUS_NOMEM; 18333871Syz147064 goto done; 18343871Syz147064 } 18353871Syz147064 18363871Syz147064 for (i = 0; i < modval_cnt; i++) { 18373871Syz147064 if (strcasecmp(*prop_val, modval[i]) == 0) { 18383871Syz147064 vdp->vd_val = (uint_t)(atof(*prop_val) * 2); 18393871Syz147064 status = DLADM_STATUS_OK; 18403871Syz147064 *vdpp = vdp; 18413871Syz147064 vdp = NULL; 18423871Syz147064 break; 18433871Syz147064 } 18443871Syz147064 } 18453871Syz147064 if (i == modval_cnt) 18463871Syz147064 status = DLADM_STATUS_BADVAL; 18473871Syz147064 done: 18483871Syz147064 free(buf); 18493871Syz147064 free(vdp); 18503871Syz147064 return (status); 18513871Syz147064 } 18523871Syz147064 18533871Syz147064 static dladm_status_t 18543871Syz147064 do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 18553871Syz147064 { 18563871Syz147064 dladm_wlan_rates_t rates; 18573871Syz147064 18583871Syz147064 if (val_cnt != 1) 18593871Syz147064 return (DLADM_STATUS_BADVALCNT); 18603871Syz147064 18613871Syz147064 rates.wr_cnt = 1; 18623871Syz147064 rates.wr_rates[0] = vdp[0].vd_val; 18633871Syz147064 18643871Syz147064 if (do_set_rate(fd, gbuf, &rates) < 0) 18653871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 18663871Syz147064 18673871Syz147064 return (DLADM_STATUS_OK); 18683871Syz147064 } 18693871Syz147064 18703871Syz147064 static int 18713871Syz147064 do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates) 18723871Syz147064 { 18733871Syz147064 int i; 18743871Syz147064 uint_t len; 18753871Syz147064 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 18763871Syz147064 18773871Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 18783871Syz147064 18793871Syz147064 for (i = 0; i < rates->wr_cnt; i++) 18803871Syz147064 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 18813871Syz147064 wrp->wl_rates_num = rates->wr_cnt; 18823871Syz147064 18833871Syz147064 len = offsetof(wl_rates_t, wl_rates_rates) + 18843871Syz147064 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 18853871Syz147064 return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len)); 18863871Syz147064 } 18873871Syz147064 18883871Syz147064 /* ARGSUSED */ 18893871Syz147064 static dladm_status_t 18903871Syz147064 do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 18913871Syz147064 { 18923871Syz147064 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 18933871Syz147064 18943871Syz147064 if (do_set_powermode(fd, gbuf, &powermode) < 0) 18953871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 18963871Syz147064 18973871Syz147064 return (DLADM_STATUS_OK); 18983871Syz147064 } 18993871Syz147064 19003871Syz147064 static int 19013871Syz147064 do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm) 19023871Syz147064 { 19033871Syz147064 wl_ps_mode_t ps_mode; 19043871Syz147064 19053871Syz147064 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 19063871Syz147064 19073871Syz147064 switch (*pm) { 19083871Syz147064 case DLADM_WLAN_PM_OFF: 19093871Syz147064 ps_mode.wl_ps_mode = WL_PM_AM; 19103871Syz147064 break; 19113871Syz147064 case DLADM_WLAN_PM_MAX: 19123871Syz147064 ps_mode.wl_ps_mode = WL_PM_MPS; 19133871Syz147064 break; 19143871Syz147064 case DLADM_WLAN_PM_FAST: 19153871Syz147064 ps_mode.wl_ps_mode = WL_PM_FAST; 19163871Syz147064 break; 19173871Syz147064 default: 19183871Syz147064 return (-1); 19193871Syz147064 } 19203871Syz147064 return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode, 19213871Syz147064 sizeof (ps_mode))); 19223871Syz147064 } 19233871Syz147064 19243871Syz147064 /* ARGSUSED */ 19253871Syz147064 static dladm_status_t 19263871Syz147064 do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 19273871Syz147064 { 19283871Syz147064 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 19293871Syz147064 19303871Syz147064 if (do_set_radio(fd, gbuf, &radio) < 0) 19313871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 19323871Syz147064 19333871Syz147064 return (DLADM_STATUS_OK); 19343871Syz147064 } 19353871Syz147064 19363871Syz147064 static int 19373871Syz147064 do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio) 19383871Syz147064 { 19393871Syz147064 wl_radio_t r; 19403871Syz147064 19413871Syz147064 switch (*radio) { 19423871Syz147064 case DLADM_WLAN_RADIO_ON: 19433871Syz147064 r = B_TRUE; 19443871Syz147064 break; 19453871Syz147064 case DLADM_WLAN_RADIO_OFF: 19463871Syz147064 r = B_FALSE; 19473871Syz147064 break; 19483871Syz147064 default: 19493871Syz147064 return (-1); 19503871Syz147064 } 19513871Syz147064 return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r))); 19523871Syz147064 } 19533871Syz147064 19543871Syz147064 static int 19553871Syz147064 do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel) 19563871Syz147064 { 19573871Syz147064 wl_phy_conf_t phy_conf; 19583871Syz147064 19593871Syz147064 if (*channel > MAX_CHANNEL_NUM) 19603871Syz147064 return (-1); 19613871Syz147064 19623871Syz147064 (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); 19633871Syz147064 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; 19643871Syz147064 19653871Syz147064 return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf, 19663871Syz147064 sizeof (phy_conf))); 19673871Syz147064 } 19683871Syz147064 19693871Syz147064 static int 19703871Syz147064 do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss) 19713871Syz147064 { 19723871Syz147064 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); 19733871Syz147064 19743871Syz147064 return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr))); 19753871Syz147064 } 19763871Syz147064 19773871Syz147064 static void 19783871Syz147064 generate_essid(dladm_wlan_essid_t *essid) 19793871Syz147064 { 19803871Syz147064 srandom(gethrtime()); 19813871Syz147064 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d", 19823871Syz147064 random()); 19833871Syz147064 } 1984*4126Szf162725 1985*4126Szf162725 static int 1986*4126Szf162725 do_get_capability(int fd, wldp_t *gbuf) 1987*4126Szf162725 { 1988*4126Szf162725 return (do_get_ioctl(fd, gbuf, WL_CAPABILITY)); 1989*4126Szf162725 } 1990*4126Szf162725 1991*4126Szf162725 static int 1992*4126Szf162725 do_get_wpamode(int fd, wldp_t *gbuf) 1993*4126Szf162725 { 1994*4126Szf162725 return (do_get_ioctl(fd, gbuf, WL_WPA)); 1995*4126Szf162725 } 1996*4126Szf162725 1997*4126Szf162725 static dladm_status_t 1998*4126Szf162725 ioctl_get(const char *link, int id, void *gbuf) 1999*4126Szf162725 { 2000*4126Szf162725 int fd; 2001*4126Szf162725 2002*4126Szf162725 if ((fd = open_link(link)) < 0) 2003*4126Szf162725 return (DLADM_STATUS_LINKINVAL); 2004*4126Szf162725 (void) do_get_ioctl(fd, gbuf, id); 2005*4126Szf162725 2006*4126Szf162725 (void) close(fd); 2007*4126Szf162725 return (dladm_wlan_wlresult2status(gbuf)); 2008*4126Szf162725 } 2009*4126Szf162725 2010*4126Szf162725 static dladm_status_t 2011*4126Szf162725 ioctl_set(const char *link, int id, void *buf, uint_t buflen) 2012*4126Szf162725 { 2013*4126Szf162725 int fd; 2014*4126Szf162725 wldp_t *gbuf; 2015*4126Szf162725 dladm_status_t status; 2016*4126Szf162725 2017*4126Szf162725 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2018*4126Szf162725 return (DLADM_STATUS_NOMEM); 2019*4126Szf162725 2020*4126Szf162725 if ((fd = open_link(link)) < 0) 2021*4126Szf162725 return (DLADM_STATUS_LINKINVAL); 2022*4126Szf162725 (void) do_set_ioctl(fd, gbuf, id, buf, buflen); 2023*4126Szf162725 2024*4126Szf162725 (void) close(fd); 2025*4126Szf162725 status = dladm_wlan_wlresult2status(gbuf); 2026*4126Szf162725 free(gbuf); 2027*4126Szf162725 2028*4126Szf162725 return (status); 2029*4126Szf162725 } 2030*4126Szf162725 2031*4126Szf162725 dladm_status_t 2032*4126Szf162725 dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, 2033*4126Szf162725 uint_t *estot) 2034*4126Szf162725 { 2035*4126Szf162725 int i, n; 2036*4126Szf162725 wldp_t *gbuf; 2037*4126Szf162725 wl_wpa_ess_t *es; 2038*4126Szf162725 dladm_status_t status; 2039*4126Szf162725 2040*4126Szf162725 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2041*4126Szf162725 return (DLADM_STATUS_NOMEM); 2042*4126Szf162725 2043*4126Szf162725 status = ioctl_get(link, WL_SCANRESULTS, gbuf); 2044*4126Szf162725 2045*4126Szf162725 if (status == DLADM_STATUS_OK) { 2046*4126Szf162725 es = (wl_wpa_ess_t *)(gbuf->wldp_buf); 2047*4126Szf162725 n = (es->count > escnt) ? escnt : es->count; 2048*4126Szf162725 for (i = 0; i < n; i ++) { 2049*4126Szf162725 (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid, 2050*4126Szf162725 DLADM_WLAN_BSSID_LEN); 2051*4126Szf162725 sr[i].we_ssid_len = es->ess[i].ssid_len; 2052*4126Szf162725 (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid, 2053*4126Szf162725 es->ess[i].ssid_len); 2054*4126Szf162725 sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len; 2055*4126Szf162725 (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie, 2056*4126Szf162725 es->ess[i].wpa_ie_len); 2057*4126Szf162725 sr[i].we_freq = es->ess[i].freq; 2058*4126Szf162725 } 2059*4126Szf162725 *estot = n; 2060*4126Szf162725 } 2061*4126Szf162725 2062*4126Szf162725 free(gbuf); 2063*4126Szf162725 return (status); 2064*4126Szf162725 } 2065*4126Szf162725 2066*4126Szf162725 dladm_status_t 2067*4126Szf162725 dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, 2068*4126Szf162725 uint_t wpa_ie_len) 2069*4126Szf162725 { 2070*4126Szf162725 wl_wpa_ie_t *ie; 2071*4126Szf162725 uint_t len; 2072*4126Szf162725 dladm_status_t status; 2073*4126Szf162725 2074*4126Szf162725 if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN) 2075*4126Szf162725 return (DLADM_STATUS_BADARG); 2076*4126Szf162725 len = sizeof (wl_wpa_ie_t) + wpa_ie_len; 2077*4126Szf162725 ie = malloc(len); 2078*4126Szf162725 if (ie == NULL) 2079*4126Szf162725 return (DLADM_STATUS_NOMEM); 2080*4126Szf162725 2081*4126Szf162725 (void) memset(ie, 0, len); 2082*4126Szf162725 ie->wpa_ie_len = wpa_ie_len; 2083*4126Szf162725 (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); 2084*4126Szf162725 2085*4126Szf162725 status = ioctl_set(link, WL_SETOPTIE, ie, len); 2086*4126Szf162725 free(ie); 2087*4126Szf162725 2088*4126Szf162725 return (status); 2089*4126Szf162725 } 2090*4126Szf162725 2091*4126Szf162725 dladm_status_t 2092*4126Szf162725 dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag) 2093*4126Szf162725 { 2094*4126Szf162725 wl_wpa_t wpa; 2095*4126Szf162725 2096*4126Szf162725 wpa.wpa_flag = flag; 2097*4126Szf162725 return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t))); 2098*4126Szf162725 } 2099*4126Szf162725 2100*4126Szf162725 dladm_status_t 2101*4126Szf162725 dladm_wlan_wpa_del_key(const char *link, uint_t key_idx, 2102*4126Szf162725 const dladm_wlan_bssid_t *addr) 2103*4126Szf162725 { 2104*4126Szf162725 wl_del_key_t wk; 2105*4126Szf162725 2106*4126Szf162725 wk.idk_keyix = key_idx; 2107*4126Szf162725 if (addr != NULL) 2108*4126Szf162725 (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, 2109*4126Szf162725 DLADM_WLAN_BSSID_LEN); 2110*4126Szf162725 2111*4126Szf162725 return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t))); 2112*4126Szf162725 } 2113*4126Szf162725 2114*4126Szf162725 dladm_status_t 2115*4126Szf162725 dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, 2116*4126Szf162725 const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, 2117*4126Szf162725 uint_t key_idx, uint8_t *key, uint_t key_len) 2118*4126Szf162725 { 2119*4126Szf162725 wl_key_t wk; 2120*4126Szf162725 2121*4126Szf162725 (void) memset(&wk, 0, sizeof (wl_key_t)); 2122*4126Szf162725 switch (cipher) { 2123*4126Szf162725 case DLADM_WLAN_CIPHER_WEP: 2124*4126Szf162725 wk.ik_type = IEEE80211_CIPHER_WEP; 2125*4126Szf162725 break; 2126*4126Szf162725 case DLADM_WLAN_CIPHER_TKIP: 2127*4126Szf162725 wk.ik_type = IEEE80211_CIPHER_TKIP; 2128*4126Szf162725 break; 2129*4126Szf162725 case DLADM_WLAN_CIPHER_AES_OCB: 2130*4126Szf162725 wk.ik_type = IEEE80211_CIPHER_AES_OCB; 2131*4126Szf162725 break; 2132*4126Szf162725 case DLADM_WLAN_CIPHER_AES_CCM: 2133*4126Szf162725 wk.ik_type = IEEE80211_CIPHER_AES_CCM; 2134*4126Szf162725 break; 2135*4126Szf162725 case DLADM_WLAN_CIPHER_CKIP: 2136*4126Szf162725 wk.ik_type = IEEE80211_CIPHER_CKIP; 2137*4126Szf162725 break; 2138*4126Szf162725 case DLADM_WLAN_CIPHER_NONE: 2139*4126Szf162725 wk.ik_type = IEEE80211_CIPHER_NONE; 2140*4126Szf162725 break; 2141*4126Szf162725 default: 2142*4126Szf162725 return (DLADM_STATUS_BADARG); 2143*4126Szf162725 } 2144*4126Szf162725 wk.ik_flags = IEEE80211_KEY_RECV; 2145*4126Szf162725 if (set_tx) { 2146*4126Szf162725 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; 2147*4126Szf162725 (void) memcpy(wk.ik_macaddr, addr->wb_bytes, 2148*4126Szf162725 DLADM_WLAN_BSSID_LEN); 2149*4126Szf162725 } else 2150*4126Szf162725 (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN); 2151*4126Szf162725 wk.ik_keyix = key_idx; 2152*4126Szf162725 wk.ik_keylen = key_len; 2153*4126Szf162725 (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ 2154*4126Szf162725 (void) memcpy(wk.ik_keydata, key, key_len); 2155*4126Szf162725 2156*4126Szf162725 return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t))); 2157*4126Szf162725 } 2158*4126Szf162725 2159*4126Szf162725 dladm_status_t 2160*4126Szf162725 dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, 2161*4126Szf162725 dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) 2162*4126Szf162725 { 2163*4126Szf162725 wl_mlme_t mlme; 2164*4126Szf162725 2165*4126Szf162725 (void) memset(&mlme, 0, sizeof (wl_mlme_t)); 2166*4126Szf162725 switch (op) { 2167*4126Szf162725 case DLADM_WLAN_MLME_ASSOC: 2168*4126Szf162725 mlme.im_op = IEEE80211_MLME_ASSOC; 2169*4126Szf162725 break; 2170*4126Szf162725 case DLADM_WLAN_MLME_DISASSOC: 2171*4126Szf162725 mlme.im_op = IEEE80211_MLME_DISASSOC; 2172*4126Szf162725 break; 2173*4126Szf162725 default: 2174*4126Szf162725 return (DLADM_STATUS_BADARG); 2175*4126Szf162725 } 2176*4126Szf162725 mlme.im_reason = reason; 2177*4126Szf162725 if (bssid != NULL) 2178*4126Szf162725 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, 2179*4126Szf162725 DLADM_WLAN_BSSID_LEN); 2180*4126Szf162725 2181*4126Szf162725 return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t))); 2182*4126Szf162725 } 2183*4126Szf162725 2184*4126Szf162725 /* 2185*4126Szf162725 * routines of create instance 2186*4126Szf162725 */ 2187*4126Szf162725 static scf_propertygroup_t * 2188*4126Szf162725 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, 2189*4126Szf162725 const char *pg_name, const char *pg_type) 2190*4126Szf162725 { 2191*4126Szf162725 scf_propertygroup_t *pg; 2192*4126Szf162725 2193*4126Szf162725 pg = scf_pg_create(handle); 2194*4126Szf162725 if (pg == NULL) 2195*4126Szf162725 return (NULL); 2196*4126Szf162725 2197*4126Szf162725 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) { 2198*4126Szf162725 scf_pg_destroy(pg); 2199*4126Szf162725 return (NULL); 2200*4126Szf162725 } 2201*4126Szf162725 2202*4126Szf162725 return (pg); 2203*4126Szf162725 } 2204*4126Szf162725 2205*4126Szf162725 static int 2206*4126Szf162725 add_new_property(scf_handle_t *handle, const char *prop_name, 2207*4126Szf162725 scf_type_t type, const char *val, scf_transaction_t *tx) 2208*4126Szf162725 { 2209*4126Szf162725 scf_value_t *value = NULL; 2210*4126Szf162725 scf_transaction_entry_t *entry = NULL; 2211*4126Szf162725 2212*4126Szf162725 entry = scf_entry_create(handle); 2213*4126Szf162725 if (entry == NULL) 2214*4126Szf162725 goto out; 2215*4126Szf162725 2216*4126Szf162725 value = scf_value_create(handle); 2217*4126Szf162725 if (value == NULL) 2218*4126Szf162725 goto out; 2219*4126Szf162725 2220*4126Szf162725 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) 2221*4126Szf162725 goto out; 2222*4126Szf162725 2223*4126Szf162725 if (scf_value_set_from_string(value, type, val) != 0) 2224*4126Szf162725 goto out; 2225*4126Szf162725 2226*4126Szf162725 if (scf_entry_add_value(entry, value) != 0) 2227*4126Szf162725 goto out; 2228*4126Szf162725 2229*4126Szf162725 return (DLADM_WLAN_SVC_SUCCESS); 2230*4126Szf162725 2231*4126Szf162725 out: 2232*4126Szf162725 if (value != NULL) 2233*4126Szf162725 scf_value_destroy(value); 2234*4126Szf162725 if (entry != NULL) 2235*4126Szf162725 scf_entry_destroy(entry); 2236*4126Szf162725 2237*4126Szf162725 return (DLADM_WLAN_SVC_FAILURE); 2238*4126Szf162725 } 2239*4126Szf162725 2240*4126Szf162725 /* 2241*4126Szf162725 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 2242*4126Szf162725 */ 2243*4126Szf162725 static int 2244*4126Szf162725 add_pg_method(scf_handle_t *handle, scf_instance_t *instance, 2245*4126Szf162725 const char *pg_name, const char *flags) 2246*4126Szf162725 { 2247*4126Szf162725 int rv, size; 2248*4126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2249*4126Szf162725 char *command = NULL; 2250*4126Szf162725 scf_transaction_t *tran = NULL; 2251*4126Szf162725 scf_propertygroup_t *pg; 2252*4126Szf162725 2253*4126Szf162725 pg = add_property_group_to_instance(handle, instance, 2254*4126Szf162725 pg_name, SCF_GROUP_METHOD); 2255*4126Szf162725 if (pg == NULL) 2256*4126Szf162725 goto out; 2257*4126Szf162725 2258*4126Szf162725 tran = scf_transaction_create(handle); 2259*4126Szf162725 if (tran == NULL) 2260*4126Szf162725 goto out; 2261*4126Szf162725 2262*4126Szf162725 size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; 2263*4126Szf162725 command = malloc(size); 2264*4126Szf162725 if (command == NULL) { 2265*4126Szf162725 status = DLADM_WLAN_SVC_APP_FAILURE; 2266*4126Szf162725 goto out; 2267*4126Szf162725 } 2268*4126Szf162725 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); 2269*4126Szf162725 2270*4126Szf162725 do { 2271*4126Szf162725 if (scf_transaction_start(tran, pg) != 0) 2272*4126Szf162725 goto out; 2273*4126Szf162725 2274*4126Szf162725 if (add_new_property(handle, SCF_PROPERTY_EXEC, 2275*4126Szf162725 SCF_TYPE_ASTRING, command, tran) != 2276*4126Szf162725 DLADM_WLAN_SVC_SUCCESS) { 2277*4126Szf162725 goto out; 2278*4126Szf162725 } 2279*4126Szf162725 2280*4126Szf162725 rv = scf_transaction_commit(tran); 2281*4126Szf162725 switch (rv) { 2282*4126Szf162725 case 1: 2283*4126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2284*4126Szf162725 goto out; 2285*4126Szf162725 case 0: 2286*4126Szf162725 scf_transaction_destroy_children(tran); 2287*4126Szf162725 if (scf_pg_update(pg) == -1) { 2288*4126Szf162725 goto out; 2289*4126Szf162725 } 2290*4126Szf162725 break; 2291*4126Szf162725 case -1: 2292*4126Szf162725 default: 2293*4126Szf162725 goto out; 2294*4126Szf162725 } 2295*4126Szf162725 } while (rv == 0); 2296*4126Szf162725 2297*4126Szf162725 out: 2298*4126Szf162725 if (tran != NULL) { 2299*4126Szf162725 scf_transaction_destroy_children(tran); 2300*4126Szf162725 scf_transaction_destroy(tran); 2301*4126Szf162725 } 2302*4126Szf162725 2303*4126Szf162725 if (pg != NULL) 2304*4126Szf162725 scf_pg_destroy(pg); 2305*4126Szf162725 2306*4126Szf162725 if (command != NULL) 2307*4126Szf162725 free(command); 2308*4126Szf162725 2309*4126Szf162725 return (status); 2310*4126Szf162725 } 2311*4126Szf162725 2312*4126Szf162725 static int 2313*4126Szf162725 do_create_instance(scf_handle_t *handle, scf_service_t *svc, 2314*4126Szf162725 const char *instance_name, const char *command) 2315*4126Szf162725 { 2316*4126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2317*4126Szf162725 char *buf; 2318*4126Szf162725 ssize_t max_fmri_len; 2319*4126Szf162725 scf_instance_t *instance; 2320*4126Szf162725 2321*4126Szf162725 instance = scf_instance_create(handle); 2322*4126Szf162725 if (instance == NULL) 2323*4126Szf162725 goto out; 2324*4126Szf162725 2325*4126Szf162725 if (scf_service_add_instance(svc, instance_name, instance) != 0) { 2326*4126Szf162725 if (scf_error() == SCF_ERROR_EXISTS) 2327*4126Szf162725 /* Let the caller deal with the duplicate instance */ 2328*4126Szf162725 status = DLADM_WLAN_SVC_INSTANCE_EXISTS; 2329*4126Szf162725 goto out; 2330*4126Szf162725 } 2331*4126Szf162725 2332*4126Szf162725 if (add_pg_method(handle, instance, "start", 2333*4126Szf162725 command) != DLADM_WLAN_SVC_SUCCESS) { 2334*4126Szf162725 goto out; 2335*4126Szf162725 } 2336*4126Szf162725 2337*4126Szf162725 /* enabling the instance */ 2338*4126Szf162725 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 2339*4126Szf162725 if ((buf = malloc(max_fmri_len + 1)) == NULL) 2340*4126Szf162725 goto out; 2341*4126Szf162725 2342*4126Szf162725 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 2343*4126Szf162725 if ((smf_disable_instance(buf, 0) != 0) || 2344*4126Szf162725 (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { 2345*4126Szf162725 goto out; 2346*4126Szf162725 } 2347*4126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2348*4126Szf162725 } 2349*4126Szf162725 2350*4126Szf162725 out: 2351*4126Szf162725 if (instance != NULL) 2352*4126Szf162725 scf_instance_destroy(instance); 2353*4126Szf162725 return (status); 2354*4126Szf162725 } 2355*4126Szf162725 2356*4126Szf162725 static int 2357*4126Szf162725 create_instance(const char *instance_name, const char *command) 2358*4126Szf162725 { 2359*4126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2360*4126Szf162725 scf_service_t *svc = NULL; 2361*4126Szf162725 scf_handle_t *handle = NULL; 2362*4126Szf162725 2363*4126Szf162725 handle = scf_handle_create(SCF_VERSION); 2364*4126Szf162725 if (handle == NULL) 2365*4126Szf162725 goto out; 2366*4126Szf162725 2367*4126Szf162725 if (scf_handle_bind(handle) == -1) 2368*4126Szf162725 goto out; 2369*4126Szf162725 2370*4126Szf162725 if ((svc = scf_service_create(handle)) == NULL) 2371*4126Szf162725 goto out; 2372*4126Szf162725 2373*4126Szf162725 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc, 2374*4126Szf162725 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 2375*4126Szf162725 goto out; 2376*4126Szf162725 2377*4126Szf162725 status = do_create_instance(handle, svc, instance_name, command); 2378*4126Szf162725 2379*4126Szf162725 out: 2380*4126Szf162725 if (svc != NULL) 2381*4126Szf162725 scf_service_destroy(svc); 2382*4126Szf162725 2383*4126Szf162725 if (handle != NULL) { 2384*4126Szf162725 (void) scf_handle_unbind(handle); 2385*4126Szf162725 scf_handle_destroy(handle); 2386*4126Szf162725 } 2387*4126Szf162725 2388*4126Szf162725 return (status); 2389*4126Szf162725 } 2390*4126Szf162725 2391*4126Szf162725 /* 2392*4126Szf162725 * routines of delete instance 2393*4126Szf162725 */ 2394*4126Szf162725 #define DEFAULT_TIMEOUT 60000000 2395*4126Szf162725 #define INIT_WAIT_USECS 50000 2396*4126Szf162725 2397*4126Szf162725 static void 2398*4126Szf162725 wait_until_disabled(scf_handle_t *handle, char *fmri) 2399*4126Szf162725 { 2400*4126Szf162725 char *state; 2401*4126Szf162725 useconds_t max; 2402*4126Szf162725 useconds_t usecs; 2403*4126Szf162725 uint64_t *cp = NULL; 2404*4126Szf162725 scf_simple_prop_t *sp = NULL; 2405*4126Szf162725 2406*4126Szf162725 max = DEFAULT_TIMEOUT; 2407*4126Szf162725 2408*4126Szf162725 if (((sp = scf_simple_prop_get(handle, fmri, "stop", 2409*4126Szf162725 SCF_PROPERTY_TIMEOUT)) != NULL) && 2410*4126Szf162725 ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0)) 2411*4126Szf162725 max = (*cp) * 1000000; /* convert to usecs */ 2412*4126Szf162725 2413*4126Szf162725 if (sp != NULL) 2414*4126Szf162725 scf_simple_prop_free(sp); 2415*4126Szf162725 2416*4126Szf162725 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) { 2417*4126Szf162725 /* incremental wait */ 2418*4126Szf162725 usecs *= 2; 2419*4126Szf162725 usecs = (usecs > max) ? max : usecs; 2420*4126Szf162725 2421*4126Szf162725 (void) usleep(usecs); 2422*4126Szf162725 2423*4126Szf162725 /* Check state after the wait */ 2424*4126Szf162725 if ((state = smf_get_state(fmri)) != NULL) { 2425*4126Szf162725 if (strcmp(state, "disabled") == 0) 2426*4126Szf162725 return; 2427*4126Szf162725 } 2428*4126Szf162725 } 2429*4126Szf162725 } 2430*4126Szf162725 2431*4126Szf162725 static int 2432*4126Szf162725 delete_instance(const char *instance_name) 2433*4126Szf162725 { 2434*4126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2435*4126Szf162725 char *buf; 2436*4126Szf162725 ssize_t max_fmri_len; 2437*4126Szf162725 scf_scope_t *scope = NULL; 2438*4126Szf162725 scf_service_t *svc = NULL; 2439*4126Szf162725 scf_handle_t *handle = NULL; 2440*4126Szf162725 scf_instance_t *instance; 2441*4126Szf162725 2442*4126Szf162725 handle = scf_handle_create(SCF_VERSION); 2443*4126Szf162725 if (handle == NULL) 2444*4126Szf162725 goto out; 2445*4126Szf162725 2446*4126Szf162725 if (scf_handle_bind(handle) == -1) 2447*4126Szf162725 goto out; 2448*4126Szf162725 2449*4126Szf162725 if ((scope = scf_scope_create(handle)) == NULL) 2450*4126Szf162725 goto out; 2451*4126Szf162725 2452*4126Szf162725 if ((svc = scf_service_create(handle)) == NULL) 2453*4126Szf162725 goto out; 2454*4126Szf162725 2455*4126Szf162725 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1) 2456*4126Szf162725 goto out; 2457*4126Szf162725 2458*4126Szf162725 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0) 2459*4126Szf162725 goto out; 2460*4126Szf162725 2461*4126Szf162725 instance = scf_instance_create(handle); 2462*4126Szf162725 if (instance == NULL) 2463*4126Szf162725 goto out; 2464*4126Szf162725 2465*4126Szf162725 if (scf_service_get_instance(svc, instance_name, instance) != 0) { 2466*4126Szf162725 scf_error_t scf_errnum = scf_error(); 2467*4126Szf162725 2468*4126Szf162725 if (scf_errnum == SCF_ERROR_NOT_FOUND) 2469*4126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2470*4126Szf162725 2471*4126Szf162725 scf_instance_destroy(instance); 2472*4126Szf162725 goto out; 2473*4126Szf162725 } 2474*4126Szf162725 2475*4126Szf162725 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 2476*4126Szf162725 if ((buf = malloc(max_fmri_len + 1)) == NULL) { 2477*4126Szf162725 scf_instance_destroy(instance); 2478*4126Szf162725 goto out; 2479*4126Szf162725 } 2480*4126Szf162725 2481*4126Szf162725 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 2482*4126Szf162725 char *state; 2483*4126Szf162725 2484*4126Szf162725 state = smf_get_state(buf); 2485*4126Szf162725 if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 || 2486*4126Szf162725 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) { 2487*4126Szf162725 if (smf_disable_instance(buf, 0) == 0) { 2488*4126Szf162725 /* 2489*4126Szf162725 * Wait for some time till timeout to avoid 2490*4126Szf162725 * a race with scf_instance_delete() below. 2491*4126Szf162725 */ 2492*4126Szf162725 wait_until_disabled(handle, buf); 2493*4126Szf162725 } 2494*4126Szf162725 } 2495*4126Szf162725 } 2496*4126Szf162725 2497*4126Szf162725 if (scf_instance_delete(instance) != 0) { 2498*4126Szf162725 scf_instance_destroy(instance); 2499*4126Szf162725 goto out; 2500*4126Szf162725 } 2501*4126Szf162725 2502*4126Szf162725 scf_instance_destroy(instance); 2503*4126Szf162725 2504*4126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2505*4126Szf162725 2506*4126Szf162725 out: 2507*4126Szf162725 if (svc != NULL) 2508*4126Szf162725 scf_service_destroy(svc); 2509*4126Szf162725 2510*4126Szf162725 if (scope != NULL) 2511*4126Szf162725 scf_scope_destroy(scope); 2512*4126Szf162725 2513*4126Szf162725 if (handle != NULL) { 2514*4126Szf162725 (void) scf_handle_unbind(handle); 2515*4126Szf162725 scf_handle_destroy(handle); 2516*4126Szf162725 } 2517*4126Szf162725 2518*4126Szf162725 return (status); 2519*4126Szf162725 } 2520*4126Szf162725 2521*4126Szf162725 /* 2522*4126Szf162725 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 2523*4126Szf162725 */ 2524*4126Szf162725 static int 2525*4126Szf162725 wpa_instance_create(const char *instance_name, void *key) 2526*4126Szf162725 { 2527*4126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2528*4126Szf162725 char *command = NULL; 2529*4126Szf162725 char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; 2530*4126Szf162725 int size; 2531*4126Szf162725 2532*4126Szf162725 size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; 2533*4126Szf162725 command = malloc(size); 2534*4126Szf162725 if (command == NULL) { 2535*4126Szf162725 status = DLADM_WLAN_SVC_APP_FAILURE; 2536*4126Szf162725 goto out; 2537*4126Szf162725 } 2538*4126Szf162725 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); 2539*4126Szf162725 2540*4126Szf162725 status = create_instance(instance_name, command); 2541*4126Szf162725 if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) { 2542*4126Szf162725 /* 2543*4126Szf162725 * Delete the existing instance and create a new instance 2544*4126Szf162725 * with the supplied arguments. 2545*4126Szf162725 */ 2546*4126Szf162725 if ((status = delete_instance(instance_name)) == 2547*4126Szf162725 DLADM_WLAN_SVC_SUCCESS) { 2548*4126Szf162725 status = create_instance(instance_name, command); 2549*4126Szf162725 } 2550*4126Szf162725 } 2551*4126Szf162725 2552*4126Szf162725 out: 2553*4126Szf162725 if (command != NULL) 2554*4126Szf162725 free(command); 2555*4126Szf162725 2556*4126Szf162725 return (status); 2557*4126Szf162725 } 2558*4126Szf162725 2559*4126Szf162725 static int 2560*4126Szf162725 wpa_instance_delete(const char *instance_name) 2561*4126Szf162725 { 2562*4126Szf162725 int status; 2563*4126Szf162725 2564*4126Szf162725 status = delete_instance(instance_name); 2565*4126Szf162725 2566*4126Szf162725 return (status); 2567*4126Szf162725 } 2568