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> 404126Szf162725 #include <libscf.h> 413871Syz147064 #include <libdlwlan.h> 423871Syz147064 #include <libdlwlan_impl.h> 434126Szf162725 #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 674126Szf162725 static int wpa_instance_create(const char *, void *); 684126Szf162725 static int wpa_instance_delete(const char *); 694126Szf162725 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 *); 834126Szf162725 static int do_get_capability(int, wldp_t *); 844126Szf162725 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 *); 914126Szf162725 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 *); 994126Szf162725 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 }, 1194126Szf162725 { "wep", DLADM_WLAN_SECMODE_WEP }, 1204126Szf162725 { "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); 3034126Szf162725 if (wlp->wl_ess_conf_reserved[0] > 0) 3044126Szf162725 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 3654126Szf162725 if (func == NULL) { 3664126Szf162725 status = DLADM_STATUS_OK; 3674126Szf162725 goto done; 3684126Szf162725 } 3694126Szf162725 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)) 3904126Szf162725 (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 5074126Szf162725 #define IEEE80211_C_WPA 0x01800000 5084126Szf162725 5093871Syz147064 static dladm_status_t 5104126Szf162725 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; 5174126Szf162725 boolean_t essid_valid = B_FALSE; 5183871Syz147064 dladm_wlan_channel_t channel; 5194126Szf162725 hrtime_t start; 5204126Szf162725 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); 5494126Szf162725 if (do_set_key(fd, gbuf, keys, key_count) < 0) 5503871Syz147064 goto fail; 5514126Szf162725 } else if (secmode == DLADM_WLAN_SECMODE_WPA) { 5524126Szf162725 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 5534126Szf162725 return (DLADM_STATUS_BADARG); 5544126Szf162725 if (do_get_capability(fd, gbuf) < 0) 5554126Szf162725 goto fail; 5564126Szf162725 caps = (wl_capability_t *)(gbuf->wldp_buf); 5574126Szf162725 if ((caps->caps & IEEE80211_C_WPA) == 0) 5584126Szf162725 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 5844126Szf162725 /* 5854126Szf162725 * Because wpa daemon needs getting essid from driver, 5864126Szf162725 * we need call do_set_essid() first, then call wpa_instance_create(). 5874126Szf162725 */ 5884126Szf162725 if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) 5894126Szf162725 (void) wpa_instance_create(link, keys); 5904126Szf162725 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)) { 6494126Szf162725 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 } 6674126Szf162725 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 6894126Szf162725 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; 6974126Szf162725 status = do_connect(link, fd, gbuf, ap, create_ibss, 6984126Szf162725 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)) 7054126Szf162725 (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 7434126Szf162725 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; 8694126Szf162725 } else { 8704126Szf162725 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 8904126Szf162725 if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) { 8914126Szf162725 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 8924126Szf162725 status = DLADM_STATUS_OK; 8934126Szf162725 goto done; 8944126Szf162725 } 8954126Szf162725 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; 9094126Szf162725 case WL_ENC_WPA: 9104126Szf162725 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 9114126Szf162725 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 14884126Szf162725 do_disconnect(const char *link, int fd, wldp_t *gbuf) 14893871Syz147064 { 14904126Szf162725 if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf-> 14914126Szf162725 wldp_buf))->wpa_flag > 0) 14924126Szf162725 (void) wpa_instance_delete(link); 14934126Szf162725 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; 17424126Szf162725 case DLADM_WLAN_SECMODE_WPA: 17434126Szf162725 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 17524126Szf162725 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; 17584126Szf162725 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); 1817*5102Syz147064 if (buf == NULL) { 1818*5102Syz147064 status = DLADM_STATUS_NOMEM; 18193871Syz147064 goto done; 1820*5102Syz147064 } 18213871Syz147064 18223871Syz147064 modval = (char **)(void *)buf; 18233871Syz147064 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 18243871Syz147064 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 18253871Syz147064 i * DLADM_STRSIZE; 18263871Syz147064 } 18273871Syz147064 18283871Syz147064 status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt); 18293871Syz147064 if (status != DLADM_STATUS_OK) 18303871Syz147064 goto done; 18313871Syz147064 18323871Syz147064 vdp = malloc(sizeof (val_desc_t)); 18333871Syz147064 if (vdp == NULL) { 18343871Syz147064 status = DLADM_STATUS_NOMEM; 18353871Syz147064 goto done; 18363871Syz147064 } 18373871Syz147064 18383871Syz147064 for (i = 0; i < modval_cnt; i++) { 18393871Syz147064 if (strcasecmp(*prop_val, modval[i]) == 0) { 18403871Syz147064 vdp->vd_val = (uint_t)(atof(*prop_val) * 2); 18413871Syz147064 status = DLADM_STATUS_OK; 18423871Syz147064 *vdpp = vdp; 18433871Syz147064 vdp = NULL; 18443871Syz147064 break; 18453871Syz147064 } 18463871Syz147064 } 18473871Syz147064 if (i == modval_cnt) 18483871Syz147064 status = DLADM_STATUS_BADVAL; 18493871Syz147064 done: 18503871Syz147064 free(buf); 18513871Syz147064 free(vdp); 18523871Syz147064 return (status); 18533871Syz147064 } 18543871Syz147064 18553871Syz147064 static dladm_status_t 18563871Syz147064 do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 18573871Syz147064 { 18583871Syz147064 dladm_wlan_rates_t rates; 18593871Syz147064 18603871Syz147064 if (val_cnt != 1) 18613871Syz147064 return (DLADM_STATUS_BADVALCNT); 18623871Syz147064 18633871Syz147064 rates.wr_cnt = 1; 18643871Syz147064 rates.wr_rates[0] = vdp[0].vd_val; 18653871Syz147064 18663871Syz147064 if (do_set_rate(fd, gbuf, &rates) < 0) 18673871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 18683871Syz147064 18693871Syz147064 return (DLADM_STATUS_OK); 18703871Syz147064 } 18713871Syz147064 18723871Syz147064 static int 18733871Syz147064 do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates) 18743871Syz147064 { 18753871Syz147064 int i; 18763871Syz147064 uint_t len; 18773871Syz147064 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 18783871Syz147064 18793871Syz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 18803871Syz147064 18813871Syz147064 for (i = 0; i < rates->wr_cnt; i++) 18823871Syz147064 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 18833871Syz147064 wrp->wl_rates_num = rates->wr_cnt; 18843871Syz147064 18853871Syz147064 len = offsetof(wl_rates_t, wl_rates_rates) + 18863871Syz147064 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 18873871Syz147064 return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len)); 18883871Syz147064 } 18893871Syz147064 18903871Syz147064 /* ARGSUSED */ 18913871Syz147064 static dladm_status_t 18923871Syz147064 do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 18933871Syz147064 { 18943871Syz147064 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 18953871Syz147064 18963871Syz147064 if (do_set_powermode(fd, gbuf, &powermode) < 0) 18973871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 18983871Syz147064 18993871Syz147064 return (DLADM_STATUS_OK); 19003871Syz147064 } 19013871Syz147064 19023871Syz147064 static int 19033871Syz147064 do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm) 19043871Syz147064 { 19053871Syz147064 wl_ps_mode_t ps_mode; 19063871Syz147064 19073871Syz147064 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 19083871Syz147064 19093871Syz147064 switch (*pm) { 19103871Syz147064 case DLADM_WLAN_PM_OFF: 19113871Syz147064 ps_mode.wl_ps_mode = WL_PM_AM; 19123871Syz147064 break; 19133871Syz147064 case DLADM_WLAN_PM_MAX: 19143871Syz147064 ps_mode.wl_ps_mode = WL_PM_MPS; 19153871Syz147064 break; 19163871Syz147064 case DLADM_WLAN_PM_FAST: 19173871Syz147064 ps_mode.wl_ps_mode = WL_PM_FAST; 19183871Syz147064 break; 19193871Syz147064 default: 19203871Syz147064 return (-1); 19213871Syz147064 } 19223871Syz147064 return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode, 19233871Syz147064 sizeof (ps_mode))); 19243871Syz147064 } 19253871Syz147064 19263871Syz147064 /* ARGSUSED */ 19273871Syz147064 static dladm_status_t 19283871Syz147064 do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 19293871Syz147064 { 19303871Syz147064 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 19313871Syz147064 19323871Syz147064 if (do_set_radio(fd, gbuf, &radio) < 0) 19333871Syz147064 return (dladm_wlan_wlresult2status(gbuf)); 19343871Syz147064 19353871Syz147064 return (DLADM_STATUS_OK); 19363871Syz147064 } 19373871Syz147064 19383871Syz147064 static int 19393871Syz147064 do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio) 19403871Syz147064 { 19413871Syz147064 wl_radio_t r; 19423871Syz147064 19433871Syz147064 switch (*radio) { 19443871Syz147064 case DLADM_WLAN_RADIO_ON: 19453871Syz147064 r = B_TRUE; 19463871Syz147064 break; 19473871Syz147064 case DLADM_WLAN_RADIO_OFF: 19483871Syz147064 r = B_FALSE; 19493871Syz147064 break; 19503871Syz147064 default: 19513871Syz147064 return (-1); 19523871Syz147064 } 19533871Syz147064 return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r))); 19543871Syz147064 } 19553871Syz147064 19563871Syz147064 static int 19573871Syz147064 do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel) 19583871Syz147064 { 19593871Syz147064 wl_phy_conf_t phy_conf; 19603871Syz147064 19613871Syz147064 if (*channel > MAX_CHANNEL_NUM) 19623871Syz147064 return (-1); 19633871Syz147064 19643871Syz147064 (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); 19653871Syz147064 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; 19663871Syz147064 19673871Syz147064 return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf, 19683871Syz147064 sizeof (phy_conf))); 19693871Syz147064 } 19703871Syz147064 19713871Syz147064 static int 19723871Syz147064 do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss) 19733871Syz147064 { 19743871Syz147064 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); 19753871Syz147064 19763871Syz147064 return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr))); 19773871Syz147064 } 19783871Syz147064 19793871Syz147064 static void 19803871Syz147064 generate_essid(dladm_wlan_essid_t *essid) 19813871Syz147064 { 19823871Syz147064 srandom(gethrtime()); 19833871Syz147064 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d", 19843871Syz147064 random()); 19853871Syz147064 } 19864126Szf162725 19874126Szf162725 static int 19884126Szf162725 do_get_capability(int fd, wldp_t *gbuf) 19894126Szf162725 { 19904126Szf162725 return (do_get_ioctl(fd, gbuf, WL_CAPABILITY)); 19914126Szf162725 } 19924126Szf162725 19934126Szf162725 static int 19944126Szf162725 do_get_wpamode(int fd, wldp_t *gbuf) 19954126Szf162725 { 19964126Szf162725 return (do_get_ioctl(fd, gbuf, WL_WPA)); 19974126Szf162725 } 19984126Szf162725 19994126Szf162725 static dladm_status_t 20004126Szf162725 ioctl_get(const char *link, int id, void *gbuf) 20014126Szf162725 { 20024126Szf162725 int fd; 20034126Szf162725 20044126Szf162725 if ((fd = open_link(link)) < 0) 20054126Szf162725 return (DLADM_STATUS_LINKINVAL); 20064126Szf162725 (void) do_get_ioctl(fd, gbuf, id); 20074126Szf162725 20084126Szf162725 (void) close(fd); 20094126Szf162725 return (dladm_wlan_wlresult2status(gbuf)); 20104126Szf162725 } 20114126Szf162725 20124126Szf162725 static dladm_status_t 20134126Szf162725 ioctl_set(const char *link, int id, void *buf, uint_t buflen) 20144126Szf162725 { 20154126Szf162725 int fd; 20164126Szf162725 wldp_t *gbuf; 20174126Szf162725 dladm_status_t status; 20184126Szf162725 20194126Szf162725 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 20204126Szf162725 return (DLADM_STATUS_NOMEM); 20214126Szf162725 20224126Szf162725 if ((fd = open_link(link)) < 0) 20234126Szf162725 return (DLADM_STATUS_LINKINVAL); 20244126Szf162725 (void) do_set_ioctl(fd, gbuf, id, buf, buflen); 20254126Szf162725 20264126Szf162725 (void) close(fd); 20274126Szf162725 status = dladm_wlan_wlresult2status(gbuf); 20284126Szf162725 free(gbuf); 20294126Szf162725 20304126Szf162725 return (status); 20314126Szf162725 } 20324126Szf162725 20334126Szf162725 dladm_status_t 20344126Szf162725 dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, 20354126Szf162725 uint_t *estot) 20364126Szf162725 { 20374126Szf162725 int i, n; 20384126Szf162725 wldp_t *gbuf; 20394126Szf162725 wl_wpa_ess_t *es; 20404126Szf162725 dladm_status_t status; 20414126Szf162725 20424126Szf162725 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 20434126Szf162725 return (DLADM_STATUS_NOMEM); 20444126Szf162725 20454126Szf162725 status = ioctl_get(link, WL_SCANRESULTS, gbuf); 20464126Szf162725 20474126Szf162725 if (status == DLADM_STATUS_OK) { 20484126Szf162725 es = (wl_wpa_ess_t *)(gbuf->wldp_buf); 20494126Szf162725 n = (es->count > escnt) ? escnt : es->count; 20504126Szf162725 for (i = 0; i < n; i ++) { 20514126Szf162725 (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid, 20524126Szf162725 DLADM_WLAN_BSSID_LEN); 20534126Szf162725 sr[i].we_ssid_len = es->ess[i].ssid_len; 20544126Szf162725 (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid, 20554126Szf162725 es->ess[i].ssid_len); 20564126Szf162725 sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len; 20574126Szf162725 (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie, 20584126Szf162725 es->ess[i].wpa_ie_len); 20594126Szf162725 sr[i].we_freq = es->ess[i].freq; 20604126Szf162725 } 20614126Szf162725 *estot = n; 20624126Szf162725 } 20634126Szf162725 20644126Szf162725 free(gbuf); 20654126Szf162725 return (status); 20664126Szf162725 } 20674126Szf162725 20684126Szf162725 dladm_status_t 20694126Szf162725 dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, 20704126Szf162725 uint_t wpa_ie_len) 20714126Szf162725 { 20724126Szf162725 wl_wpa_ie_t *ie; 20734126Szf162725 uint_t len; 20744126Szf162725 dladm_status_t status; 20754126Szf162725 20764126Szf162725 if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN) 20774126Szf162725 return (DLADM_STATUS_BADARG); 20784126Szf162725 len = sizeof (wl_wpa_ie_t) + wpa_ie_len; 20794126Szf162725 ie = malloc(len); 20804126Szf162725 if (ie == NULL) 20814126Szf162725 return (DLADM_STATUS_NOMEM); 20824126Szf162725 20834126Szf162725 (void) memset(ie, 0, len); 20844126Szf162725 ie->wpa_ie_len = wpa_ie_len; 20854126Szf162725 (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); 20864126Szf162725 20874126Szf162725 status = ioctl_set(link, WL_SETOPTIE, ie, len); 20884126Szf162725 free(ie); 20894126Szf162725 20904126Szf162725 return (status); 20914126Szf162725 } 20924126Szf162725 20934126Szf162725 dladm_status_t 20944126Szf162725 dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag) 20954126Szf162725 { 20964126Szf162725 wl_wpa_t wpa; 20974126Szf162725 20984126Szf162725 wpa.wpa_flag = flag; 20994126Szf162725 return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t))); 21004126Szf162725 } 21014126Szf162725 21024126Szf162725 dladm_status_t 21034126Szf162725 dladm_wlan_wpa_del_key(const char *link, uint_t key_idx, 21044126Szf162725 const dladm_wlan_bssid_t *addr) 21054126Szf162725 { 21064126Szf162725 wl_del_key_t wk; 21074126Szf162725 21084126Szf162725 wk.idk_keyix = key_idx; 21094126Szf162725 if (addr != NULL) 21104126Szf162725 (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, 21114126Szf162725 DLADM_WLAN_BSSID_LEN); 21124126Szf162725 21134126Szf162725 return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t))); 21144126Szf162725 } 21154126Szf162725 21164126Szf162725 dladm_status_t 21174126Szf162725 dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, 21184126Szf162725 const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, 21194126Szf162725 uint_t key_idx, uint8_t *key, uint_t key_len) 21204126Szf162725 { 21214126Szf162725 wl_key_t wk; 21224126Szf162725 21234126Szf162725 (void) memset(&wk, 0, sizeof (wl_key_t)); 21244126Szf162725 switch (cipher) { 21254126Szf162725 case DLADM_WLAN_CIPHER_WEP: 21264126Szf162725 wk.ik_type = IEEE80211_CIPHER_WEP; 21274126Szf162725 break; 21284126Szf162725 case DLADM_WLAN_CIPHER_TKIP: 21294126Szf162725 wk.ik_type = IEEE80211_CIPHER_TKIP; 21304126Szf162725 break; 21314126Szf162725 case DLADM_WLAN_CIPHER_AES_OCB: 21324126Szf162725 wk.ik_type = IEEE80211_CIPHER_AES_OCB; 21334126Szf162725 break; 21344126Szf162725 case DLADM_WLAN_CIPHER_AES_CCM: 21354126Szf162725 wk.ik_type = IEEE80211_CIPHER_AES_CCM; 21364126Szf162725 break; 21374126Szf162725 case DLADM_WLAN_CIPHER_CKIP: 21384126Szf162725 wk.ik_type = IEEE80211_CIPHER_CKIP; 21394126Szf162725 break; 21404126Szf162725 case DLADM_WLAN_CIPHER_NONE: 21414126Szf162725 wk.ik_type = IEEE80211_CIPHER_NONE; 21424126Szf162725 break; 21434126Szf162725 default: 21444126Szf162725 return (DLADM_STATUS_BADARG); 21454126Szf162725 } 21464126Szf162725 wk.ik_flags = IEEE80211_KEY_RECV; 21474126Szf162725 if (set_tx) { 21484126Szf162725 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; 21494126Szf162725 (void) memcpy(wk.ik_macaddr, addr->wb_bytes, 21504126Szf162725 DLADM_WLAN_BSSID_LEN); 21514126Szf162725 } else 21524126Szf162725 (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN); 21534126Szf162725 wk.ik_keyix = key_idx; 21544126Szf162725 wk.ik_keylen = key_len; 21554126Szf162725 (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ 21564126Szf162725 (void) memcpy(wk.ik_keydata, key, key_len); 21574126Szf162725 21584126Szf162725 return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t))); 21594126Szf162725 } 21604126Szf162725 21614126Szf162725 dladm_status_t 21624126Szf162725 dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, 21634126Szf162725 dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) 21644126Szf162725 { 21654126Szf162725 wl_mlme_t mlme; 21664126Szf162725 21674126Szf162725 (void) memset(&mlme, 0, sizeof (wl_mlme_t)); 21684126Szf162725 switch (op) { 21694126Szf162725 case DLADM_WLAN_MLME_ASSOC: 21704126Szf162725 mlme.im_op = IEEE80211_MLME_ASSOC; 21714126Szf162725 break; 21724126Szf162725 case DLADM_WLAN_MLME_DISASSOC: 21734126Szf162725 mlme.im_op = IEEE80211_MLME_DISASSOC; 21744126Szf162725 break; 21754126Szf162725 default: 21764126Szf162725 return (DLADM_STATUS_BADARG); 21774126Szf162725 } 21784126Szf162725 mlme.im_reason = reason; 21794126Szf162725 if (bssid != NULL) 21804126Szf162725 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, 21814126Szf162725 DLADM_WLAN_BSSID_LEN); 21824126Szf162725 21834126Szf162725 return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t))); 21844126Szf162725 } 21854126Szf162725 21864126Szf162725 /* 21874126Szf162725 * routines of create instance 21884126Szf162725 */ 21894126Szf162725 static scf_propertygroup_t * 21904126Szf162725 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, 21914126Szf162725 const char *pg_name, const char *pg_type) 21924126Szf162725 { 21934126Szf162725 scf_propertygroup_t *pg; 21944126Szf162725 21954126Szf162725 pg = scf_pg_create(handle); 21964126Szf162725 if (pg == NULL) 21974126Szf162725 return (NULL); 21984126Szf162725 21994126Szf162725 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) { 22004126Szf162725 scf_pg_destroy(pg); 22014126Szf162725 return (NULL); 22024126Szf162725 } 22034126Szf162725 22044126Szf162725 return (pg); 22054126Szf162725 } 22064126Szf162725 22074126Szf162725 static int 22084126Szf162725 add_new_property(scf_handle_t *handle, const char *prop_name, 22094126Szf162725 scf_type_t type, const char *val, scf_transaction_t *tx) 22104126Szf162725 { 22114126Szf162725 scf_value_t *value = NULL; 22124126Szf162725 scf_transaction_entry_t *entry = NULL; 22134126Szf162725 22144126Szf162725 entry = scf_entry_create(handle); 22154126Szf162725 if (entry == NULL) 22164126Szf162725 goto out; 22174126Szf162725 22184126Szf162725 value = scf_value_create(handle); 22194126Szf162725 if (value == NULL) 22204126Szf162725 goto out; 22214126Szf162725 22224126Szf162725 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) 22234126Szf162725 goto out; 22244126Szf162725 22254126Szf162725 if (scf_value_set_from_string(value, type, val) != 0) 22264126Szf162725 goto out; 22274126Szf162725 22284126Szf162725 if (scf_entry_add_value(entry, value) != 0) 22294126Szf162725 goto out; 22304126Szf162725 22314126Szf162725 return (DLADM_WLAN_SVC_SUCCESS); 22324126Szf162725 22334126Szf162725 out: 22344126Szf162725 if (value != NULL) 22354126Szf162725 scf_value_destroy(value); 22364126Szf162725 if (entry != NULL) 22374126Szf162725 scf_entry_destroy(entry); 22384126Szf162725 22394126Szf162725 return (DLADM_WLAN_SVC_FAILURE); 22404126Szf162725 } 22414126Szf162725 22424126Szf162725 /* 22434126Szf162725 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 22444126Szf162725 */ 22454126Szf162725 static int 22464126Szf162725 add_pg_method(scf_handle_t *handle, scf_instance_t *instance, 22474126Szf162725 const char *pg_name, const char *flags) 22484126Szf162725 { 22494126Szf162725 int rv, size; 22504126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 22514126Szf162725 char *command = NULL; 22524126Szf162725 scf_transaction_t *tran = NULL; 22534126Szf162725 scf_propertygroup_t *pg; 22544126Szf162725 22554126Szf162725 pg = add_property_group_to_instance(handle, instance, 22564126Szf162725 pg_name, SCF_GROUP_METHOD); 22574126Szf162725 if (pg == NULL) 22584126Szf162725 goto out; 22594126Szf162725 22604126Szf162725 tran = scf_transaction_create(handle); 22614126Szf162725 if (tran == NULL) 22624126Szf162725 goto out; 22634126Szf162725 22644126Szf162725 size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; 22654126Szf162725 command = malloc(size); 22664126Szf162725 if (command == NULL) { 22674126Szf162725 status = DLADM_WLAN_SVC_APP_FAILURE; 22684126Szf162725 goto out; 22694126Szf162725 } 22704126Szf162725 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); 22714126Szf162725 22724126Szf162725 do { 22734126Szf162725 if (scf_transaction_start(tran, pg) != 0) 22744126Szf162725 goto out; 22754126Szf162725 22764126Szf162725 if (add_new_property(handle, SCF_PROPERTY_EXEC, 22774126Szf162725 SCF_TYPE_ASTRING, command, tran) != 22784126Szf162725 DLADM_WLAN_SVC_SUCCESS) { 22794126Szf162725 goto out; 22804126Szf162725 } 22814126Szf162725 22824126Szf162725 rv = scf_transaction_commit(tran); 22834126Szf162725 switch (rv) { 22844126Szf162725 case 1: 22854126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 22864126Szf162725 goto out; 22874126Szf162725 case 0: 22884126Szf162725 scf_transaction_destroy_children(tran); 22894126Szf162725 if (scf_pg_update(pg) == -1) { 22904126Szf162725 goto out; 22914126Szf162725 } 22924126Szf162725 break; 22934126Szf162725 case -1: 22944126Szf162725 default: 22954126Szf162725 goto out; 22964126Szf162725 } 22974126Szf162725 } while (rv == 0); 22984126Szf162725 22994126Szf162725 out: 23004126Szf162725 if (tran != NULL) { 23014126Szf162725 scf_transaction_destroy_children(tran); 23024126Szf162725 scf_transaction_destroy(tran); 23034126Szf162725 } 23044126Szf162725 23054126Szf162725 if (pg != NULL) 23064126Szf162725 scf_pg_destroy(pg); 23074126Szf162725 23084126Szf162725 if (command != NULL) 23094126Szf162725 free(command); 23104126Szf162725 23114126Szf162725 return (status); 23124126Szf162725 } 23134126Szf162725 23144126Szf162725 static int 23154126Szf162725 do_create_instance(scf_handle_t *handle, scf_service_t *svc, 23164126Szf162725 const char *instance_name, const char *command) 23174126Szf162725 { 23184126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 23194126Szf162725 char *buf; 23204126Szf162725 ssize_t max_fmri_len; 23214126Szf162725 scf_instance_t *instance; 23224126Szf162725 23234126Szf162725 instance = scf_instance_create(handle); 23244126Szf162725 if (instance == NULL) 23254126Szf162725 goto out; 23264126Szf162725 23274126Szf162725 if (scf_service_add_instance(svc, instance_name, instance) != 0) { 23284126Szf162725 if (scf_error() == SCF_ERROR_EXISTS) 23294126Szf162725 /* Let the caller deal with the duplicate instance */ 23304126Szf162725 status = DLADM_WLAN_SVC_INSTANCE_EXISTS; 23314126Szf162725 goto out; 23324126Szf162725 } 23334126Szf162725 23344126Szf162725 if (add_pg_method(handle, instance, "start", 23354126Szf162725 command) != DLADM_WLAN_SVC_SUCCESS) { 23364126Szf162725 goto out; 23374126Szf162725 } 23384126Szf162725 23394126Szf162725 /* enabling the instance */ 23404126Szf162725 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 23414126Szf162725 if ((buf = malloc(max_fmri_len + 1)) == NULL) 23424126Szf162725 goto out; 23434126Szf162725 23444126Szf162725 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 23454126Szf162725 if ((smf_disable_instance(buf, 0) != 0) || 23464126Szf162725 (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { 23474126Szf162725 goto out; 23484126Szf162725 } 23494126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 23504126Szf162725 } 23514126Szf162725 23524126Szf162725 out: 23534126Szf162725 if (instance != NULL) 23544126Szf162725 scf_instance_destroy(instance); 23554126Szf162725 return (status); 23564126Szf162725 } 23574126Szf162725 23584126Szf162725 static int 23594126Szf162725 create_instance(const char *instance_name, const char *command) 23604126Szf162725 { 23614126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 23624126Szf162725 scf_service_t *svc = NULL; 23634126Szf162725 scf_handle_t *handle = NULL; 23644126Szf162725 23654126Szf162725 handle = scf_handle_create(SCF_VERSION); 23664126Szf162725 if (handle == NULL) 23674126Szf162725 goto out; 23684126Szf162725 23694126Szf162725 if (scf_handle_bind(handle) == -1) 23704126Szf162725 goto out; 23714126Szf162725 23724126Szf162725 if ((svc = scf_service_create(handle)) == NULL) 23734126Szf162725 goto out; 23744126Szf162725 23754126Szf162725 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc, 23764126Szf162725 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 23774126Szf162725 goto out; 23784126Szf162725 23794126Szf162725 status = do_create_instance(handle, svc, instance_name, command); 23804126Szf162725 23814126Szf162725 out: 23824126Szf162725 if (svc != NULL) 23834126Szf162725 scf_service_destroy(svc); 23844126Szf162725 23854126Szf162725 if (handle != NULL) { 23864126Szf162725 (void) scf_handle_unbind(handle); 23874126Szf162725 scf_handle_destroy(handle); 23884126Szf162725 } 23894126Szf162725 23904126Szf162725 return (status); 23914126Szf162725 } 23924126Szf162725 23934126Szf162725 /* 23944126Szf162725 * routines of delete instance 23954126Szf162725 */ 23964126Szf162725 #define DEFAULT_TIMEOUT 60000000 23974126Szf162725 #define INIT_WAIT_USECS 50000 23984126Szf162725 23994126Szf162725 static void 24004126Szf162725 wait_until_disabled(scf_handle_t *handle, char *fmri) 24014126Szf162725 { 24024126Szf162725 char *state; 24034126Szf162725 useconds_t max; 24044126Szf162725 useconds_t usecs; 24054126Szf162725 uint64_t *cp = NULL; 24064126Szf162725 scf_simple_prop_t *sp = NULL; 24074126Szf162725 24084126Szf162725 max = DEFAULT_TIMEOUT; 24094126Szf162725 24104126Szf162725 if (((sp = scf_simple_prop_get(handle, fmri, "stop", 24114126Szf162725 SCF_PROPERTY_TIMEOUT)) != NULL) && 24124126Szf162725 ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0)) 24134126Szf162725 max = (*cp) * 1000000; /* convert to usecs */ 24144126Szf162725 24154126Szf162725 if (sp != NULL) 24164126Szf162725 scf_simple_prop_free(sp); 24174126Szf162725 24184126Szf162725 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) { 24194126Szf162725 /* incremental wait */ 24204126Szf162725 usecs *= 2; 24214126Szf162725 usecs = (usecs > max) ? max : usecs; 24224126Szf162725 24234126Szf162725 (void) usleep(usecs); 24244126Szf162725 24254126Szf162725 /* Check state after the wait */ 24264126Szf162725 if ((state = smf_get_state(fmri)) != NULL) { 24274126Szf162725 if (strcmp(state, "disabled") == 0) 24284126Szf162725 return; 24294126Szf162725 } 24304126Szf162725 } 24314126Szf162725 } 24324126Szf162725 24334126Szf162725 static int 24344126Szf162725 delete_instance(const char *instance_name) 24354126Szf162725 { 24364126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 24374126Szf162725 char *buf; 24384126Szf162725 ssize_t max_fmri_len; 24394126Szf162725 scf_scope_t *scope = NULL; 24404126Szf162725 scf_service_t *svc = NULL; 24414126Szf162725 scf_handle_t *handle = NULL; 24424126Szf162725 scf_instance_t *instance; 24434126Szf162725 24444126Szf162725 handle = scf_handle_create(SCF_VERSION); 24454126Szf162725 if (handle == NULL) 24464126Szf162725 goto out; 24474126Szf162725 24484126Szf162725 if (scf_handle_bind(handle) == -1) 24494126Szf162725 goto out; 24504126Szf162725 24514126Szf162725 if ((scope = scf_scope_create(handle)) == NULL) 24524126Szf162725 goto out; 24534126Szf162725 24544126Szf162725 if ((svc = scf_service_create(handle)) == NULL) 24554126Szf162725 goto out; 24564126Szf162725 24574126Szf162725 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1) 24584126Szf162725 goto out; 24594126Szf162725 24604126Szf162725 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0) 24614126Szf162725 goto out; 24624126Szf162725 24634126Szf162725 instance = scf_instance_create(handle); 24644126Szf162725 if (instance == NULL) 24654126Szf162725 goto out; 24664126Szf162725 24674126Szf162725 if (scf_service_get_instance(svc, instance_name, instance) != 0) { 24684126Szf162725 scf_error_t scf_errnum = scf_error(); 24694126Szf162725 24704126Szf162725 if (scf_errnum == SCF_ERROR_NOT_FOUND) 24714126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 24724126Szf162725 24734126Szf162725 scf_instance_destroy(instance); 24744126Szf162725 goto out; 24754126Szf162725 } 24764126Szf162725 24774126Szf162725 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 24784126Szf162725 if ((buf = malloc(max_fmri_len + 1)) == NULL) { 24794126Szf162725 scf_instance_destroy(instance); 24804126Szf162725 goto out; 24814126Szf162725 } 24824126Szf162725 24834126Szf162725 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 24844126Szf162725 char *state; 24854126Szf162725 24864126Szf162725 state = smf_get_state(buf); 24874126Szf162725 if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 || 24884126Szf162725 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) { 24894126Szf162725 if (smf_disable_instance(buf, 0) == 0) { 24904126Szf162725 /* 24914126Szf162725 * Wait for some time till timeout to avoid 24924126Szf162725 * a race with scf_instance_delete() below. 24934126Szf162725 */ 24944126Szf162725 wait_until_disabled(handle, buf); 24954126Szf162725 } 24964126Szf162725 } 24974126Szf162725 } 24984126Szf162725 24994126Szf162725 if (scf_instance_delete(instance) != 0) { 25004126Szf162725 scf_instance_destroy(instance); 25014126Szf162725 goto out; 25024126Szf162725 } 25034126Szf162725 25044126Szf162725 scf_instance_destroy(instance); 25054126Szf162725 25064126Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 25074126Szf162725 25084126Szf162725 out: 25094126Szf162725 if (svc != NULL) 25104126Szf162725 scf_service_destroy(svc); 25114126Szf162725 25124126Szf162725 if (scope != NULL) 25134126Szf162725 scf_scope_destroy(scope); 25144126Szf162725 25154126Szf162725 if (handle != NULL) { 25164126Szf162725 (void) scf_handle_unbind(handle); 25174126Szf162725 scf_handle_destroy(handle); 25184126Szf162725 } 25194126Szf162725 25204126Szf162725 return (status); 25214126Szf162725 } 25224126Szf162725 25234126Szf162725 /* 25244126Szf162725 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 25254126Szf162725 */ 25264126Szf162725 static int 25274126Szf162725 wpa_instance_create(const char *instance_name, void *key) 25284126Szf162725 { 25294126Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 25304126Szf162725 char *command = NULL; 25314126Szf162725 char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; 25324126Szf162725 int size; 25334126Szf162725 25344126Szf162725 size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; 25354126Szf162725 command = malloc(size); 25364126Szf162725 if (command == NULL) { 25374126Szf162725 status = DLADM_WLAN_SVC_APP_FAILURE; 25384126Szf162725 goto out; 25394126Szf162725 } 25404126Szf162725 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); 25414126Szf162725 25424126Szf162725 status = create_instance(instance_name, command); 25434126Szf162725 if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) { 25444126Szf162725 /* 25454126Szf162725 * Delete the existing instance and create a new instance 25464126Szf162725 * with the supplied arguments. 25474126Szf162725 */ 25484126Szf162725 if ((status = delete_instance(instance_name)) == 25494126Szf162725 DLADM_WLAN_SVC_SUCCESS) { 25504126Szf162725 status = create_instance(instance_name, command); 25514126Szf162725 } 25524126Szf162725 } 25534126Szf162725 25544126Szf162725 out: 25554126Szf162725 if (command != NULL) 25564126Szf162725 free(command); 25574126Szf162725 25584126Szf162725 return (status); 25594126Szf162725 } 25604126Szf162725 25614126Szf162725 static int 25624126Szf162725 wpa_instance_delete(const char *instance_name) 25634126Szf162725 { 25644126Szf162725 int status; 25654126Szf162725 25664126Szf162725 status = delete_instance(instance_name); 25674126Szf162725 25684126Szf162725 return (status); 25694126Szf162725 } 2570